EhTagBuilder

Build EhTagTranslater from Wiki.

  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.2
  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(".UnderlineNav"); //窗口插入位置
  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?6: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. onerror: function(response) {
  165. var page_get_w = document.querySelector("#ETB_page-get");
  166. if (page_get_w)
  167. {
  168. var statetxt = page_get_w.querySelector(".page-get-" + rowObj.name);
  169. statetxt.classList.add("page-load");
  170. statetxt.innerHTML = "页面获取错误";
  171. }
  172. rowsCurrent++;
  173. },
  174. });
  175. }
  176. var tagObj = function(){
  177. this.type = 0;
  178. this.name = "";
  179. this.cname = [];
  180. this.info = [];
  181. this.links = [];
  182. }
  183. //一条新的外部链接
  184. var linkObj = function(text,href,title){
  185. this.text = text||"";
  186. this.href = href||"";
  187. this.title = title||"";
  188. }
  189.  
  190.  
  191. //处理版本的页面
  192. function dealVersion(response)
  193. {
  194. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  195. var wiki_version_Dom;
  196. if (newRe)
  197. { //新仓库的结构版本
  198. wiki_version_Dom = PageDOM.querySelector("#LC1");
  199. }else
  200. { //wiki的结构版本
  201. wiki_version_Dom = PageDOM.querySelector("a[title='database-structure-version']");
  202. }
  203.  
  204. if (!wiki_version_Dom)
  205. {
  206. alert("未找到数据库结构版本,你的 " + scriptName + " 版本可能已经不适用新的数据库,请更新你的脚本。");
  207. return;
  208. }
  209. var wiki_version = Number(wiki_version_Dom.textContent.replace(/\D/ig,""));
  210.  
  211. var page_get_w = document.querySelector("#ETB_page-get");
  212. if (page_get_w)
  213. {
  214. var statetxt = page_get_w.querySelector(".page-get-wiki-version");
  215. statetxt.classList.add("page-load");
  216. statetxt.innerHTML = (newRe?"ETT组织仓库":"传统Wiki仓库")+"最新版本" + wiki_version + ",当前" + database_structure_version;
  217. }
  218. if (wiki_version > database_structure_version)
  219. {
  220. alert("Wiki数据库结构已更新,你的 " + scriptName + " 版本可能已经不适用新的数据库,请更新你的脚本。");
  221. return;
  222. }
  223. }
  224. //处理行的页面
  225. function dealRows(response, dataset)
  226. {
  227. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  228. var page_get_w = document.querySelector("#ETB_page-get");
  229. if (page_get_w)
  230. {
  231. var statetxt = page_get_w.querySelector(".page-get-rows");
  232. statetxt.classList.add("page-load");
  233. statetxt.innerHTML = "获取成功";
  234. }
  235.  
  236. var table = PageDOM.querySelector(newRe?"#readme .markdown-body table:nth-of-type(2)":"#wiki-body .markdown-body table").tBodies[0];
  237. rowsCount = table.rows.length;
  238. for(var ri=0, rilen=table.rows.length; ri<rilen; ri++)
  239. {
  240. var trow = table.rows[ri];
  241. var row = new rowObj;
  242. row.name = trow.cells[0].textContent.replace(/(^\s|\s$)/ig,""); //去除首尾空格;
  243. row.cname = InfoToArray(trow.cells[1]);
  244. row.info = InfoToArray(trow.cells[2]);
  245. row.links = LinksToArray(trow.cells[3]);
  246. row.addTagFromName();
  247. dataset.push(row);
  248. if (page_get_w)
  249. {
  250. page_get_w.querySelector(".select-menu-list").appendChild(
  251. buildMenuItem((function()
  252. {
  253. var div = document.createElement("div");
  254. var span1 = document.createElement("span");
  255. span1.className = "page-title";
  256. span1.innerHTML = row.cname
  257. .filter(function(item){return item.type==0;})
  258. .map(function(item){return item.text;})
  259. .join("");
  260. div.appendChild(span1);
  261. var span2 = document.createElement("span");
  262. span2.className = "page-get-" + row.name;
  263. span2.innerHTML = "等待";
  264. div.appendChild(span2);
  265. return div;
  266. })()
  267. )
  268. );
  269. }
  270. }
  271. }
  272.  
  273. //生成按钮
  274. function specialCharToCss(str)
  275. {
  276. var strn = str;
  277. strn = strn.replace("\\","\\\\");
  278. strn = strn.replace("\"","\\\"");
  279. strn = strn.replace("\r","");
  280. strn = strn.replace("\n","\\A");
  281. return strn;
  282. }
  283.  
  284. //将外部链接变换为数组
  285. function LinksToArray(linksDom)
  286. {
  287. var arr = [];
  288. var as = linksDom.querySelectorAll("a");
  289. for (var ai=0;ai<as.length;ai++)
  290. {
  291. var a = as[ai];
  292. arr.push(new linkObj(a.textContent,a.href,a.title));
  293. }
  294. return arr;
  295. }
  296. //介绍信息转为数组
  297. function InfoToArray(infoDom)
  298. {
  299. var arr = [];
  300. if (infoDom.childNodes != undefined)
  301. {
  302. for (var ci=0, cilen=infoDom.childNodes.length; ci<cilen; ci++)
  303. {
  304. var node = infoDom.childNodes[ci];
  305. //type,0是文字,1是换行,2是图片,3是链接
  306. var InfoObj = {type:0};
  307. switch (node.nodeName) {
  308. case "#text":case "G-EMOJI":
  309. InfoObj.type = 0;
  310. if (node.textContent == "\n")
  311. continue;
  312. InfoObj.text = node.textContent;
  313. break;
  314. case "BR":
  315. InfoObj.type = 1;
  316. break;
  317. case "IMG":
  318. InfoObj.type = 2;
  319. var osrc = node.getAttribute("data-canonical-src");
  320. if (osrc) //链接写在data-canonical-src
  321. {
  322. InfoObj.src = osrc;
  323. }else if(node.title.length > 0) //链接写在title
  324. {
  325. InfoObj.src = node.title;
  326. }else if(node.src.length > 0) //链接写在src
  327. {
  328. InfoObj.src = node.src;
  329. }else
  330. {
  331. console.error("发现未知的其他图片地址格式",node,"来自",infoDom);
  332. }
  333. InfoObj.alt = node.alt;
  334. break;
  335. case "A":
  336. InfoObj.type = 3;
  337. InfoObj.text = node.textContent;
  338. InfoObj.href = node.href;
  339. InfoObj.title = node.title;
  340. break;
  341. default: //未知的其他格式
  342. console.error("发现未知的其他Node格式:" + node.nodeName,node,"来自",infoDom);
  343. InfoObj.type = 0;
  344. InfoObj.text = node.textContent;
  345. continue;
  346. }
  347. arr.push(InfoObj);
  348. }
  349. }
  350. return arr;
  351. }
  352. //介绍信息数组输出到CSS
  353. function InfoArrayToCssString(infoArr, creatImage)
  354. {
  355. if (creatImage == undefined) creatImage = true;
  356. var infoArrTmp = infoArr.concat(); //创建编辑用临时数组
  357. var str = []; //最终输出的内容字符串的部件数组
  358. var lastText = false; //上一条是不是文字,用渝判断下一条是储存到临时数组等候拼接还是将前方的加入最终字符串
  359. var strPart = []; //当前的临时字符串(储存多块相邻文本,用于拼接)
  360. while (infoArrTmp.length>0)
  361. {
  362. var inf = infoArrTmp.shift();
  363. if (inf.type == 0 || inf.type == 1 || inf.type == 3) //type,0是文字,1是换行,2是图片,3是链接
  364. { //处理文本
  365. if (lastText) //如果上一条不是文本
  366. { //添加一条新的文本,或者换行
  367. strPart.push(inf.text || "\\A");
  368. }else
  369. { //处理每一张图片
  370. str.push(strPart.map(function(item){return 'url("' + item + '")'}).join("")); //已储存的图片添加到最终字符串
  371. strPart = [];
  372. lastText = true;
  373. strPart.push(inf.text || "\\A");
  374. }
  375. }else if (creatImage) //如果同意生成图片,才处理图片
  376. { //处理图片
  377. if (lastText)
  378. { //处理每一条文本
  379. var txtTmp = strPart.join("");
  380. txtTmp = txtTmp.replace(/\"/igm,"\\\""); //将引号改为斜杠引号
  381. if (!creatImage) txtTmp = dealEmoji(txtTmp); //去除Emoji
  382. str.push('"' + txtTmp + '"');
  383. strPart = [];
  384. lastText = false;
  385. strPart.push(inf.src);
  386. }else
  387. { //添加一张新的图片
  388. strPart.push(inf.src);
  389. }
  390. }
  391. }
  392. //最后没被处理掉的
  393. if (lastText)
  394. { //处理每一条文本
  395. var txtTmp = strPart.join("");
  396. txtTmp = txtTmp.replace(/\"/igm,"\\\""); //将引号改为斜杠引号
  397. if (!creatImage) txtTmp = dealEmoji(txtTmp); //去除Emoji
  398. str.push('"' + txtTmp + '"');
  399. strPart = [];
  400. lastText = false;
  401. }else
  402. { //处理每一张图片
  403. str.push(strPart.map(function(item){return 'url("' + item + '")'}).join(""));
  404. strPart = [];
  405. lastText = true;
  406. }
  407. return str.join("");
  408. }
  409.  
  410. //处理Tag页面
  411. function dealTags(response, rowdataset)
  412. {
  413. var rowTags = rowdataset.tags;
  414. var PageDOM = new DOMParser().parseFromString(response, "text/html");
  415.  
  416. var table = PageDOM.querySelector(newRe?"#readme .markdown-body table:nth-of-type(2)":"#wiki-body .markdown-body table");
  417. if (table == undefined)
  418. {
  419. alert(PageDOM.title + "\n该页面未发现数据表格,可能存在格式错误。")
  420. console.error("未发现表格",PageDOM.title);
  421. }
  422. var tBody = table.tBodies[0];
  423. for(var ri=0, rilen=tBody.rows.length; ri<rilen; ri++)
  424. {
  425. var trow = tBody.rows[ri];
  426. var tag = new tagObj;
  427. if (trow.cells.length > 2)
  428. {//没有足够单元格的跳过
  429. tag.name = trow.cells[0].textContent.replace(/(^\s|\s$)/ig,""); //去除首尾空格
  430. tag.cname = InfoToArray(trow.cells[1]);
  431. tag.info = InfoToArray(trow.cells[2]);
  432. tag.links = LinksToArray(trow.cells[3]);
  433. //type=0代表一行翻译,1代表注释
  434. tag.type = tag.name.replace(/\s/ig,"").length < 1 ? 1 : 0; //英文去除所有空格后如果没有文字,则算为注释
  435. if (tag.type != 1 && tag.cname.length < 1) //不是注释,中文名又没有文字
  436. {
  437. //console.error("发现无中文翻译行%d - %s:%s",ri,rowdataset.name,tag.name);
  438. }
  439. if (tag.type != 1 && rowTags.some(function(ttag){return ttag.name == tag.name;})) //从数组中搜索任一符合条件的,返回true
  440. {
  441. console.error("发现重复定义行%d - %s:%s",ri,rowdataset.name,tag.name);
  442. }
  443. rowTags.push(tag);
  444. }
  445. else
  446. {
  447. console.error("发现无3单元格的错误行%d %s",ri,tag.name);
  448. }
  449. }
  450. rowsCurrent++;
  451. }
  452.  
  453. //点击开始任务按钮
  454. function startProgram(dataset, mode){
  455. var downOver = startProgramCheck(dataset, mode);
  456. if (!downOver || downOverCheckHook == undefined)
  457. {
  458. GM_xmlhttpRequest({
  459. method: "GET",
  460. url: wiki_URL + "/" + wiki_version_filename,
  461. onload: function(response) {
  462. dealVersion(response.responseText);
  463. GM_xmlhttpRequest({
  464. method: "GET",
  465. url: wiki_URL + "/" + rows_filename,
  466. onload: function(response) {
  467. dealRows(response.responseText,dataset);
  468. }
  469. });
  470. },
  471. onerror: function(response) {
  472. dealVersion("");
  473. GM_xmlhttpRequest({
  474. method: "GET",
  475. url: wiki_URL + "/" + rows_filename,
  476. onload: function(response) {
  477. dealRows(response.responseText,dataset);
  478. }
  479. });
  480. },
  481. });
  482. downOverCheckHook = setInterval(function () { startProgramCheck(dataset, mode) }, 200);
  483. }
  484. if (!downOver)
  485. {
  486. buildDownloadProgress();
  487. }
  488. }
  489.  
  490. //创建下载进度窗口
  491. function buildDownloadProgress()
  492. {
  493. var page_get_w = document.querySelector("#ETB_page-get");
  494. if (!page_get_w)
  495. {
  496. windowInserPlace.appendChild(buildMenuModal("window", "ETB_page-get", "数据获取进度", null, [
  497. buildMenuList([
  498. buildMenuItem((function()
  499. {
  500. var div = document.createElement("div");
  501. var span1 = document.createElement("span");
  502. span1.className = "page-title";
  503. span1.innerHTML = "Wiki结构版本";
  504. div.appendChild(span1);
  505. var span2 = document.createElement("span");
  506. span2.className = "page-get-wiki-version";
  507. span2.innerHTML = "等待";
  508. div.appendChild(span2);
  509. return div;
  510. })()
  511. ),
  512. buildMenuItem((function()
  513. {
  514. var div = document.createElement("div");
  515. var span1 = document.createElement("span");
  516. span1.className = "page-title";
  517. span1.innerHTML = "列表页面";
  518. div.appendChild(span1);
  519. var span2 = document.createElement("span");
  520. span2.className = "page-get-rows";
  521. span2.innerHTML = "等待";
  522. div.appendChild(span2);
  523. return div;
  524. })()
  525. ),
  526. ])
  527. ],
  528. [
  529. ".ETB_page-get .page-title" + "{\r\n" + [
  530. 'font-weight: bold',
  531. 'margin-right: 15px',
  532. ].join(';\r\n') + "\r\n}",
  533. ".ETB_page-get .page-load" + "{\r\n" + [
  534. 'color: #0A0',
  535. ].join(';\r\n') + "\r\n}",
  536. ].join('\r\n')
  537. ));
  538. }
  539. else
  540. {
  541. page_get_w.style.display = "block";
  542. }
  543. }
  544.  
  545. //检测下载完成情况
  546. function startProgramCheck(dataset, mode)
  547. {
  548. if (rowsCount > 0 && rowsCurrent >= rowsCount)
  549. {
  550. console.debug("获取完成");
  551. clearInterval(downOverCheckHook);
  552. switch (mode) {
  553. case 1:
  554. buildJSOutput(dataset);
  555. break;
  556. case 0:
  557. default:
  558. buildCSSOutput(dataset);
  559. break;
  560. }
  561. var page_get_w = document.querySelector("#ETB_page-get");
  562. if (page_get_w)
  563. {
  564. page_get_w.parentNode.removeChild(page_get_w);
  565. }
  566. return true;
  567. }
  568. else
  569. {
  570. console.debug("获取%d/%d",rowsCurrent, rowsCount);
  571. return false;
  572. }
  573. }
  574.  
  575. //获取完成后创建CSS输出窗口
  576. function buildCSSOutput(dataset)
  577. {
  578. var css = createOutputCSS(dataset
  579. ,GM_getValue("ETB_create-info","boolean")
  580. ,GM_getValue("ETB_create-info-image","boolean")
  581. ,GM_getValue("ETB_create-cname-image","boolean")
  582. );
  583. var downBlob = new Blob([css], {'type': 'text\/css'});
  584. var downurl = window.URL.createObjectURL(downBlob);
  585. var css_output_w = document.querySelector("#ETB_css-output");
  586. if (!css_output_w)
  587. {
  588. windowInserPlace.appendChild(buildMenuModal("window", "ETB_css-output", "用户样式版EhTagTranslator", null,
  589. [
  590. buildMenuList([
  591. buildMenuItem("CSS文本",
  592. (function()
  593. {
  594. var textarea = document.createElement("textarea");
  595. textarea.id = "ETB_css-textarea";
  596. textarea.name = textarea.id;
  597. textarea.className = "txta " + textarea.id;
  598. textarea.value = css;
  599. textarea.wrap = "off";
  600. textarea.setAttribute("readonly",true);
  601. return textarea;
  602. })()
  603. ,buildSVG("css")),
  604. buildMenuItem("直接下载CSS文件",null,buildSVG("download"),downurl,1),
  605. ])
  606. ],
  607. [
  608. ".ETB_css-output .txta" + "{\r\n" + [
  609. 'resize: vertical',
  610. 'width:100%',
  611. 'height:300px',
  612. ].join(';\r\n') + "\r\n}",
  613. ].join('\r\n')
  614. ));
  615. }
  616. else
  617. {
  618. css_output_w.style.display = "block";
  619. css_output_w.querySelector(".ETB_css-textarea").value = css;
  620. css_output_w.querySelector("a").href = downurl;
  621. }
  622. }
  623.  
  624. //开始构建CSS
  625. function createOutputCSS(dataset, createInfo, createInfoImage, createCnameImage)
  626. {
  627. if (createInfo == undefined) createInfo = true;
  628. if (createInfoImage == undefined) createInfoImage = true;
  629. if (createCnameImage == undefined) createCnameImage = true;
  630. var date = new Date();
  631. var cssAry = [];
  632. //样式信息说明
  633. cssAry.push(
  634. "/* EhTagTranslator 用户样式版,由 " + scriptName + " v" + scriptVersion + " 构建"
  635. ," * 数据来源于" + wiki_URL
  636. ," * 构建时间为"
  637. ," * " + date.toString()
  638. ," */"
  639. )
  640. //样式命名区间
  641. cssAry.push(
  642. //▼CSS内容部分
  643. "@namespace url(http://www.w3.org/1999/xhtml);"
  644. //▲CSS内容部分
  645. );
  646.  
  647. //表里通用样式
  648. cssAry.push(""
  649. //▼CSS内容部分
  650. ,"/* 表里通用样式 */"
  651. ,"@-moz-document"
  652. ," domain('exhentai.org'),"
  653. ," domain('e-hentai.org')"
  654. ,"{"
  655. ,GM_getValue("ETB_global-style")
  656. ,"}"
  657. //▲CSS内容部分
  658. );
  659.  
  660. //表站样式
  661. cssAry.push(""
  662. //▼CSS内容部分
  663. ,"/* 表站样式 */"
  664. ,"@-moz-document"
  665. ," domain('e-hentai.org')"
  666. ,"{"
  667. ,GM_getValue("ETB_global-style-eh")
  668. ,"}"
  669. //▲CSS内容部分
  670. );
  671.  
  672. //里站样式
  673. cssAry.push(""
  674. //▼CSS内容部分
  675. ,"/* 里站样式 */"
  676. ,"@-moz-document"
  677. ," domain('exhentai.org')"
  678. ,"{"
  679. ,GM_getValue("ETB_global-style-ex")
  680. ,"}"
  681. //▲CSS内容部分
  682. );
  683.  
  684. //翻译内容
  685. cssAry.push(""
  686. //▼CSS内容部分
  687. ,"/* 翻译内容 */"
  688. ,"@-moz-document"
  689. ," domain('exhentai.org'),"
  690. ," domain('e-hentai.org')"
  691. ,"{"
  692. //▲CSS内容部分
  693. );
  694.  
  695. dataset.forEach(function(row){
  696.  
  697. //添加行名的注释
  698. cssAry.push(""
  699. ,"/* " + row.name
  700. ," * " + row.cname
  701. .filter(function(item){return item.type==0;})
  702. .map(function(item){return item.text;})
  703. .join("")
  704. ," */"
  705. );
  706.  
  707. row.tags.forEach(function(tag){
  708.  
  709. if (tag.type == 0)
  710. {
  711. var tagid = (row.name=="misc"?"":row.name + ":") + tag.name.replace(/\s/ig,"_");
  712. cssAry.push(""
  713. //▼CSS内容部分
  714. ," a[id=\"ta_" + tagid + "\"]{"
  715. ," font-size:0;"
  716. ," }"
  717. ," a[id=\"ta_" + tagid + "\"]::before{"
  718. ," content:" + InfoArrayToCssString(tag.cname, createCnameImage) + ";"
  719. ," }"
  720. //▲CSS内容部分
  721. );
  722. if (createInfo)
  723. {
  724. var sinfo = InfoArrayToCssString(tag.info, createInfoImage);
  725. if (sinfo.replace(/\s/ig,"").length > 0)
  726. {
  727. cssAry.push(""
  728. //▼CSS内容部分
  729. ," a[id=\"ta_" + tagid + "\"]::after{"
  730. ," content:" + sinfo + ";"
  731. ," }"
  732. //▲CSS内容部分
  733. );
  734. }
  735. }
  736. }
  737. else
  738. { //将注释写成CSS注释
  739. cssAry.push(
  740. "/* " + InfoArrayToCssString(tag.cname, false)
  741. ," * " + InfoArrayToCssString(tag.info, false)
  742. ," */"
  743. );
  744. }
  745. })//row.tags.forEach
  746. });//dataset.forEach
  747.  
  748. cssAry.push(
  749. //▼CSS内容部分
  750. "}"
  751. //▲CSS内容部分
  752. );
  753. var css = cssAry.join("\r\n");
  754. return css;
  755. }
  756.  
  757. //获取完成后创建JS输出窗口
  758. function buildJSOutput(dataset)
  759. {
  760. var json = createOutputJSON(dataset
  761. ,GM_getValue("ETB_create-info","boolean")
  762. ,GM_getValue("ETB_create-info-image","boolean")
  763. ,GM_getValue("ETB_create-cname-image","boolean")
  764. );
  765. var jsonStr = JSON.stringify(json);
  766. var downBlob = new Blob([jsonStr], {'type': 'text\/json'});
  767. var downurl = window.URL.createObjectURL(downBlob);
  768. var js_output_w = document.querySelector("#ETB_js-output");
  769. if (!js_output_w)
  770. {
  771. windowInserPlace.appendChild(buildMenuModal("window", "ETB_js-output", "用户脚本版EhTagTranslator数据库", null,
  772. [
  773. buildMenuList([
  774. buildMenuItem("JSON文本",
  775. (function()
  776. {
  777. var textarea = document.createElement("textarea");
  778. textarea.id = "ETB_js-textarea";
  779. textarea.name = textarea.id;
  780. textarea.className = "txta " + textarea.id;
  781. textarea.value = jsonStr;
  782. textarea.setAttribute("readonly",true);
  783. return textarea;
  784. })()
  785. ,buildSVG("json")),
  786. buildMenuItem("数据库数量",
  787. (function()
  788. {
  789. var tb = document.createElement("table");
  790. tb.id = "ETB_database-count";
  791. tb.name = tb.id;
  792. tb.className = tb.id;
  793. //正式开始构建内容
  794. //tHead
  795. tb.createTHead();
  796. var th = tb.tHead.insertRow();
  797. th.insertCell().appendChild(document.createTextNode("行名"));
  798. th.insertCell().appendChild(document.createTextNode("数据行数"));
  799. th.insertCell().appendChild(document.createTextNode("注释行数"));
  800. //tBody
  801. json.dataset.forEach(function(item){
  802. var tr = tb.insertRow();
  803. tr.insertCell().appendChild(document.createTextNode(item.cname
  804. .filter(function(item){return item.type==0;})
  805. .map(function(item){return item.text;})
  806. .join("")));
  807. tr.insertCell().appendChild(document.createTextNode(item.tags.filter(function(item){return item.type==0}).length));
  808. tr.insertCell().appendChild(document.createTextNode(item.tags.filter(function(item){return item.type==1}).length));
  809. })
  810. return tb;
  811. })()
  812. ,buildSVG("book")),
  813. buildMenuItem("直接下载JSON文件",null,buildSVG("download"),downurl,1)
  814. ])
  815. ],
  816. [
  817. ".ETB_js-output .txta" + "{\r\n" + [
  818. 'resize: vertical',
  819. 'width:100%',
  820. 'height:200px',
  821. ].join(';\r\n') + "\r\n}",
  822. "#ETB_js-output .select-menu-list" + "{\r\n" + [
  823. 'max-height: 700px',
  824. ].join(';\r\n') + "\r\n}",
  825. "#ETB_database-count,#ETB_database-count td" + "{\r\n" + [
  826. 'border: solid 1px lightgrey;',
  827. ].join(';\r\n') + "\r\n}",
  828. ].join('\r\n')
  829. ));
  830. }
  831. else
  832. {
  833. js_output_w.style.display = "block";
  834. js_output_w.querySelector(".ETB_js-textarea").value = jsonStr;
  835. js_output_w.querySelector("a").href = downurl;
  836. }
  837. }
  838.  
  839. //开始构建JSON
  840. function createOutputJSON(dataset, createInfo, createInfoImage, createCnameImage)
  841. {
  842. if (createInfo == undefined) createInfo = true;
  843. if (createInfoImage == undefined) createInfoImage = true;
  844. if (createCnameImage == undefined) createCnameImage = true;
  845.  
  846. var outArray =
  847. /*
  848. * 生成一个不会干涉到原对象的Row对象
  849. */
  850. dataset.map(function(row_orignal){
  851. var row = Object.assign(new rowObj(), row_orignal);
  852. row.cname=row_orignal.cname
  853. .filter(function(item){return createCnameImage || item.type != 2;})
  854. .map(function(item){
  855. var newItem = Object.assign({}, item);
  856. if(!createCnameImage && item.text) {
  857. newItem.text = dealEmoji(item.text);
  858. }
  859. return newItem;
  860. });
  861. if (createInfo)
  862. {
  863. row.info=row_orignal.info
  864. .filter(function(item){return createInfoImage || item.type != 2;})
  865. .map(function(item){
  866. var newItem = Object.assign({}, item);
  867. if(!createInfoImage && item.text) {
  868. newItem.text = dealEmoji(item.text);
  869. }
  870. return newItem;
  871. });
  872. }
  873. else
  874. {
  875. row.info = null;
  876. }
  877. row.links=row_orignal.links
  878. .map(function(item){
  879. var newItem = Object.assign(new linkObj(), item);
  880. return newItem;
  881. });
  882.  
  883. row.tags =
  884. /*
  885. * 生成一个不会干涉到原对象的Tag对象
  886. */
  887. row_orignal.tags.map(function(tag_orignal){
  888. var tag = Object.assign(new tagObj(), tag_orignal);
  889. tag.cname=tag_orignal.cname
  890. .filter(function(item){return createCnameImage || item.type != 2;})
  891. .map(function(item){
  892. var newItem = Object.assign({}, item);
  893. if(!createCnameImage && item.text) {
  894. newItem.text = dealEmoji(item.text);
  895. }
  896. return newItem;
  897. });
  898. tag.links=tag_orignal.links
  899. .map(function(item){
  900. var newItem = Object.assign(new linkObj(), item);
  901. return newItem;
  902. });
  903.  
  904. if (createInfo || tag.type==1)
  905. {
  906. tag.info=tag_orignal.info
  907. .filter(function(item){return createInfoImage || item.type != 2;})
  908. .map(function(item){
  909. var newItem = Object.assign({}, item);
  910. if(!createInfoImage && item.text) {
  911. newItem.text = dealEmoji(item.text);
  912. }
  913. return newItem;
  914. });
  915. }
  916. else
  917. {
  918. tag.info = null;
  919. }
  920. return tag;
  921. })//row.tags.forEach
  922.  
  923. return row;
  924. });//dataset.forEach
  925.  
  926. var date = new Date();
  927. var outJson =
  928. {
  929. "scriptName":scriptName,
  930. "scriptVersion":scriptVersion,
  931. "database-structure-version":database_structure_version,
  932. "date":date.getTime(),
  933. "dataset":outArray
  934. }
  935. return outJson;
  936. }
  937.  
  938. //去除文本中的Emoji字符
  939. function dealEmoji(str)
  940. {
  941. return str.replace(emojireg,"");
  942. }
  943.  
  944. //生成按钮
  945. function buildButton(title, icon, modal)
  946. {
  947. var li = document.createElement("li");
  948. var select_menu = document.createElement("div");
  949. select_menu.className = "select-menu js-menu-container js-select-menu";
  950. li.appendChild(select_menu);
  951. var button = document.createElement("button");
  952. button.className = "btn btn-sm select-menu-button js-menu-target css-truncate";
  953. button.onclick = function(){
  954. modal.style.display = "block";
  955. }
  956. select_menu.appendChild(button);
  957. var span = document.createElement("span");
  958. span.className = "js-select-button";
  959. if (icon != undefined)
  960. span.appendChild(icon);
  961. span.innerHTML += title;
  962. button.appendChild(span);
  963. select_menu.appendChild(modal);
  964. button.onclick = function(){
  965. modal.style.display = "block";
  966. }
  967. return li;
  968. }
  969.  
  970. //生成菜单窗口
  971. function buildMenuModal(mode, id, stitle, filters, lists, sstyle)
  972. {
  973. var modal_holder = document.createElement("div");
  974. modal_holder.className = "select-menu-modal-holder js-menu-content js-navigation-container js-active-navigation-container";
  975. if (id != undefined)
  976. {
  977. modal_holder.id = id;
  978. modal_holder.classList.add(id);
  979. }
  980. if (sstyle != undefined)
  981. {
  982. var style = document.createElement("style");
  983. style.innerHTML = sstyle;
  984. modal_holder.appendChild(style);
  985. }
  986.  
  987. var modal = document.createElement("div");
  988. modal.className = "select-menu-modal subscription-menu-modal js-menu-content";
  989. modal_holder.appendChild(modal);
  990. var header = document.createElement("div");
  991. header.className = "select-menu-header js-navigation-enable";
  992. modal.appendChild(header);
  993. var CloseSvg = buildSVG("Close");
  994. header.appendChild(CloseSvg);
  995. CloseSvg.onclick = function(){
  996. modal_holder.style.display = "none";
  997. }
  998.  
  999. switch (mode) {
  1000. case "window":
  1001. modal_holder.style.display = "block";
  1002. }
  1003. var title = document.createElement("span");
  1004. title.className = "select-menu-title";
  1005. title.innerHTML = stitle;
  1006. header.appendChild(title);
  1007.  
  1008. if (lists != undefined)
  1009. {
  1010. for(var li = 0, lilen=lists.length; li<lilen; li++)
  1011. {
  1012. var list = lists[li];
  1013. if (list)
  1014. modal.appendChild(list);
  1015. }
  1016. }
  1017. return modal_holder;
  1018. }
  1019.  
  1020. //构建一个菜单列表框架
  1021. function buildMenuList(items)
  1022. {
  1023. var list = document.createElement("div");
  1024. list.className = "select-menu-list js-navigation-container";
  1025. if (items != undefined)
  1026. {
  1027. for(var ii=0, lilen=items.length; ii<lilen; ii++)
  1028. {
  1029. var item = items[ii];
  1030. if (item)
  1031. list.appendChild(item);
  1032. }
  1033. }
  1034. return list;
  1035. }
  1036.  
  1037. //构建一个菜单列表项
  1038. function buildMenuItem(heading, description, icon, callback, type)
  1039. {
  1040. if (heading == undefined) heading = "未设定";
  1041. var item = document.createElement("div");
  1042. if (type == 3)
  1043. {
  1044. var item = document.createElement("label");
  1045. item.setAttribute('for', callback);
  1046. }
  1047. else if (typeof(callback) == "string")
  1048. {
  1049. var item = document.createElement("a");
  1050. item.target = "_blank";
  1051. item.href = callback;
  1052. }
  1053. else
  1054. {
  1055. if (callback) item.onclick = callback;
  1056. }
  1057. item.className = "select-menu-item";
  1058. switch (type) {
  1059. case 0:
  1060. item.classList.add("js-navigation-item");
  1061. break;
  1062. case 1:
  1063. item.classList.add("select-menu-action");
  1064. break;
  1065. default:
  1066. break;
  1067. }
  1068. if (icon != undefined) item.appendChild(icon);
  1069. var item_text = document.createElement("div");
  1070. item_text.className = "select-menu-item-text";
  1071. item.appendChild(item_text);
  1072. if (description != undefined)
  1073. {
  1074. var item_heading = document.createElement("span");
  1075. item_heading.className = "select-menu-item-heading";
  1076. if (typeof(heading)=="string")
  1077. item_heading.innerHTML = heading;
  1078. else
  1079. item_heading.appendChild(heading);
  1080. var item_description = document.createElement("span");
  1081. item_description.className = "description";
  1082. if (typeof(description)=="string")
  1083. item_description.innerHTML = description;
  1084. else
  1085. item_description.appendChild(description);
  1086. item_text.appendChild(item_heading);
  1087. item_text.appendChild(item_description);
  1088. }
  1089. else
  1090. {
  1091. if (typeof(heading)=="string")
  1092. item_text.innerHTML = heading;
  1093. else
  1094. item_text.appendChild(heading);
  1095. }
  1096. return item;
  1097. }
  1098. //生成svg
  1099. function buildSVG(mode,check)
  1100. {
  1101. if (check == undefined) check = false;
  1102. var CloseSvgDiv = document.createElement("div");
  1103. var innerHTML = "";
  1104. switch (mode) {
  1105. case "Close":
  1106. 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>';
  1107. break;
  1108.  
  1109. case "Settings":
  1110. 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>';
  1111. break;
  1112.  
  1113. case "check":
  1114. 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>';
  1115. break;
  1116.  
  1117. case "question":
  1118. 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>';
  1119. break;
  1120.  
  1121. case "download":
  1122. 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>';
  1123. break;
  1124.  
  1125. case "book":
  1126. 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>';
  1127. break;
  1128. case "code":
  1129. 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>'
  1130. break;
  1131. case "css":
  1132. 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>';
  1133. break;
  1134.  
  1135. case "json":
  1136. 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>';
  1137. break;
  1138.  
  1139. case "eh":
  1140. 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>';
  1141. break;
  1142. default:
  1143. 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>';
  1144. break;
  1145. }
  1146. CloseSvgDiv.innerHTML = innerHTML;
  1147. var CloseSvg = CloseSvgDiv.firstChild;
  1148. if(check)
  1149. CloseSvg.classList.add("octicon-check");
  1150. else
  1151. CloseSvg.classList.remove("octicon-check");
  1152. //更改SVG的渐变ID名
  1153. function changeSvgIdName(svg)
  1154. {
  1155. var linearGradient = svg.getElementsByTagName("linearGradient");
  1156. for (var lGi=0, lGilen=linearGradient.length;lGi<lGilen;lGi++)
  1157. {
  1158. var idName = linearGradient[lGi].id;
  1159. var idIndex = 0;
  1160. while(document.querySelector("#" + idName + "_" + idIndex.toString()))
  1161. {
  1162. idIndex++;
  1163. }
  1164. linearGradient[lGi].id = idName + "_" + idIndex.toString();
  1165. var idReg = new RegExp("#" + idName + "", "igm"); //P站图片地址正则匹配式
  1166. svg.innerHTML = svg.innerHTML.replace(idReg,"#" + idName + "_" + idIndex.toString());
  1167. }
  1168. return svg;
  1169. }
  1170. CloseSvg = changeSvgIdName(CloseSvg);
  1171.  
  1172. return CloseSvg;
  1173. }
  1174. //打开设置窗口
  1175. function startOption()
  1176. {
  1177. var option_modal_w = document.querySelector("#ETB_option");
  1178. if (!option_modal_w)
  1179. {
  1180. windowInserPlace.appendChild(
  1181. buildMenuModal("window", "ETB_option", scriptName + " 设置", null, [
  1182. buildMenuList([
  1183. buildMenuItem("生成简介","生成光标移动到Tag上时出现的简介。",
  1184. (function(){
  1185. var chk = document.createElement("input");
  1186. chk.type = "checkbox";
  1187. chk.id = "ETB_create-info";
  1188. chk.name = chk.id;
  1189. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1190. return chk;
  1191. })()
  1192. ,"ETB_create-info",3),
  1193. buildMenuItem("生成简介图片和Emoji","生成简介中的图片和绘文字。",
  1194. (function(){
  1195. var chk = document.createElement("input");
  1196. chk.type = "checkbox";
  1197. chk.id = "ETB_create-info-image";
  1198. chk.name = chk.id;
  1199. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1200. return chk;
  1201. })()
  1202. ,"ETB_create-info-image",3),
  1203. buildMenuItem("生成中文名图片和Emoji","生成中文名中的图片和绘文字,一般为名称前的小图标。",
  1204. (function(){
  1205. var chk = document.createElement("input");
  1206. chk.type = "checkbox";
  1207. chk.id = "ETB_create-cname-image";
  1208. chk.name = chk.id;
  1209. chk.className = "octicon octicon-question select-menu-item-icon " + chk.id;
  1210. return chk;
  1211. })()
  1212. ,"ETB_create-cname-image",3),
  1213. buildMenuItem("Tag通用样式",
  1214. (function(){
  1215. var div = document.createElement("div");
  1216. var span1 = document.createElement("div");
  1217. span1.innerHTML = "Tag统一应用的样式,可修改为自己喜爱的样式。";
  1218. div.appendChild(span1);
  1219. //表里共用
  1220. var textarea = document.createElement("textarea");
  1221. textarea.id = "ETB_global-style";
  1222. textarea.name = textarea.id;
  1223. textarea.className = "txta " + textarea.id;
  1224. textarea.wrap = "off";
  1225. var label = document.createElement("label");
  1226. label.setAttribute('for', textarea.id);
  1227. label.innerHTML = "表里共用样式";
  1228. div.appendChild(label);
  1229. div.appendChild(textarea);
  1230. //表站
  1231. var textarea = document.createElement("textarea");
  1232. textarea.id = "ETB_global-style-eh";
  1233. textarea.name = textarea.id;
  1234. textarea.className = "txta " + textarea.id;
  1235. textarea.wrap = "off";
  1236. var label = document.createElement("label");
  1237. label.setAttribute('for', textarea.id);
  1238. label.innerHTML = "表站样式";
  1239. div.appendChild(label);
  1240. div.appendChild(textarea);
  1241. //里站
  1242. var textarea = document.createElement("textarea");
  1243. textarea.id = "ETB_global-style-ex";
  1244. textarea.name = textarea.id;
  1245. textarea.className = "txta " + textarea.id;
  1246. textarea.wrap = "off";
  1247. var label = document.createElement("label");
  1248. label.setAttribute('for', textarea.id);
  1249. label.innerHTML = "里站样式";
  1250. div.appendChild(label);
  1251. div.appendChild(textarea);
  1252. return div;
  1253. })()
  1254. ,buildSVG("css")),
  1255. ]),
  1256. buildMenuList([
  1257. buildMenuItem("其他用户分享的通用样式",null,buildSVG("code"),"https://github.com/Mapaler/EhTagTranslator/labels/%E6%A0%B7%E5%BC%8F%E5%88%86%E4%BA%AB",1),
  1258. buildMenuItem(
  1259. (function(){
  1260. var div = document.createElement("div");
  1261. var btn = document.createElement("button");
  1262. btn.innerHTML = "重置";
  1263. btn.id = "ETB_reset-option";
  1264. btn.name = btn.id;
  1265. btn.className = "btn btn-sm btn-danger " + btn.id;
  1266. btn.onclick = function(){
  1267. resetOption();
  1268. }
  1269. div.appendChild(btn);
  1270. /*
  1271. var btn2 = document.createElement("button");
  1272. btn2.innerHTML = "取消";
  1273. btn2.className = "btn btn-sm";
  1274. div.appendChild(btn2);
  1275. */
  1276. var btn = document.createElement("button");
  1277. btn.innerHTML = "保存";
  1278. btn.id = "ETB_save-option";
  1279. btn.name = btn.id;
  1280. btn.className = "btn btn-sm btn-primary " + btn.id;
  1281. btn.onclick = function(){
  1282. saveOption();
  1283. }
  1284. div.appendChild(btn);
  1285. return div;
  1286. })()
  1287. ,null,null,null,1),
  1288. ]),
  1289. ],
  1290. [
  1291. ".ETB_option .select-menu-item-text" + "{\r\n" + [
  1292. 'font-weight: normal',
  1293. ].join(';\r\n') + "\r\n}",
  1294. ".ETB_option .txta" + "{\r\n" + [
  1295. 'resize: vertical',
  1296. 'width: 100%',
  1297. 'height: 100px',
  1298. ].join(';\r\n') + "\r\n}",
  1299. ".ETB_option .ETB_save-option" + "{\r\n" + [
  1300. 'float: right',
  1301. ].join(';\r\n') + "\r\n}",
  1302. ].join('\r\n')
  1303. )
  1304. );
  1305. }
  1306. else
  1307. {
  1308. option_modal_w.style.display = "block";
  1309. }
  1310. }
  1311. //重置设置
  1312. function resetOption(part)
  1313. {
  1314. function partReset(name,value,ispart)
  1315. {
  1316. if (!ispart || ispart && GM_getValue(name) == undefined)
  1317. GM_setValue(name, value);
  1318. }
  1319. var cssAry = [];
  1320. var cssAry_eh = [];
  1321. var cssAry_ex = [];
  1322. cssAry.push(
  1323. //▼CSS内容部分
  1324. " #taglist a{"
  1325. ," background:inherit;"
  1326. ," border-color: inherit;"
  1327. ," }"
  1328. ," #taglist a::before{"
  1329. ," font-size:12px;"
  1330. ," }"
  1331. ," #taglist a::after{"
  1332. ," background: inherit;"
  1333. ," border-style: solid;"
  1334. ," border-width: 1px;"
  1335. ," border-color: inherit;"
  1336. ," border-radius:5px;"
  1337. ," font-size:12pt;"
  1338. ," float:left;"
  1339. ," position:fixed;"
  1340. ," z-index:999;"
  1341. ," padding:2px;"
  1342. ," box-shadow: 3px 3px 5px #888;"
  1343. ," min-width:150px;"
  1344. ," max-width:300px;"
  1345. ," white-space:pre-wrap;"
  1346. ," opacity: 0;"
  1347. ," transition: opacity 0.2s;"
  1348. ," transform: translate(30px,25px);"
  1349. ," top:0px;"
  1350. ," pointer-events:none;"
  1351. ," }"
  1352. ," #taglist a:hover::after,#taglist a:focus::after{"
  1353. ," opacity: 1;"
  1354. ," transition: opacity 0.5s;"
  1355. ," }"
  1356. //▲CSS内容部分
  1357. );
  1358. cssAry_eh.push(
  1359. //▼CSS内容部分
  1360. " #taglist a::after{"
  1361. ," color:#5c0d11;"
  1362. ," }"
  1363. //▲CSS内容部分
  1364. );
  1365. cssAry_ex.push(
  1366. //▼CSS内容部分
  1367. " #taglist a::after{"
  1368. ," color:#dddddd;"
  1369. ," }"
  1370. //▲CSS内容部分
  1371. );
  1372. partReset("ETB_option-version",optionVersion,part);
  1373. partReset("ETB_create-info","true",part);
  1374. partReset("ETB_create-info-image","true",part);
  1375. partReset("ETB_create-cname-image","true",part);
  1376. partReset("ETB_global-style",cssAry.join("\r\n"),part);
  1377. partReset("ETB_global-style-eh",cssAry_eh.join("\r\n"),part);
  1378. partReset("ETB_global-style-ex",cssAry_ex.join("\r\n"),part);
  1379. reloadOption();
  1380. }
  1381. //访问设置用递归函数
  1382. function visitChildNodes(dom, callback)
  1383. {
  1384. callback(dom);
  1385. for (var ci=0, cilen=dom.childNodes.length; ci<cilen; ci++)
  1386. {
  1387. visitChildNodes(dom.childNodes[ci], callback);
  1388. }
  1389. }
  1390. //保存设置
  1391. function saveOption()
  1392. {
  1393. var option_modal_w = document.querySelector("#ETB_option");
  1394. if (option_modal_w)
  1395. {
  1396. visitChildNodes(option_modal_w,setValue);
  1397. }
  1398. function setValue(dom)
  1399. {
  1400. if (dom.name && dom.value != undefined)
  1401. {
  1402. if (dom.type == "checkbox")
  1403. GM_setValue(dom.name, dom.checked);
  1404. else
  1405. GM_setValue(dom.name, dom.value);
  1406. }
  1407. }
  1408. option_modal_w.style.display = "none";
  1409. }
  1410. //重新加载设置窗口
  1411. function reloadOption()
  1412. {
  1413. var option_modal_w = document.querySelector("#ETB_option");
  1414. if (option_modal_w)
  1415. {
  1416. visitChildNodes(option_modal_w, getValue);
  1417. }
  1418. function getValue(dom)
  1419. {
  1420. if (dom.name && dom.value != undefined)
  1421. {
  1422. var value = GM_getValue(dom.name);
  1423. if (value != undefined)
  1424. {
  1425. if (dom.type != undefined && dom.type == "checkbox")
  1426. dom.checked = value;
  1427. else
  1428. dom.value = value;
  1429. }
  1430. }
  1431. }
  1432. }
  1433.  
  1434.  
  1435. /*
  1436. * 开始实际执行的程序
  1437. */
  1438.  
  1439. if (!GM_getValue("ETB_option-version"))
  1440. {
  1441. resetOption(false); //新用户重置设置
  1442. }
  1443. else if (GM_getValue("ETB_option-version", "number") < optionVersion)
  1444. { //老用户提醒更改设置
  1445. alert(scriptName + " 本次程序版本更新改变了设置结构,建议先重置设置,否则可能会导致无法正常使用。");
  1446. resetOption(true);
  1447. }
  1448.  
  1449. var menu_modal = buildMenuModal("menu", null, "请选择任务 v" + scriptVersion, null, [
  1450. buildMenuList([
  1451. buildMenuItem("生成CSS","生成用户样式版EhTagTranslator,请使用Stylus扩展安装。安卓火狐也可使用。",buildSVG("css"),function(){
  1452. startProgram(ds,0);
  1453. }
  1454. ,0),
  1455. buildMenuItem("生成JSON","为第三方程序生成EhTagTranslator数据库。",buildSVG("json"),function(){
  1456. startProgram(ds,1);
  1457. }
  1458. ,0)
  1459. ]),
  1460. buildMenuList([
  1461. buildMenuItem("选项",null,buildSVG("Settings"),function(){startOption();reloadOption();},1),
  1462. //buildMenuItem("查看使用帮助",null,buildSVG("question"),"https://github.com/Mapaler/EhTagTranslator/blob/master/README.md",1),
  1463. buildMenuItem("参与补全翻译",null,buildSVG("book"),"https://github.com/Mapaler/EhTagTranslator/wiki",1),
  1464. ])
  1465. ]);
  1466. buttonInserPlace.insertBefore(buildButton(" " + scriptName + " ", buildSVG("eh"), menu_modal),buttonInserPlace.querySelector("li"));
  1467. })();