E紳士標籤構建者

從Wiki獲取EhTagTranslater資料庫,將E紳士TAG翻譯為中文

目前為 2019-07-15 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name EhTagBuilder
  3. // @name:zh-CN E绅士标签构建者
  4. // @name:zh-TW E紳士標籤構建者
  5. // @name:zh-HK E紳士標籤構建者
  6. // @namespace http://www.mapaler.com/
  7. // @homepage https://github.com/Mapaler/EhTagTranslator
  8. // @supportURL https://github.com/Mapaler/EhTagTranslator/issues
  9. // @description Build EhTagTranslater from Wiki.
  10. // @description:zh-CN 从Wiki获取EhTagTranslater数据库,将E绅士TAG翻译为中文
  11. // @description:zh-TW 從Wiki獲取EhTagTranslater資料庫,將E紳士TAG翻譯為中文
  12. // @description:zh-HK 從Wiki獲取EhTagTranslater資料庫,將E紳士TAG翻譯為中文
  13. // @include *://github.com/Mapaler/EhTagTranslator*
  14. // @include *://github.com/EhTagTranslation/Database*
  15. // @icon http://exhentai.org/favicon.ico
  16. // @version 2.9.0
  17. // @grant none
  18. // @author Mapaler <mapaler@163.com>
  19. // @copyright 2017+, Mapaler <mapaler@163.com>
  20. //-@grant GM_xmlhttpRequest
  21. //-@grant GM_getValue
  22. //-@grant GM_setValue
  23. //-@grant GM_deleteValue
  24. //-@grant GM_listValues
  25. // ==/UserScript==
  26.  
  27. (function() {
  28. var newRe = location.pathname.indexOf("EhTagTranslation/Database")>=0; //是否已经迁移
  29. var wiki_URL= newRe ? //GitHub wiki 的地址
  30. "https://github.com/EhTagTranslation/Database/tree/master/" : //新的组织项目地址
  31. "https://github.com/Mapaler/EhTagTranslator/wiki"; //传统Wiki地址
  32. var wiki_version_filename = "version"; //版本的地址
  33. var rows_filename = newRe?"database/rows.md":"rows"; //行名的地址
  34. var buttonInserPlace = document.querySelector(".pagehead-actions"); //按钮插入位置
  35. var windowInserPlace = document.querySelector(".reponav"); //窗口插入位置
  36. var scriptVersion = "unknown"; //本程序的版本
  37. var scriptName = "EhTagBuilder"; //本程序的名称
  38. if (typeof(GM_info)!="undefined")
  39. {
  40. scriptVersion = GM_info.script.version.replace(/(^\s*)|(\s*$)/g, "");
  41. if (GM_info.script.name_i18n)
  42. {
  43. var i18n = (navigator.language||navigator.userLanguage).replace("-","_"); //获取浏览器语言
  44. scriptName = GM_info.script.name_i18n[i18n]; //支持Tampermonkey
  45. }
  46. else
  47. {
  48. scriptName = GM_info.script.localizedName || //支持Greasemonkey 油猴子 3.x
  49. GM_info.script.name; //支持Violentmonkey 暴力猴
  50. }
  51. }
  52. var optionVersion = 1; //当前设置版本,用于提醒是否需要重置设置
  53. var database_structure_version = newRe?5:4; //当前数据库结构版本,用于提醒是否需要更新脚本
  54. var downOverCheckHook; //检测下载是否完成的循环函数
  55. var rowsCount = 0; //行名总数
  56. var rowsCurrent = 0; //当前下载行名
  57. //匹配Emoji正则表达式,Made by @xioxin
  58. var emojireg = /\u{2139}|[\u{2194}-\u{2199}]|[\u{21A9}-\u{21AA}]|[\u{231A}-\u{231B}]|\u{2328}|\u{23CF}|[\u{23E9}-\u{23F3}]|[\u{23F8}-\u{23FA}]|\u{24C2}|[\u{25AA}-\u{25AB}]|\u{25B6}|\u{25C0}|[\u{25FB}-\u{25FE}]|[\u{2600}-\u{2604}]|\u{260E}|\u{2611}|[\u{2614}-\u{2615}]|\u{2618}|\u{261D}|\u{2620}|[\u{2622}-\u{2623}]|\u{2626}|\u{262A}|[\u{262E}-\u{262F}]|[\u{2638}-\u{263A}]|[\u{2648}-\u{2653}]|\u{2660}|\u{2663}|\u{2666}|\u{2668}|\u{267B}|\u{267F}|[\u{2692}-\u{2697}]|\u{2699}|[\u{269B}-\u{269C}]|[\u{26A0}-\u{26A1}]|[\u{26AA}-\u{26AB}]|[\u{26B0}-\u{26B1}]|[\u{26BD}-\u{26BE}]|[\u{26C4}-\u{26C5}]|\u{26C8}|\u{26CE}|\u{26CF}|\u{26D1}|[\u{26D3}-\u{26D4}]|[\u{26E9}-\u{26EA}]|[\u{26F0}-\u{26F5}]|[\u{26F7}-\u{26FA}]|\u{26FD}|\u{2702}|\u{2705}|[\u{2708}-\u{2709}]|[\u{270A}-\u{270B}]|[\u{270C}-\u{270D}]|\u{270F}|\u{2712}|\u{2714}|\u{2716}|\u{271D}|\u{2721}|\u{2728}|[\u{2733}-\u{2734}]|\u{2744}|\u{2747}|\u{274C}|\u{274E}|[\u{2753}-\u{2755}]|\u{2757}|\u{2763}|[\u{2795}-\u{2797}]|\u{27A1}|\u{27B0}|\u{27BF}|[\u{2934}-\u{2935}]|[\u{2B05}-\u{2B07}]|[\u{2B1B}-\u{2B1C}]|\u{2B50}|\u{2B55}|\u{3030}|\u{303D}|\u{3297}|\u{3299}|\u{1F004}|\u{1F0CF}|[\u{1F170}-\u{1F171}]|\u{1F17E}|\u{1F17F}|\u{1F18E}|[\u{1F191}-\u{1F19A}]|[\u{1F1E6}-\u{1F1FF}]|[\u{1F201}-\u{1F202}]|\u{1F21A}|\u{1F22F}|[\u{1F232}-\u{1F23A}]|[\u{1F250}-\u{1F251}]|[\u{1F300}-\u{1F320}]|\u{1F321}|[\u{1F324}-\u{1F32C}]|[\u{1F32D}-\u{1F32F}]|[\u{1F330}-\u{1F335}]|\u{1F336}|[\u{1F337}-\u{1F37C}]|\u{1F37D}|[\u{1F37E}-\u{1F37F}]|[\u{1F380}-\u{1F393}]|[\u{1F396}-\u{1F397}]|[\u{1F399}-\u{1F39B}]|[\u{1F39E}-\u{1F39F}]|[\u{1F3A0}-\u{1F3C4}]|\u{1F3C5}|[\u{1F3C6}-\u{1F3CA}]|[\u{1F3CB}-\u{1F3CE}]|[\u{1F3CF}-\u{1F3D3}]|[\u{1F3D4}-\u{1F3DF}]|[\u{1F3E0}-\u{1F3F0}]|[\u{1F3F3}-\u{1F3F5}]|\u{1F3F7}|[\u{1F3F8}-\u{1F3FF}]|[\u{1F400}-\u{1F43E}]|\u{1F43F}|\u{1F440}|\u{1F441}|[\u{1F442}-\u{1F4F7}]|\u{1F4F8}|[\u{1F4F9}-\u{1F4FC}]|\u{1F4FD}|\u{1F4FF}|[\u{1F500}-\u{1F53D}]|[\u{1F549}-\u{1F54A}]|[\u{1F54B}-\u{1F54E}]|[\u{1F550}-\u{1F567}]|[\u{1F56F}-\u{1F570}]|[\u{1F573}-\u{1F579}]|\u{1F57A}|\u{1F587}|[\u{1F58A}-\u{1F58D}]|\u{1F590}|[\u{1F595}-\u{1F596}]|\u{1F5A4}|\u{1F5A5}|\u{1F5A8}|[\u{1F5B1}-\u{1F5B2}]|\u{1F5BC}|[\u{1F5C2}-\u{1F5C4}]|[\u{1F5D1}-\u{1F5D3}]|[\u{1F5DC}-\u{1F5DE}]|\u{1F5E1}|\u{1F5E3}|\u{1F5E8}|\u{1F5EF}|\u{1F5F3}|\u{1F5FA}|[\u{1F5FB}-\u{1F5FF}]|\u{1F600}|[\u{1F601}-\u{1F610}]|\u{1F611}|[\u{1F612}-\u{1F614}]|\u{1F615}|\u{1F616}|\u{1F617}|\u{1F618}|\u{1F619}|\u{1F61A}|\u{1F61B}|[\u{1F61C}-\u{1F61E}]|\u{1F61F}|[\u{1F620}-\u{1F625}]|[\u{1F626}-\u{1F627}]|[\u{1F628}-\u{1F62B}]|\u{1F62C}|\u{1F62D}|[\u{1F62E}-\u{1F62F}]|[\u{1F630}-\u{1F633}]|\u{1F634}|[\u{1F635}-\u{1F640}]|[\u{1F641}-\u{1F642}]|[\u{1F643}-\u{1F644}]|[\u{1F645}-\u{1F64F}]|[\u{1F680}-\u{1F6C5}]|[\u{1F6CB}-\u{1F6CF}]|\u{1F6D0}|[\u{1F6D1}-\u{1F6D2}]|[\u{1F6E0}-\u{1F6E5}]|\u{1F6E9}|[\u{1F6EB}-\u{1F6EC}]|\u{1F6F0}|\u{1F6F3}|[\u{1F6F4}-\u{1F6F6}]|[\u{1F6F7}-\u{1F6F8}]|[\u{1F910}-\u{1F918}]|[\u{1F919}-\u{1F91E}]|\u{1F91F}|[\u{1F920}-\u{1F927}]|[\u{1F928}-\u{1F92F}]|\u{1F930}|[\u{1F931}-\u{1F932}]|[\u{1F933}-\u{1F93A}]|[\u{1F93C}-\u{1F93E}]|[\u{1F940}-\u{1F945}]|[\u{1F947}-\u{1F94B}]|\u{1F94C}|[\u{1F950}-\u{1F95E}]|[\u{1F95F}-\u{1F96B}]|[\u{1F980}-\u{1F984}]|[\u{1F985}-\u{1F991}]|[\u{1F992}-\u{1F997}]|\u{1F9C0}|[\u{1F9D0}-\u{1F9E6}]/gu;
  59.  
  60. //仿GM_xmlhttpRequest函数v1.3
  61. if (typeof(GM_xmlhttpRequest) == "undefined") {
  62. var GM_xmlhttpRequest = function(GM_param) {
  63.  
  64. var xhr = new XMLHttpRequest(); //创建XMLHttpRequest对象
  65. xhr.open(GM_param.method, GM_param.url, true);
  66. if (GM_param.responseType) xhr.responseType = GM_param.responseType;
  67. if (GM_param.overrideMimeType) xhr.overrideMimeType(GM_param.overrideMimeType);
  68. xhr.onreadystatechange = function() //设置回调函数
  69. {
  70. if (xhr.readyState === xhr.DONE) {
  71. if (xhr.status === 200 && GM_param.onload)
  72. GM_param.onload(xhr);
  73. if (xhr.status !== 200 && GM_param.onerror)
  74. GM_param.onerror(xhr);
  75. }
  76. }
  77.  
  78. for (var header in GM_param.headers) {
  79. xhr.setRequestHeader(header, GM_param.headers[header]);
  80. }
  81.  
  82. xhr.send(GM_param.data ? GM_param.data : null);
  83. }
  84. }
  85. //仿GM_getValue函数v1.0
  86. if(typeof(GM_getValue) == "undefined")
  87. {
  88. var GM_getValue = function(name, type){
  89. var value = localStorage.getItem(name);
  90. if (value == undefined) return value;
  91. if ((/^(?:true|false)$/i.test(value) && type == undefined) || type == "boolean")
  92. {
  93. if (/^true$/i.test(value))
  94. return true;
  95. else if (/^false$/i.test(value))
  96. return false;
  97. else
  98. return Boolean(value);
  99. }
  100. else if((/^\-?[\d\.]+$/i.test(value) && type == undefined) || type == "number")
  101. return Number(value);
  102. else
  103. return value;
  104. }
  105. }
  106. //仿GM_setValue函数v1.0
  107. if(typeof(GM_setValue) == "undefined")
  108. {
  109. var GM_setValue = function(name, value){
  110. localStorage.setItem(name, value);
  111. }
  112. }
  113. //仿GM_deleteValue函数v1.0
  114. if(typeof(GM_deleteValue) == "undefined")
  115. {
  116. var GM_deleteValue = function(name){
  117. localStorage.removeItem(name);
  118. }
  119. }
  120. //仿GM_listValues函数v1.0
  121. if(typeof(GM_listValues) == "undefined")
  122. {
  123. var GM_listValues = function(){
  124. var keys = [];
  125. for (var ki=0, kilen=localStorage.length; ki<kilen; ki++)
  126. {
  127. keys.push(localStorage.key(ki));
  128. }
  129. return keys;
  130. }
  131. }
  132.  
  133. var ds = [];
  134. var rowObj = function(){
  135. this.name = "";
  136. this.cname = [];
  137. this.info = [];
  138. this.tags = [];
  139. this.links = [];
  140. }
  141. rowObj.prototype.addTagFromName = function(rowObj)
  142. {
  143. if (rowObj == undefined) rowObj = this;
  144. GM_xmlhttpRequest({
  145. method: "GET",
  146. //url: wiki_URL + (rowObj.name.length?"/"+rowObj.name:""),
  147. url: rowObj.links[0]?rowObj.links[0].href:(wiki_URL + (rowObj.name.length?"/"+rowObj.name:"")),
  148. onload: function(response) {
  149. var page_get_w = document.querySelector("#ETB_page-get");
  150. if (page_get_w)
  151. {
  152. var statetxt = page_get_w.querySelector(".page-get-" + rowObj.name);
  153. statetxt.classList.add("page-load");
  154. statetxt.innerHTML = "获取成功";
  155. }
  156. console.debug("正在处理 %s %s 页面",rowObj.name,
  157. rowObj.cname
  158. .filter(function(item){return item.type==0;})
  159. .map(function(item){return item.text;})
  160. .join("")
  161. );
  162. dealTags(response.responseText,rowObj);
  163. }
  164. });
  165. }
  166. var tagObj = function(){
  167. this.type = 0;
  168. this.name = "";
  169. this.cname = [];
  170. this.info = [];
  171. this.links = [];
  172. }
  173. //一条新的外部链接
  174. var linkObj = function(text,href,title){
  175. this.text = text||"";
  176. this.href = href||"";
  177. this.title = title||"";
  178. }
  179.  
  180.  
  181. //处理版本的页面
  182. function dealVersion(response)
  183. {
  184. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  185. var wiki_version_Dom;
  186. if (newRe)
  187. { //新仓库的结构版本
  188. wiki_version_Dom = PageDOM.querySelector("#LC1");
  189. }else
  190. { //wiki的结构版本
  191. wiki_version_Dom = PageDOM.querySelector("a[title='database-structure-version']");
  192. }
  193.  
  194. if (!wiki_version_Dom)
  195. {
  196. alert("未找到数据库结构版本,你的 " + scriptName + " 版本可能已经不适用新的数据库,请更新你的脚本。");
  197. return;
  198. }
  199. var wiki_version = Number(wiki_version_Dom.textContent.replace(/\D/ig,""));
  200.  
  201. var page_get_w = document.querySelector("#ETB_page-get");
  202. if (page_get_w)
  203. {
  204. var statetxt = page_get_w.querySelector(".page-get-wiki-version");
  205. statetxt.classList.add("page-load");
  206. statetxt.innerHTML = (newRe?"ETT组织仓库":"传统Wiki仓库")+"最新版本" + wiki_version + ",当前" + database_structure_version;
  207. }
  208. if (wiki_version > database_structure_version)
  209. {
  210. alert("Wiki数据库结构已更新,你的 " + scriptName + " 版本可能已经不适用新的数据库,请更新你的脚本。");
  211. return;
  212. }
  213. }
  214. //处理行的页面
  215. function dealRows(response, dataset)
  216. {
  217. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  218. var page_get_w = document.querySelector("#ETB_page-get");
  219. if (page_get_w)
  220. {
  221. var statetxt = page_get_w.querySelector(".page-get-rows");
  222. statetxt.classList.add("page-load");
  223. statetxt.innerHTML = "获取成功";
  224. }
  225. var table = PageDOM.querySelector((newRe?"#readme":"#wiki-body")+" .markdown-body table").tBodies[0];
  226. rowsCount = table.rows.length;
  227. for(var ri=0, rilen=table.rows.length; ri<rilen; ri++)
  228. {
  229. var trow = table.rows[ri];
  230. var row = new rowObj;
  231. row.name = trow.cells[0].textContent.replace(/(^\s|\s$)/ig,""); //去除首尾空格;
  232. row.cname = InfoToArray(trow.cells[1]);
  233. row.info = InfoToArray(trow.cells[2]);
  234. row.links = LinksToArray(trow.cells[3]);
  235. row.addTagFromName();
  236. dataset.push(row);
  237. if (page_get_w)
  238. {
  239. page_get_w.querySelector(".select-menu-list").appendChild(
  240. buildMenuItem((function()
  241. {
  242. var div = document.createElement("div");
  243. var span1 = document.createElement("span");
  244. span1.className = "page-title";
  245. span1.innerHTML = row.cname
  246. .filter(function(item){return item.type==0;})
  247. .map(function(item){return item.text;})
  248. .join("");
  249. div.appendChild(span1);
  250. var span2 = document.createElement("span");
  251. span2.className = "page-get-" + row.name;
  252. span2.innerHTML = "等待";
  253. div.appendChild(span2);
  254. return div;
  255. })()
  256. )
  257. );
  258. }
  259. }
  260. }
  261.  
  262. //生成按钮
  263. function specialCharToCss(str)
  264. {
  265. var strn = str;
  266. strn = strn.replace("\\","\\\\");
  267. strn = strn.replace("\"","\\\"");
  268. strn = strn.replace("\r","");
  269. strn = strn.replace("\n","\\A");
  270. return strn;
  271. }
  272.  
  273. //将外部链接变换为数组
  274. function LinksToArray(linksDom)
  275. {
  276. var arr = [];
  277. var as = linksDom.querySelectorAll("a");
  278. for (var ai=0;ai<as.length;ai++)
  279. {
  280. var a = as[ai];
  281. arr.push(new linkObj(a.textContent,a.href,a.title));
  282. }
  283. return arr;
  284. }
  285. //介绍信息转为数组
  286. function InfoToArray(infoDom)
  287. {
  288. var arr = [];
  289. if (infoDom.childNodes != undefined)
  290. {
  291. for (var ci=0, cilen=infoDom.childNodes.length; ci<cilen; ci++)
  292. {
  293. var node = infoDom.childNodes[ci];
  294. //type,0是文字,1是换行,2是图片,3是链接
  295. var InfoObj = {type:0};
  296. switch (node.nodeName) {
  297. case "#text":case "G-EMOJI":
  298. InfoObj.type = 0;
  299. if (node.textContent == "\n")
  300. continue;
  301. InfoObj.text = node.textContent;
  302. break;
  303. case "BR":
  304. InfoObj.type = 1;
  305. break;
  306. case "IMG":
  307. InfoObj.type = 2;
  308. var osrc = node.getAttribute("data-canonical-src");
  309. if (osrc) //链接写在data-canonical-src
  310. {
  311. InfoObj.src = osrc;
  312. }else if(node.title.length > 0) //链接写在title
  313. {
  314. InfoObj.src = node.title;
  315. }else if(node.src.length > 0) //链接写在src
  316. {
  317. InfoObj.src = node.src;
  318. }else
  319. {
  320. console.error("发现未知的其他图片地址格式",node,"来自",infoDom);
  321. }
  322. InfoObj.alt = node.alt;
  323. break;
  324. case "A":
  325. InfoObj.type = 3;
  326. InfoObj.text = node.textContent;
  327. InfoObj.href = node.href;
  328. InfoObj.title = node.title;
  329. break;
  330. default: //未知的其他格式
  331. console.error("发现未知的其他Node格式:" + node.nodeName,node,"来自",infoDom);
  332. continue;
  333. }
  334. arr.push(InfoObj);
  335. }
  336. }
  337. return arr;
  338. }
  339. //介绍信息数组输出到CSS
  340. function InfoArrayToCssString(infoArr, creatImage)
  341. {
  342. if (creatImage == undefined) creatImage = true;
  343. var infoArrTmp = infoArr.concat(); //创建编辑用临时数组
  344. var str = []; //最终输出的内容字符串的部件数组
  345. var lastText = false; //上一条是不是文字,用渝判断下一条是储存到临时数组等候拼接还是将前方的加入最终字符串
  346. var strPart = []; //当前的临时字符串(储存多块相邻文本,用于拼接)
  347. while (infoArrTmp.length>0)
  348. {
  349. var inf = infoArrTmp.shift();
  350. if (inf.type == 0 || inf.type == 1 || inf.type == 3) //type,0是文字,1是换行,2是图片,3是链接
  351. { //处理文本
  352. if (lastText) //如果上一条不是文本
  353. { //添加一条新的文本,或者换行
  354. strPart.push(inf.text || "\\A");
  355. }else
  356. { //处理每一张图片
  357. str.push(strPart.map(function(item){return 'url("' + item + '")'}).join("")); //已储存的图片添加到最终字符串
  358. strPart = [];
  359. lastText = true;
  360. strPart.push(inf.text || "\\A");
  361. }
  362. }else if (creatImage) //如果同意生成图片,才处理图片
  363. { //处理图片
  364. if (lastText)
  365. { //处理每一条文本
  366. var txtTmp = strPart.join("");
  367. txtTmp = txtTmp.replace(/\"/igm,"\\\""); //将引号改为斜杠引号
  368. if (!creatImage) txtTmp = dealEmoji(txtTmp); //去除Emoji
  369. str.push('"' + txtTmp + '"');
  370. strPart = [];
  371. lastText = false;
  372. strPart.push(inf.src);
  373. }else
  374. { //添加一张新的图片
  375. strPart.push(inf.src);
  376. }
  377. }
  378. }
  379. //最后没被处理掉的
  380. if (lastText)
  381. { //处理每一条文本
  382. var txtTmp = strPart.join("");
  383. txtTmp = txtTmp.replace(/\"/igm,"\\\""); //将引号改为斜杠引号
  384. if (!creatImage) txtTmp = dealEmoji(txtTmp); //去除Emoji
  385. str.push('"' + txtTmp + '"');
  386. strPart = [];
  387. lastText = false;
  388. }else
  389. { //处理每一张图片
  390. str.push(strPart.map(function(item){return 'url("' + item + '")'}).join(""));
  391. strPart = [];
  392. lastText = true;
  393. }
  394. return str.join("");
  395. }
  396.  
  397. //处理Tag页面
  398. function dealTags(response, rowdataset)
  399. {
  400. var rowTags = rowdataset.tags;
  401. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  402. var table = PageDOM.querySelector((newRe?"#readme":"#wiki-body")+" .markdown-body table");
  403. if (table == undefined)
  404. {
  405. alert(PageDOM.title + "\n该页面未发现数据表格,可能存在格式错误。")
  406. console.error("未发现表格",PageDOM.title);
  407. }
  408. var tBody = table.tBodies[0];
  409. for(var ri=0, rilen=tBody.rows.length; ri<rilen; ri++)
  410. {
  411. var trow = tBody.rows[ri];
  412. var tag = new tagObj;
  413. if (trow.cells.length > 2)
  414. {//没有足够单元格的跳过
  415. tag.name = trow.cells[0].textContent.replace(/(^\s|\s$)/ig,""); //去除首尾空格
  416. tag.cname = InfoToArray(trow.cells[1]);
  417. tag.info = InfoToArray(trow.cells[2]);
  418. tag.links = LinksToArray(trow.cells[3]);
  419. //type=0代表一行翻译,1代表注释
  420. tag.type = tag.name.replace(/\s/ig,"").length < 1 ? 1 : 0; //英文去除所有空格后如果没有文字,则算为注释
  421. if (tag.type != 1 && tag.cname.length < 1) //不是注释,中文名又没有文字
  422. {
  423. //console.error("发现无中文翻译行%d - %s:%s",ri,rowdataset.name,tag.name);
  424. }
  425. if (tag.type != 1 && rowTags.some(function(ttag){return ttag.name == tag.name;})) //从数组中搜索任一符合条件的,返回true
  426. {
  427. console.error("发现重复定义行%d - %s:%s",ri,rowdataset.name,tag.name);
  428. }
  429. rowTags.push(tag);
  430. }
  431. else
  432. {
  433. console.error("发现无3单元格的错误行%d %s",ri,tag.name);
  434. }
  435. }
  436. rowsCurrent++;
  437. }
  438.  
  439. //点击开始任务按钮
  440. function startProgram(dataset, mode){
  441. var downOver = startProgramCheck(dataset, mode);
  442. if (!downOver || downOverCheckHook == undefined)
  443. {
  444. GM_xmlhttpRequest({
  445. method: "GET",
  446. url: wiki_URL + "/" + wiki_version_filename,
  447. onload: function(response) {
  448. dealVersion(response.responseText);
  449. GM_xmlhttpRequest({
  450. method: "GET",
  451. url: wiki_URL + "/" + rows_filename,
  452. onload: function(response) {
  453. dealRows(response.responseText,dataset);
  454. }
  455. });
  456. },
  457. onerror: function(response) {
  458. dealVersion("");
  459. GM_xmlhttpRequest({
  460. method: "GET",
  461. url: wiki_URL + "/" + rows_filename,
  462. onload: function(response) {
  463. dealRows(response.responseText,dataset);
  464. }
  465. });
  466. },
  467. });
  468. downOverCheckHook = setInterval(function () { startProgramCheck(dataset, mode) }, 200);
  469. }
  470. if (!downOver)
  471. {
  472. buildDownloadProgress();
  473. }
  474. }
  475.  
  476. //创建下载进度窗口
  477. function buildDownloadProgress()
  478. {
  479. var page_get_w = document.querySelector("#ETB_page-get");
  480. if (!page_get_w)
  481. {
  482. windowInserPlace.appendChild(buildMenuModal("window", "ETB_page-get", "数据获取进度", null, [
  483. buildMenuList([
  484. buildMenuItem((function()
  485. {
  486. var div = document.createElement("div");
  487. var span1 = document.createElement("span");
  488. span1.className = "page-title";
  489. span1.innerHTML = "Wiki结构版本";
  490. div.appendChild(span1);
  491. var span2 = document.createElement("span");
  492. span2.className = "page-get-wiki-version";
  493. span2.innerHTML = "等待";
  494. div.appendChild(span2);
  495. return div;
  496. })()
  497. ),
  498. buildMenuItem((function()
  499. {
  500. var div = document.createElement("div");
  501. var span1 = document.createElement("span");
  502. span1.className = "page-title";
  503. span1.innerHTML = "列表页面";
  504. div.appendChild(span1);
  505. var span2 = document.createElement("span");
  506. span2.className = "page-get-rows";
  507. span2.innerHTML = "等待";
  508. div.appendChild(span2);
  509. return div;
  510. })()
  511. ),
  512. ])
  513. ],
  514. [
  515. ".ETB_page-get .page-title" + "{\r\n" + [
  516. 'font-weight: bold',
  517. 'margin-right: 15px',
  518. ].join(';\r\n') + "\r\n}",
  519. ".ETB_page-get .page-load" + "{\r\n" + [
  520. 'color: #0A0',
  521. ].join(';\r\n') + "\r\n}",
  522. ].join('\r\n')
  523. ));
  524. }
  525. else
  526. {
  527. page_get_w.style.display = "block";
  528. }
  529. }
  530.  
  531. //检测下载完成情况
  532. function startProgramCheck(dataset, mode)
  533. {
  534. if (rowsCount > 0 && rowsCurrent >= rowsCount)
  535. {
  536. console.debug("获取完成");
  537. clearInterval(downOverCheckHook);
  538. switch (mode) {
  539. case 1:
  540. buildJSOutput(dataset);
  541. break;
  542. case 0:
  543. default:
  544. buildCSSOutput(dataset);
  545. break;
  546. }
  547. var page_get_w = document.querySelector("#ETB_page-get");
  548. if (page_get_w)
  549. {
  550. page_get_w.parentNode.removeChild(page_get_w);
  551. }
  552. return true;
  553. }
  554. else
  555. {
  556. console.debug("获取%d/%d",rowsCurrent, rowsCount);
  557. return false;
  558. }
  559. }
  560.  
  561. //获取完成后创建CSS输出窗口
  562. function buildCSSOutput(dataset)
  563. {
  564. var css = createOutputCSS(dataset
  565. ,GM_getValue("ETB_create-info","boolean")
  566. ,GM_getValue("ETB_create-info-image","boolean")
  567. ,GM_getValue("ETB_create-cname-image","boolean")
  568. );
  569. var downBlob = new Blob([css], {'type': 'text\/css'});
  570. var downurl = window.URL.createObjectURL(downBlob);
  571. var css_output_w = document.querySelector("#ETB_css-output");
  572. if (!css_output_w)
  573. {
  574. windowInserPlace.appendChild(buildMenuModal("window", "ETB_css-output", "用户样式版EhTagTranslator", null,
  575. [
  576. buildMenuList([
  577. buildMenuItem("CSS文本",
  578. (function()
  579. {
  580. var textarea = document.createElement("textarea");
  581. textarea.id = "ETB_css-textarea";
  582. textarea.name = textarea.id;
  583. textarea.className = "txta " + textarea.id;
  584. textarea.value = css;
  585. textarea.wrap = "off";
  586. textarea.setAttribute("readonly",true);
  587. return textarea;
  588. })()
  589. ,buildSVG("css")),
  590. buildMenuItem("直接下载CSS文件",null,buildSVG("download"),downurl,1),
  591. ])
  592. ],
  593. [
  594. ".ETB_css-output .txta" + "{\r\n" + [
  595. 'resize: vertical',
  596. 'width:100%',
  597. 'height:300px',
  598. ].join(';\r\n') + "\r\n}",
  599. ].join('\r\n')
  600. ));
  601. }
  602. else
  603. {
  604. css_output_w.style.display = "block";
  605. css_output_w.querySelector(".ETB_css-textarea").value = css;
  606. css_output_w.querySelector("a").href = downurl;
  607. }
  608. }
  609.  
  610. //开始构建CSS
  611. function createOutputCSS(dataset, createInfo, createInfoImage, createCnameImage)
  612. {
  613. if (createInfo == undefined) createInfo = true;
  614. if (createInfoImage == undefined) createInfoImage = true;
  615. if (createCnameImage == undefined) createCnameImage = true;
  616. var date = new Date();
  617. var cssAry = [];
  618. //样式信息说明
  619. cssAry.push(
  620. "/* EhTagTranslator 用户样式版,由 " + scriptName + " v" + scriptVersion + " 构建"
  621. ," * 数据来源于" + wiki_URL
  622. ," * 构建时间为"
  623. ," * " + date.toString()
  624. ," */"
  625. )
  626. //样式命名区间
  627. cssAry.push(
  628. //▼CSS内容部分
  629. "@namespace url(http://www.w3.org/1999/xhtml);"
  630. //▲CSS内容部分
  631. );
  632.  
  633. //表里通用样式
  634. cssAry.push(""
  635. //▼CSS内容部分
  636. ,"/* 表里通用样式 */"
  637. ,"@-moz-document"
  638. ," domain('exhentai.org'),"
  639. ," domain('e-hentai.org')"
  640. ,"{"
  641. ,GM_getValue("ETB_global-style")
  642. ,"}"
  643. //▲CSS内容部分
  644. );
  645.  
  646. //表站样式
  647. cssAry.push(""
  648. //▼CSS内容部分
  649. ,"/* 表站样式 */"
  650. ,"@-moz-document"
  651. ," domain('e-hentai.org')"
  652. ,"{"
  653. ,GM_getValue("ETB_global-style-eh")
  654. ,"}"
  655. //▲CSS内容部分
  656. );
  657.  
  658. //里站样式
  659. cssAry.push(""
  660. //▼CSS内容部分
  661. ,"/* 里站样式 */"
  662. ,"@-moz-document"
  663. ," domain('exhentai.org')"
  664. ,"{"
  665. ,GM_getValue("ETB_global-style-ex")
  666. ,"}"
  667. //▲CSS内容部分
  668. );
  669.  
  670. //翻译内容
  671. cssAry.push(""
  672. //▼CSS内容部分
  673. ,"/* 翻译内容 */"
  674. ,"@-moz-document"
  675. ," domain('exhentai.org'),"
  676. ," domain('e-hentai.org')"
  677. ,"{"
  678. //▲CSS内容部分
  679. );
  680.  
  681. dataset.forEach(function(row){
  682.  
  683. //添加行名的注释
  684. cssAry.push(""
  685. ,"/* " + row.name
  686. ," * " + row.cname
  687. .filter(function(item){return item.type==0;})
  688. .map(function(item){return item.text;})
  689. .join("")
  690. ," */"
  691. );
  692.  
  693. row.tags.forEach(function(tag){
  694.  
  695. if (tag.type == 0)
  696. {
  697. var tagid = (row.name=="misc"?"":row.name + ":") + tag.name.replace(/\s/ig,"_");
  698. cssAry.push(""
  699. //▼CSS内容部分
  700. ," a[id=\"ta_" + tagid + "\"]{"
  701. ," font-size:0;"
  702. ," }"
  703. ," a[id=\"ta_" + tagid + "\"]::before{"
  704. ," content:" + InfoArrayToCssString(tag.cname, createCnameImage) + ";"
  705. ," }"
  706. //▲CSS内容部分
  707. );
  708. if (createInfo)
  709. {
  710. var sinfo = InfoArrayToCssString(tag.info, createInfoImage);
  711. if (sinfo.replace(/\s/ig,"").length > 0)
  712. {
  713. cssAry.push(""
  714. //▼CSS内容部分
  715. ," a[id=\"ta_" + tagid + "\"]::after{"
  716. ," content:" + sinfo + ";"
  717. ," }"
  718. //▲CSS内容部分
  719. );
  720. }
  721. }
  722. }
  723. else
  724. { //将注释写成CSS注释
  725. cssAry.push(
  726. "/* " + InfoArrayToCssString(tag.cname, false)
  727. ," * " + InfoArrayToCssString(tag.info, false)
  728. ," */"
  729. );
  730. }
  731. })//row.tags.forEach
  732. });//dataset.forEach
  733.  
  734. cssAry.push(
  735. //▼CSS内容部分
  736. "}"
  737. //▲CSS内容部分
  738. );
  739. var css = cssAry.join("\r\n");
  740. return css;
  741. }
  742.  
  743. //获取完成后创建JS输出窗口
  744. function buildJSOutput(dataset)
  745. {
  746. var json = createOutputJSON(dataset
  747. ,GM_getValue("ETB_create-info","boolean")
  748. ,GM_getValue("ETB_create-info-image","boolean")
  749. ,GM_getValue("ETB_create-cname-image","boolean")
  750. );
  751. var jsonStr = JSON.stringify(json);
  752. var downBlob = new Blob([jsonStr], {'type': 'text\/json'});
  753. var downurl = window.URL.createObjectURL(downBlob);
  754. var js_output_w = document.querySelector("#ETB_js-output");
  755. if (!js_output_w)
  756. {
  757. windowInserPlace.appendChild(buildMenuModal("window", "ETB_js-output", "用户脚本版EhTagTranslator数据库", null,
  758. [
  759. buildMenuList([
  760. buildMenuItem("JSON文本",
  761. (function()
  762. {
  763. var textarea = document.createElement("textarea");
  764. textarea.id = "ETB_js-textarea";
  765. textarea.name = textarea.id;
  766. textarea.className = "txta " + textarea.id;
  767. textarea.value = jsonStr;
  768. textarea.setAttribute("readonly",true);
  769. return textarea;
  770. })()
  771. ,buildSVG("json")),
  772. buildMenuItem("数据库数量",
  773. (function()
  774. {
  775. var tb = document.createElement("table");
  776. tb.id = "ETB_database-count";
  777. tb.name = tb.id;
  778. tb.className = tb.id;
  779. //正式开始构建内容
  780. //tHead
  781. tb.createTHead();
  782. var th = tb.tHead.insertRow();
  783. th.insertCell().appendChild(document.createTextNode("行名"));
  784. th.insertCell().appendChild(document.createTextNode("数据行数"));
  785. th.insertCell().appendChild(document.createTextNode("注释行数"));
  786. //tBody
  787. json.dataset.forEach(function(item){
  788. var tr = tb.insertRow();
  789. tr.insertCell().appendChild(document.createTextNode(item.cname
  790. .filter(function(item){return item.type==0;})
  791. .map(function(item){return item.text;})
  792. .join("")));
  793. tr.insertCell().appendChild(document.createTextNode(item.tags.filter(function(item){return item.type==0}).length));
  794. tr.insertCell().appendChild(document.createTextNode(item.tags.filter(function(item){return item.type==1}).length));
  795. })
  796. return tb;
  797. })()
  798. ,buildSVG("book")),
  799. buildMenuItem("直接下载JSON文件",null,buildSVG("download"),downurl,1)
  800. ])
  801. ],
  802. [
  803. ".ETB_js-output .txta" + "{\r\n" + [
  804. 'resize: vertical',
  805. 'width:100%',
  806. 'height:200px',
  807. ].join(';\r\n') + "\r\n}",
  808. "#ETB_js-output .select-menu-list" + "{\r\n" + [
  809. 'max-height: 700px',
  810. ].join(';\r\n') + "\r\n}",
  811. "#ETB_database-count,#ETB_database-count td" + "{\r\n" + [
  812. 'border: solid 1px lightgrey;',
  813. ].join(';\r\n') + "\r\n}",
  814. ].join('\r\n')
  815. ));
  816. }
  817. else
  818. {
  819. js_output_w.style.display = "block";
  820. js_output_w.querySelector(".ETB_js-textarea").value = jsonStr;
  821. js_output_w.querySelector("a").href = downurl;
  822. }
  823. }
  824.  
  825. //开始构建JSON
  826. function createOutputJSON(dataset, createInfo, createInfoImage, createCnameImage)
  827. {
  828. if (createInfo == undefined) createInfo = true;
  829. if (createInfoImage == undefined) createInfoImage = true;
  830. if (createCnameImage == undefined) createCnameImage = true;
  831.  
  832. var outArray =
  833. /*
  834. * 生成一个不会干涉到原对象的Row对象
  835. */
  836. dataset.map(function(row_orignal){
  837. var row = Object.assign(new rowObj(), row_orignal);
  838. row.cname=row_orignal.cname
  839. .filter(function(item){return createCnameImage || item.type != 2;})
  840. .map(function(item){
  841. var newItem = Object.assign({}, item);
  842. if(!createCnameImage && item.text) {
  843. newItem.text = dealEmoji(item.text);
  844. }
  845. return newItem;
  846. });
  847. if (createInfo)
  848. {
  849. row.info=row_orignal.info
  850. .filter(function(item){return createInfoImage || item.type != 2;})
  851. .map(function(item){
  852. var newItem = Object.assign({}, item);
  853. if(!createInfoImage && item.text) {
  854. newItem.text = dealEmoji(item.text);
  855. }
  856. return newItem;
  857. });
  858. }
  859. else
  860. {
  861. row.info = null;
  862. }
  863. row.links=row_orignal.links
  864. .map(function(item){
  865. var newItem = Object.assign(new linkObj(), item);
  866. return newItem;
  867. });
  868.  
  869. row.tags =
  870. /*
  871. * 生成一个不会干涉到原对象的Tag对象
  872. */
  873. row_orignal.tags.map(function(tag_orignal){
  874. var tag = Object.assign(new tagObj(), tag_orignal);
  875. tag.cname=tag_orignal.cname
  876. .filter(function(item){return createCnameImage || item.type != 2;})
  877. .map(function(item){
  878. var newItem = Object.assign({}, item);
  879. if(!createCnameImage && item.text) {
  880. newItem.text = dealEmoji(item.text);
  881. }
  882. return newItem;
  883. });
  884. tag.links=tag_orignal.links
  885. .map(function(item){
  886. var newItem = Object.assign(new linkObj(), item);
  887. return newItem;
  888. });
  889.  
  890. if (createInfo || tag.type==1)
  891. {
  892. tag.info=tag_orignal.info
  893. .filter(function(item){return createInfoImage || item.type != 2;})
  894. .map(function(item){
  895. var newItem = Object.assign({}, item);
  896. if(!createInfoImage && item.text) {
  897. newItem.text = dealEmoji(item.text);
  898. }
  899. return newItem;
  900. });
  901. }
  902. else
  903. {
  904. tag.info = null;
  905. }
  906. return tag;
  907. })//row.tags.forEach
  908.  
  909. return row;
  910. });//dataset.forEach
  911.  
  912. var date = new Date();
  913. var outJson =
  914. {
  915. "scriptName":scriptName,
  916. "scriptVersion":scriptVersion,
  917. "database-structure-version":database_structure_version,
  918. "date":date.getTime(),
  919. "dataset":outArray
  920. }
  921. return outJson;
  922. }
  923.  
  924. //去除文本中的Emoji字符
  925. function dealEmoji(str)
  926. {
  927. return str.replace(emojireg,"");
  928. }
  929.  
  930. //生成按钮
  931. function buildButton(title, icon, modal)
  932. {
  933. var li = document.createElement("li");
  934. var select_menu = document.createElement("div");
  935. select_menu.className = "select-menu js-menu-container js-select-menu";
  936. li.appendChild(select_menu);
  937. var button = document.createElement("button");
  938. button.className = "btn btn-sm select-menu-button js-menu-target css-truncate";
  939. select_menu.appendChild(button);
  940. var span = document.createElement("span");
  941. span.className = "js-select-button";
  942. if (icon != undefined)
  943. span.appendChild(icon);
  944. span.innerHTML += title;
  945. button.appendChild(span);
  946. select_menu.appendChild(modal);
  947. return li;
  948. }
  949.  
  950. //生成菜单窗口
  951. function buildMenuModal(mode, id, stitle, filters, lists, sstyle)
  952. {
  953. var modal_holder = document.createElement("div");
  954. modal_holder.className = "select-menu-modal-holder js-menu-content js-navigation-container js-active-navigation-container";
  955. if (id != undefined)
  956. {
  957. modal_holder.id = id;
  958. modal_holder.classList.add(id);
  959. }
  960. if (sstyle != undefined)
  961. {
  962. var style = document.createElement("style");
  963. style.innerHTML = sstyle;
  964. modal_holder.appendChild(style);
  965. }
  966.  
  967. var modal = document.createElement("div");
  968. modal.className = "select-menu-modal subscription-menu-modal js-menu-content";
  969. modal_holder.appendChild(modal);
  970. var header = document.createElement("div");
  971. header.className = "select-menu-header js-navigation-enable";
  972. modal.appendChild(header);
  973. var CloseSvg = buildSVG("Close");
  974. header.appendChild(CloseSvg);
  975.  
  976. switch (mode) {
  977. case "window":
  978. modal_holder.style.display = "block";
  979. CloseSvg.onclick = function(){
  980. modal_holder.style.display = "none";
  981. }
  982. break;
  983.  
  984. case "menu":
  985. default:
  986. break;
  987. }
  988. var title = document.createElement("span");
  989. title.className = "select-menu-title";
  990. title.innerHTML = stitle;
  991. header.appendChild(title);
  992.  
  993. if (lists != undefined)
  994. {
  995. for(var li = 0, lilen=lists.length; li<lilen; li++)
  996. {
  997. var list = lists[li];
  998. if (list)
  999. modal.appendChild(list);
  1000. }
  1001. }
  1002. return modal_holder;
  1003. }
  1004.  
  1005. //构建一个菜单列表框架
  1006. function buildMenuList(items)
  1007. {
  1008. var list = document.createElement("div");
  1009. list.className = "select-menu-list js-navigation-container";
  1010. if (items != undefined)
  1011. {
  1012. for(var ii=0, lilen=items.length; ii<lilen; ii++)
  1013. {
  1014. var item = items[ii];
  1015. if (item)
  1016. list.appendChild(item);
  1017. }
  1018. }
  1019. return list;
  1020. }
  1021.  
  1022. //构建一个菜单列表项
  1023. function buildMenuItem(heading, description, icon, callback, type)
  1024. {
  1025. if (heading == undefined) heading = "未设定";
  1026. var item = document.createElement("div");
  1027. if (type == 3)
  1028. {
  1029. var item = document.createElement("label");
  1030. item.setAttribute('for', callback);
  1031. }
  1032. else if (typeof(callback) == "string")
  1033. {
  1034. var item = document.createElement("a");
  1035. item.target = "_blank";
  1036. item.href = callback;
  1037. }
  1038. else
  1039. {
  1040. if (callback) item.onclick = callback;
  1041. }
  1042. item.className = "select-menu-item";
  1043. switch (type) {
  1044. case 0:
  1045. item.classList.add("js-navigation-item");
  1046. break;
  1047. case 1:
  1048. item.classList.add("select-menu-action");
  1049. break;
  1050. default:
  1051. break;
  1052. }
  1053. if (icon != undefined) item.appendChild(icon);
  1054. var item_text = document.createElement("div");
  1055. item_text.className = "select-menu-item-text";
  1056. item.appendChild(item_text);
  1057. if (description != undefined)
  1058. {
  1059. var item_heading = document.createElement("span");
  1060. item_heading.className = "select-menu-item-heading";
  1061. if (typeof(heading)=="string")
  1062. item_heading.innerHTML = heading;
  1063. else
  1064. item_heading.appendChild(heading);
  1065. var item_description = document.createElement("span");
  1066. item_description.className = "description";
  1067. if (typeof(description)=="string")
  1068. item_description.innerHTML = description;
  1069. else
  1070. item_description.appendChild(description);
  1071. item_text.appendChild(item_heading);
  1072. item_text.appendChild(item_description);
  1073. }
  1074. else
  1075. {
  1076. if (typeof(heading)=="string")
  1077. item_text.innerHTML = heading;
  1078. else
  1079. item_text.appendChild(heading);
  1080. }
  1081. return item;
  1082. }
  1083. //生成svg
  1084. function buildSVG(mode,check)
  1085. {
  1086. if (check == undefined) check = false;
  1087. var CloseSvgDiv = document.createElement("div");
  1088. var innerHTML = "";
  1089. switch (mode) {
  1090. case "Close":
  1091. innerHTML = '<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48-3.75-3.75-3.75 3.75-1.48-1.48 3.75-3.75L0.77 4.25l1.48-1.48 3.75 3.75 3.75-3.75 1.48 1.48-3.75 3.75z"/></svg>';
  1092. break;
  1093.  
  1094. case "Settings":
  1095. innerHTML = '<svg width="14" viewBox="0 0 14 16" version="1.1" height="16" class="octicon octicon-question select-menu-item-icon" aria-hidden="true"><path d="M14 8.77V7.17l-1.94-0.64-0.45-1.09 0.88-1.84-1.13-1.13-1.81 0.91-1.09-0.45-0.69-1.92H6.17l-0.63 1.94-1.11 0.45-1.84-0.88-1.13 1.13 0.91 1.81-0.45 1.09L0 7.23v1.59l1.94 0.64 0.45 1.09-0.88 1.84 1.13 1.13 1.81-0.91 1.09 0.45 0.69 1.92h1.59l0.63-1.94 1.11-0.45 1.84 0.88 1.13-1.13-0.92-1.81 0.47-1.09 1.92-0.69zM7 11c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"/></svg>';
  1096. break;
  1097.  
  1098. case "check":
  1099. innerHTML = '<svg width="12" viewBox="0 0 12 16" version="1.1" height="16" class="octicon octicon-check select-menu-item-icon" aria-hidden="true"><path d="M12 5L4 13 0 9l1.5-1.5 2.5 2.5 6.5-6.5 1.5 1.5z"/></svg>';
  1100. break;
  1101.  
  1102. case "question":
  1103. innerHTML = '<svg width="14" viewBox="0 0 14 16" version="1.1" height="16" class="octicon octicon-question select-menu-item-icon" aria-hidden="true"><path d="M6 10h2v2H6V10z m4-3.5c0 2.14-2 2.5-2 2.5H6c0-0.55 0.45-1 1-1h0.5c0.28 0 0.5-0.22 0.5-0.5v-1c0-0.28-0.22-0.5-0.5-0.5h-1c-0.28 0-0.5 0.22-0.5 0.5v0.5H4c0-1.5 1.5-3 3-3s3 1 3 2.5zM7 2.3c3.14 0 5.7 2.56 5.7 5.7S10.14 13.7 7 13.7 1.3 11.14 1.3 8s2.56-5.7 5.7-5.7m0-1.3C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7S10.86 1 7 1z"/></svg>';
  1104. break;
  1105.  
  1106. case "download":
  1107. innerHTML = '<svg width="16" viewBox="0 0 16 16" version="1.1" height="16" class="octicon octicon-desktop-download select-menu-item-icon" aria-hidden="true"><path d="M4 6h3V0h2v6h3L8 10 4 6z m11-4H11v1h4v8H1V3h4v-1H1c-0.55 0-1 0.45-1 1v9c0 0.55 0.45 1 1 1h5.34c-0.25 0.61-0.86 1.39-2.34 2h8c-1.48-0.61-2.09-1.39-2.34-2h5.34c0.55 0 1-0.45 1-1V3c0-0.55-0.45-1-1-1z"/></svg>';
  1108. break;
  1109.  
  1110. case "book":
  1111. innerHTML = '<svg width="16" viewBox="0 0 16 16" version="1.1" height="16" class="octicon octicon-book select-menu-item-icon" aria-hidden="true"><path d="M2 5h4v1H2v-1z m0 3h4v-1H2v1z m0 2h4v-1H2v1z m11-5H9v1h4v-1z m0 2H9v1h4v-1z m0 2H9v1h4v-1z m2-6v9c0 0.55-0.45 1-1 1H8.5l-1 1-1-1H1c-0.55 0-1-0.45-1-1V3c0-0.55 0.45-1 1-1h5.5l1 1 1-1h5.5c0.55 0 1 0.45 1 1z m-8 0.5l-0.5-0.5H1v9h6V3.5z m7-0.5H8.5l-0.5 0.5v8.5h6V3z"/></svg>';
  1112. break;
  1113. case "code":
  1114. innerHTML = '<svg width="14" viewBox="0 0 14 16" version="1.1" height="16" class="octicon octicon-code select-menu-item-icon" aria-hidden="true"><path d="M9.5 3l-1.5 1.5 3.5 3.5L8 11.5l1.5 1.5 4.5-5L9.5 3zM4.5 3L0 8l4.5 5 1.5-1.5L2.5 8l3.5-3.5L4.5 3z"/></svg>'
  1115. break;
  1116. case "css":
  1117. innerHTML = '<svg width="16" height="16" viewBox="0 0 64 64" version="1.1" class="octicon octicon-question select-menu-item-icon"><defs><path d="M0 14.995C0 6.714 6.713 0 14.995 0h34.01C57.286 0 64 6.713 64 14.995v34.01C64 57.287 57.287 64 49.005 64h-34.01C6.714 64 0 57.287 0 49.005v-34.01z" id="a"/></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><use fill-opacity="0" fill="#FFF" xlink:href="#a"/><path fill="#2ECC71" mask="url(#b)" d="M30 0v39H0V0z"/><path fill="#E74C3C" mask="url(#b)" d="M64 0v21H34V0z"/><path fill="#F39C12" mask="url(#b)" d="M30 43v21H0V43z"/><path fill="#3498DB" mask="url(#b)" d="M64 25.5v39H34v-39z"/></g></svg>';
  1118. break;
  1119.  
  1120. case "json":
  1121. innerHTML = '<svg viewBox="0 0 16 16" height="15" width="16" version="1.1" class="octicon octicon-code select-menu-item-icon"><defs><style>.cls-1{fill:url(#linearGradient_1);}.cls-2{fill:url(#linearGradient_2);}</style><linearGradient gradientUnits="userSpaceOnUse" gradientTransform="matrix(1, 0, 0, -1, 688.46, -371.22)" y2="-385.5" x2="-675.75" y1="-374.22" x1="-687.04" id="linearGradient_1"><stop offset="0"/><stop stop-color="#fff" offset="1"/></linearGradient><linearGradient xlink:href="#linearGradient_1" y2="-373.71" x2="-686.52" y1="-384.99" x1="-675.24" id="linearGradient_2"/></defs><path style="fill:url(#linearGradient_1)" d="M8,11.91c3.54,4.83,7-1.35,7-5.06C15,2.46,10.53,0,8,0A8.07,8.07,0,0,0,0,8a8.06,8.06,0,0,0,8,8c-0.8-.11-3.45-0.68-3.49-6.8C4.47,5.07,5.85,3.42,8,4.14A4.06,4.06,0,0,1,10.33,8,4.08,4.08,0,0,1,8,11.91Z" class="cls-1"/><path style="fill:url(#linearGradient_2)" d="M8,4.14c-2.34-.81-5.2,1.12-5.2,5C2.78,15.43,7.45,16,8,16a8.07,8.07,0,0,0,8-8A8.06,8.06,0,0,0,8,0c1-.13,5.25,1.05,5.25,6.9,0,3.81-3.2,5.89-5.27,5A4.06,4.06,0,0,1,5.65,8,4.1,4.1,0,0,1,8,4.14Z" class="cls-2"/></svg>';
  1122. break;
  1123.  
  1124. case "eh":
  1125. innerHTML = '<svg class="octicon" style="margin:2px 2px;" width="12" height="12" viewBox="0 0 180 180" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="EH" fill="#000000" transform="translate(0.000000, 13.000000)"><polygon id="Path-2" points="0 0.202883984 0 153.452455 63.9237403 153.452455 63.9237403 128.434878 25.3357783 128.434878 25.3357783 89.8192926 51.0881973 89.8192926 51.0881973 64.4842269 25.815364 64.4842269 25.815364 26.0161147 63.9458219 26.0161147 63.9458219 0"></polygon><polygon id="Path-3" points="102.413793 0.499934441 102.413793 153.799341 128.267497 153.799341 128.267497 89.8145927 153.883139 89.8145927 153.883139 153.360711 179.611922 153.360711 179.611922 0 154.060738 0 154.060738 63.8323757 128.389266 63.8323757 128.389266 0.125830495"></polygon><rect id="Rectangle" x="63.6206897" y="64.9220339" width="26.3793103" height="26.2779661"></rect></g></svg>';
  1126. break;
  1127. default:
  1128. innerHTML = '<svg width="12" viewBox="0 0 12 16" version="1.1" height="16" class="octicon octicon-check select-menu-item-icon" aria-hidden="true"></svg>';
  1129. break;
  1130. }
  1131. CloseSvgDiv.innerHTML = innerHTML;
  1132. var CloseSvg = CloseSvgDiv.firstChild;
  1133. if(check)
  1134. CloseSvg.classList.add("octicon-check");
  1135. else
  1136. CloseSvg.classList.remove("octicon-check");
  1137. //更改SVG的渐变ID名
  1138. function changeSvgIdName(svg)
  1139. {
  1140. var linearGradient = svg.getElementsByTagName("linearGradient");
  1141. for (var lGi=0, lGilen=linearGradient.length;lGi<lGilen;lGi++)
  1142. {
  1143. var idName = linearGradient[lGi].id;
  1144. var idIndex = 0;
  1145. while(document.querySelector("#" + idName + "_" + idIndex.toString()))
  1146. {
  1147. idIndex++;
  1148. }
  1149. linearGradient[lGi].id = idName + "_" + idIndex.toString();
  1150. var idReg = new RegExp("#" + idName + "", "igm"); //P站图片地址正则匹配式
  1151. svg.innerHTML = svg.innerHTML.replace(idReg,"#" + idName + "_" + idIndex.toString());
  1152. }
  1153. return svg;
  1154. }
  1155. CloseSvg = changeSvgIdName(CloseSvg);
  1156.  
  1157. return CloseSvg;
  1158. }
  1159. //打开设置窗口
  1160. function startOption()
  1161. {
  1162. var option_modal_w = document.querySelector("#ETB_option");
  1163. if (!option_modal_w)
  1164. {
  1165. windowInserPlace.appendChild(
  1166. buildMenuModal("window", "ETB_option", scriptName + " 设置", null, [
  1167. buildMenuList([
  1168. buildMenuItem("生成简介","生成光标移动到Tag上时出现的简介。",
  1169. (function(){
  1170. var chk = document.createElement("input");
  1171. chk.type = "checkbox";
  1172. chk.id = "ETB_create-info";
  1173. chk.name = chk.id;
  1174. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1175. return chk;
  1176. })()
  1177. ,"ETB_create-info",3),
  1178. buildMenuItem("生成简介图片和Emoji","生成简介中的图片和绘文字。",
  1179. (function(){
  1180. var chk = document.createElement("input");
  1181. chk.type = "checkbox";
  1182. chk.id = "ETB_create-info-image";
  1183. chk.name = chk.id;
  1184. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1185. return chk;
  1186. })()
  1187. ,"ETB_create-info-image",3),
  1188. buildMenuItem("生成中文名图片和Emoji","生成中文名中的图片和绘文字,一般为名称前的小图标。",
  1189. (function(){
  1190. var chk = document.createElement("input");
  1191. chk.type = "checkbox";
  1192. chk.id = "ETB_create-cname-image";
  1193. chk.name = chk.id;
  1194. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1195. return chk;
  1196. })()
  1197. ,"ETB_create-cname-image",3),
  1198. buildMenuItem("Tag通用样式",
  1199. (function(){
  1200. var div = document.createElement("div");
  1201. var span1 = document.createElement("div");
  1202. span1.innerHTML = "Tag统一应用的样式,可修改为自己喜爱的样式。";
  1203. div.appendChild(span1);
  1204. //表里共用
  1205. var textarea = document.createElement("textarea");
  1206. textarea.id = "ETB_global-style";
  1207. textarea.name = textarea.id;
  1208. textarea.className = "txta " + textarea.id;
  1209. textarea.wrap = "off";
  1210. var label = document.createElement("label");
  1211. label.setAttribute('for', textarea.id);
  1212. label.innerHTML = "表里共用样式";
  1213. div.appendChild(label);
  1214. div.appendChild(textarea);
  1215. //表站
  1216. var textarea = document.createElement("textarea");
  1217. textarea.id = "ETB_global-style-eh";
  1218. textarea.name = textarea.id;
  1219. textarea.className = "txta " + textarea.id;
  1220. textarea.wrap = "off";
  1221. var label = document.createElement("label");
  1222. label.setAttribute('for', textarea.id);
  1223. label.innerHTML = "表站样式";
  1224. div.appendChild(label);
  1225. div.appendChild(textarea);
  1226. //里站
  1227. var textarea = document.createElement("textarea");
  1228. textarea.id = "ETB_global-style-ex";
  1229. textarea.name = textarea.id;
  1230. textarea.className = "txta " + textarea.id;
  1231. textarea.wrap = "off";
  1232. var label = document.createElement("label");
  1233. label.setAttribute('for', textarea.id);
  1234. label.innerHTML = "里站样式";
  1235. div.appendChild(label);
  1236. div.appendChild(textarea);
  1237. return div;
  1238. })()
  1239. ,buildSVG("css")),
  1240. ]),
  1241. buildMenuList([
  1242. buildMenuItem("其他用户分享的通用样式",null,buildSVG("code"),"https://github.com/Mapaler/EhTagTranslator/labels/%E6%A0%B7%E5%BC%8F%E5%88%86%E4%BA%AB",1),
  1243. buildMenuItem(
  1244. (function(){
  1245. var div = document.createElement("div");
  1246. var btn = document.createElement("button");
  1247. btn.innerHTML = "重置";
  1248. btn.id = "ETB_reset-option";
  1249. btn.name = btn.id;
  1250. btn.className = "btn btn-sm btn-danger " + btn.id;
  1251. btn.onclick = function(){
  1252. resetOption();
  1253. }
  1254. div.appendChild(btn);
  1255. /*
  1256. var btn2 = document.createElement("button");
  1257. btn2.innerHTML = "取消";
  1258. btn2.className = "btn btn-sm";
  1259. div.appendChild(btn2);
  1260. */
  1261. var btn = document.createElement("button");
  1262. btn.innerHTML = "保存";
  1263. btn.id = "ETB_save-option";
  1264. btn.name = btn.id;
  1265. btn.className = "btn btn-sm btn-primary " + btn.id;
  1266. btn.onclick = function(){
  1267. saveOption();
  1268. }
  1269. div.appendChild(btn);
  1270. return div;
  1271. })()
  1272. ,null,null,null,1),
  1273. ]),
  1274. ],
  1275. [
  1276. ".ETB_option .select-menu-item-text" + "{\r\n" + [
  1277. 'font-weight: normal',
  1278. ].join(';\r\n') + "\r\n}",
  1279. ".ETB_option .txta" + "{\r\n" + [
  1280. 'resize: vertical',
  1281. 'width: 100%',
  1282. 'height: 100px',
  1283. ].join(';\r\n') + "\r\n}",
  1284. ".ETB_option .ETB_save-option" + "{\r\n" + [
  1285. 'float: right',
  1286. ].join(';\r\n') + "\r\n}",
  1287. ].join('\r\n')
  1288. )
  1289. );
  1290. }
  1291. else
  1292. {
  1293. option_modal_w.style.display = "block";
  1294. }
  1295. }
  1296. //重置设置
  1297. function resetOption(part)
  1298. {
  1299. function partReset(name,value,ispart)
  1300. {
  1301. if (!ispart || ispart && GM_getValue(name) == undefined)
  1302. GM_setValue(name, value);
  1303. }
  1304. var cssAry = [];
  1305. var cssAry_eh = [];
  1306. var cssAry_ex = [];
  1307. cssAry.push(
  1308. //▼CSS内容部分
  1309. " #taglist a{"
  1310. ," background:inherit;"
  1311. ," border-color: inherit;"
  1312. ," }"
  1313. ," #taglist a::before{"
  1314. ," font-size:12px;"
  1315. ," }"
  1316. ," #taglist a::after{"
  1317. ," background: inherit;"
  1318. ," border-style: solid;"
  1319. ," border-width: 1px;"
  1320. ," border-color: inherit;"
  1321. ," border-radius:5px;"
  1322. ," font-size:12pt;"
  1323. ," float:left;"
  1324. ," position:fixed;"
  1325. ," z-index:999;"
  1326. ," padding:2px;"
  1327. ," box-shadow: 3px 3px 5px #888;"
  1328. ," min-width:150px;"
  1329. ," max-width:300px;"
  1330. ," white-space:pre-wrap;"
  1331. ," opacity: 0;"
  1332. ," transition: opacity 0.2s;"
  1333. ," transform: translate(30px,25px);"
  1334. ," top:0px;"
  1335. ," pointer-events:none;"
  1336. ," }"
  1337. ," #taglist a:hover::after,#taglist a:focus::after{"
  1338. ," opacity: 1;"
  1339. ," transition: opacity 0.5s;"
  1340. ," }"
  1341. //▲CSS内容部分
  1342. );
  1343. cssAry_eh.push(
  1344. //▼CSS内容部分
  1345. " #taglist a::after{"
  1346. ," color:#5c0d11;"
  1347. ," }"
  1348. //▲CSS内容部分
  1349. );
  1350. cssAry_ex.push(
  1351. //▼CSS内容部分
  1352. " #taglist a::after{"
  1353. ," color:#dddddd;"
  1354. ," }"
  1355. //▲CSS内容部分
  1356. );
  1357. partReset("ETB_option-version",optionVersion,part);
  1358. partReset("ETB_create-info","true",part);
  1359. partReset("ETB_create-info-image","true",part);
  1360. partReset("ETB_create-cname-image","true",part);
  1361. partReset("ETB_global-style",cssAry.join("\r\n"),part);
  1362. partReset("ETB_global-style-eh",cssAry_eh.join("\r\n"),part);
  1363. partReset("ETB_global-style-ex",cssAry_ex.join("\r\n"),part);
  1364. reloadOption();
  1365. }
  1366. //访问设置用递归函数
  1367. function visitChildNodes(dom, callback)
  1368. {
  1369. callback(dom);
  1370. for (var ci=0, cilen=dom.childNodes.length; ci<cilen; ci++)
  1371. {
  1372. visitChildNodes(dom.childNodes[ci], callback);
  1373. }
  1374. }
  1375. //保存设置
  1376. function saveOption()
  1377. {
  1378. var option_modal_w = document.querySelector("#ETB_option");
  1379. if (option_modal_w)
  1380. {
  1381. visitChildNodes(option_modal_w,setValue);
  1382. }
  1383. function setValue(dom)
  1384. {
  1385. if (dom.name && dom.value != undefined)
  1386. {
  1387. if (dom.type == "checkbox")
  1388. GM_setValue(dom.name, dom.checked);
  1389. else
  1390. GM_setValue(dom.name, dom.value);
  1391. }
  1392. }
  1393. option_modal_w.style.display = "none";
  1394. }
  1395. //重新加载设置窗口
  1396. function reloadOption()
  1397. {
  1398. var option_modal_w = document.querySelector("#ETB_option");
  1399. if (option_modal_w)
  1400. {
  1401. visitChildNodes(option_modal_w, getValue);
  1402. }
  1403. function getValue(dom)
  1404. {
  1405. if (dom.name && dom.value != undefined)
  1406. {
  1407. var value = GM_getValue(dom.name);
  1408. if (value != undefined)
  1409. {
  1410. if (dom.type != undefined && dom.type == "checkbox")
  1411. dom.checked = value;
  1412. else
  1413. dom.value = value;
  1414. }
  1415. }
  1416. }
  1417. }
  1418.  
  1419.  
  1420. /*
  1421. * 开始实际执行的程序
  1422. */
  1423.  
  1424. if (!GM_getValue("ETB_option-version"))
  1425. {
  1426. resetOption(false); //新用户重置设置
  1427. }
  1428. else if (GM_getValue("ETB_option-version", "number") < optionVersion)
  1429. { //老用户提醒更改设置
  1430. alert(scriptName + " 本次程序版本更新改变了设置结构,建议先重置设置,否则可能会导致无法正常使用。");
  1431. resetOption(true);
  1432. }
  1433.  
  1434. var menu_modal = buildMenuModal("menu", null, "请选择任务 v" + scriptVersion, null, [
  1435. buildMenuList([
  1436. buildMenuItem("生成CSS","生成用户样式版EhTagTranslator,请使用Stylus扩展安装。安卓火狐也可使用。",buildSVG("css"),function(){
  1437. startProgram(ds,0);
  1438. }
  1439. ,0),
  1440. buildMenuItem("生成JSON","为第三方程序生成EhTagTranslator数据库。",buildSVG("json"),function(){
  1441. startProgram(ds,1);
  1442. }
  1443. ,0)
  1444. ]),
  1445. buildMenuList([
  1446. buildMenuItem("选项",null,buildSVG("Settings"),function(){startOption();reloadOption();},1),
  1447. //buildMenuItem("查看使用帮助",null,buildSVG("question"),"https://github.com/Mapaler/EhTagTranslator/blob/master/README.md",1),
  1448. buildMenuItem("参与补全翻译",null,buildSVG("book"),"https://github.com/Mapaler/EhTagTranslator/wiki",1),
  1449. ])
  1450. ]);
  1451. buttonInserPlace.insertBefore(buildButton(" " + scriptName + " ", buildSVG("eh"), menu_modal),buttonInserPlace.querySelector("li"));
  1452. })();