EhTagBuilder

Build EhTagTranslater from Wiki.

Stan na 22-01-2019. Zobacz najnowsza wersja.

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