Block_Obj

屏蔽内容对象库

当前为 2021-08-19 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/407543/961909/Block_Obj.js

  1. // ==UserScript==
  2. // @name Block_Obj
  3. // @namespace https://greasyfork.org/zh-CN/users/193133-pana
  4. // @homepage https://greasyfork.org/zh-CN/users/193133-pana
  5. // @version 3.0.1
  6. // @description 屏蔽内容对象库
  7. // @author pana
  8. // @license GNU General Public License v3.0 or later
  9. // ==/UserScript==
  10.  
  11. const BLOCK_STYLE = `
  12. .block_obj_wrap_div {
  13. background-color: #222222;
  14. border-radius: 3px;
  15. border: 1px solid #282A36;
  16. bottom: 6vh;
  17. box-shadow: 0 0 5px #282A36;
  18. color: #D3D3D3;
  19. font-size: 13px;
  20. margin: 0px;
  21. padding: 0px;
  22. position: fixed;
  23. text-align: left;
  24. transition: 0.8s;
  25. width: 520px;
  26. z-index: 99999;
  27. }
  28. .block_obj_show_wrap {
  29. display: block;
  30. right: 0;
  31. }
  32. .block_obj_hidden_wrap {
  33. right: -530px;
  34. }
  35. .block_obj_main_fieldset {
  36. border-radius: 3px;
  37. border: 3px groove #00A1D6;
  38. height: auto;
  39. margin: 8px;
  40. min-width: 300px;
  41. padding: 4px 9px 6px 9px;
  42. width: auto;
  43. }
  44. .block_obj_ul_node {
  45. list-style: none;
  46. padding-left: 0;
  47. margin: 0;
  48. }
  49. .block_obj_checkbox_li {
  50. display: inline-block;
  51. margin-top: 5px;
  52. }
  53. .block_obj_checkbox_input {
  54. clip: rect(0, 0, 0, 0);
  55. position: absolute;
  56. }
  57. .block_obj_checkbox_label {
  58. cursor: pointer;
  59. vertical-align: middle;
  60. }
  61. .block_obj_checkbox_input + label::before {
  62. background-color: silver;
  63. border-radius: 0.1em;
  64. color: #FFF;
  65. content: "\\a0";
  66. display: inline-block;
  67. height: 1em;
  68. line-height: 85%;
  69. margin-right: 0.5em;
  70. text-align: center;
  71. vertical-align: 0.2em;
  72. width: 1em;
  73. }
  74. .block_obj_checkbox_input:checked + label::before {
  75. background-color: #00A1D6;
  76. content: "\\2713";
  77. }
  78. .block_obj_separator_text {
  79. color: #FFB86C;
  80. margin-top: 5px;
  81. }
  82. .block_obj_separator_symbol {
  83. background-color: #303030;
  84. height: 2px;
  85. margin-bottom: 5px;
  86. margin-top: 5px;
  87. min-width: 400px;
  88. }
  89. .block_obj_input_div {
  90. margin-top: 5px;
  91. }
  92. .block_obj_input {
  93. background-color: #C0C0C0;
  94. border: 1px solid #C0C0C0;
  95. color: #000;
  96. font-size: 13px;
  97. min-height: 15px;
  98. margin-left: 5px;
  99. margin-right: 5px;
  100. padding-left: 4px;
  101. }
  102. .block_obj_keyword_input {
  103. width: 220px;
  104. }
  105. .block_obj_input_btn {
  106. background-color: #3da9cc;
  107. border-radius: 3px;
  108. border: 1px solid #73C9E5;
  109. box-shadow: 0 0 4px #73C9E5;
  110. color: #FFF;
  111. cursor: pointer;
  112. display: inline-block;
  113. min-height: 15px;
  114. margin-left: 5px;
  115. text-align: center;
  116. vertical-align: bottom;
  117. white-space: nowrap;
  118. width: 30px;
  119. }
  120. .block_obj_list_div {
  121. margin-top: 5px;
  122. }
  123. .block_obj_list_textarea_div {
  124. border: 1px dotted #00A1D6;
  125. margin-top: 3px;
  126. max-height: 60px;
  127. min-height: 3px;
  128. overflow: auto;
  129. }
  130. .block_obj_list_textarea_div::-webkit-scrollbar {
  131. background-color: #979797;
  132. border-radius: 5px;
  133. width: 10px;
  134. }
  135. .block_obj_list_textarea_div::-webkit-scrollbar-thumb {
  136. background-color: #404040;
  137. border-radius: 5px;
  138. }
  139. .block_obj_button_clicked {
  140. color: #000;
  141. }
  142. .block_obj_child_span {
  143. background-color: #3D3D3D;
  144. border-radius: 5px;
  145. border: 1px solid #3D3D3D;
  146. display: inline-block;
  147. margin: 3px;
  148. padding: 2px;
  149. min-height: 18px;
  150. }
  151. .block_obj_child_text {
  152. border-right: 1px solid #A9181C;
  153. margin-right: 4px;
  154. padding-right: 4px;
  155. }
  156. .block_obj_child_green {
  157. color: #41B349;
  158. }
  159. .block_obj_child_del {
  160. color: #A9181C;
  161. cursor: pointer;
  162. }
  163. .block_obj_list_textarea_expand {
  164. max-height: 720px;
  165. }
  166. .block_obj_li_hide {
  167. display: none;
  168. }
  169. .block_obj_button {
  170. background-color: #FB7299;
  171. border-radius: 4px;
  172. border: 1px solid #FB7299;
  173. color: #FFF;
  174. cursor: pointer;
  175. margin-top: 5px;
  176. padding: 2px 4px;
  177. position: relative;
  178. min-height: 17px;
  179. }
  180. .block_obj_save_button {
  181. float: right;
  182. margin-right: 5px;
  183. }
  184. .block_obj_cancel_button {
  185. float: left;
  186. margin-left: 5px;
  187. }
  188. .block_obj_expand_box {
  189. bottom: 0px;
  190. height: 6vh;
  191. position: fixed;
  192. right: -6vw;
  193. transition: 0.5s;
  194. width: 12vw;
  195. z-index: 99999;
  196. }
  197. .block_obj_show_expand_box {
  198. right: 0;
  199. width: 6vw;
  200. }
  201. .block_obj_expand_span {
  202. background-color: #00A1D6;
  203. border-radius: 19px;
  204. border: 1px solid #00A1D6;
  205. bottom: 1vh;
  206. color: #FFF;
  207. cursor: pointer;
  208. display: block;
  209. font-size: 13px;
  210. height: 38px;
  211. line-height: 38px;
  212. position: absolute;
  213. right: 1vw;
  214. text-align: center;
  215. width: 38px;
  216. z-index: 99999;
  217. user-select: none;
  218. }
  219. .block_obj_expand_span:hover {
  220. box-shadow: 0 0 5px 1px green;
  221. }
  222. .block_obj_move_right {
  223. margin-left: 15px;
  224. }
  225. .block_obj_none {
  226. display: none !important;
  227. }
  228. .block_obj_hidden {
  229. visibility: hidden !important;
  230. }
  231. .block_obj_presentation_div {
  232. display: flex;
  233. position: fixed;
  234. background-color: rgba(0, 0, 0, .5);
  235. top: 0;
  236. bottom: 0;
  237. left: 0;
  238. right: 0;
  239. z-index: 100000;
  240. align-items: center;
  241. justify-content: center;
  242. }
  243. .block_obj_dialog_div {
  244. position: relative;
  245. width: 400px;
  246. background-color: #4e5654;
  247. border: 0 solid #000;
  248. border-radius: 12px;
  249. display: flex;
  250. flex-direction: column;
  251. }
  252. .block_obj_big_bang_top_part {
  253. margin-top: 5px;
  254. margin-bottom: 5px;
  255. }
  256. .block_obj_big_bang_h3 {
  257. font-size: 20px;
  258. color: #fff;
  259. margin-left: 5px;
  260. background-color: #4e5654;
  261. border-color: #4e5654;
  262. }
  263. .block_obj_big_bang_deselect_btn {
  264. float: right;
  265. margin-top: 5px;
  266. margin-right: 5px;
  267. color: #2a2a92;
  268. cursor: pointer;
  269. }
  270. .block_obj_big_bang_middle_part {
  271. margin-top: 5px;
  272. margin-bottom: 5px;
  273. max-height: 500px;
  274. overflow-y: auto;
  275. }
  276. .block_obj_big_bang_text {
  277. background-color: #3e3939;
  278. color: #fff;
  279. padding: 5px;
  280. margin: 4px;
  281. font-size: 16px;
  282. display: inline-block;
  283. border-radius: 99px;
  284. cursor: pointer;
  285. user-select: none;
  286. }
  287. .block_obj_big_bang_text_selected {
  288. background-color: #3636b1 !important;
  289. }
  290. .block_obj_big_bang_bottom_part {
  291. margin-top: 5px;
  292. margin-bottom: 5px;
  293. text-align: center;
  294. }
  295. .block_obj_big_bang_add_btn, .block_obj_big_bang_copy_btn {
  296. display: inline-block;
  297. padding: 10px;
  298. color: #fff;
  299. background-color: #325561;
  300. cursor: pointer;
  301. border-radius: 99px;
  302. margin-left: 20px;
  303. margin-right: 20px;
  304. }
  305. .block_obj_big_bang_add_btn:hover, .block_obj_big_bang_copy_btn:hover {
  306. color: #2a2a92;
  307. }
  308. `;
  309. class Block_Obj {
  310. constructor(configKey, regConversion = []) {
  311. this.wrapDiv = null;
  312. this.mainFieldset = null;
  313. this.ulNode = null;
  314. this.style = null;
  315. this.saveField = [];
  316. this.onSave = null;
  317. this.onChange = null;
  318. this.field = [];
  319. this.configKey = configKey;
  320. this.regConversion = regConversion;
  321. this.config = {};
  322. this.timer = null;
  323. this.saveTimer = null;
  324. this.cancelTimer = null;
  325. }
  326. async init(initialization) {
  327. if (!this.id) {
  328. this.id = initialization.id ? 'blockObj_' + initialization.id : 'blockObj_' + Block_Obj.count;
  329. !initialization.id && Block_Obj.count++;
  330. }
  331. this.config = await this.readConfig();
  332. this.regConversion.forEach(item => {
  333. const { ori, key } = item;
  334. if (ori && this.config[ori] != undefined) {
  335. this.config[key] = this.config[key].concat(this.config[ori]);
  336. delete this.config[ori];
  337. }
  338. });
  339. this.display = initialization.display ? true : false;
  340. if (initialization.events) {
  341. if (typeof initialization.events['save'] === 'function') {
  342. this.onSave = initialization.events['save'];
  343. }
  344. if (typeof initialization.events['change'] === 'function') {
  345. this.onChange = initialization.events['change'];
  346. }
  347. }
  348. this.style = document.createElement('style');
  349. this.style.innerHTML = BLOCK_STYLE;
  350. document.body.appendChild(this.style);
  351. if (initialization.style && typeof initialization.style === 'string') {
  352. const externalStyle = document.createElement('style');
  353. externalStyle.innerHTML = initialization.style;
  354. document.body.appendChild(externalStyle);
  355. }
  356. !this.wrapDiv && this.createSettingsPanel();
  357. this.field = initialization.field;
  358. this.settingsPanel();
  359. Block_Obj.GM.registerMenuCommand(initialization.menu, () => this.expandWrap());
  360. Block_Obj.GM.addValueChangeListener(this.configKey, (_name, _oldValue, newValue, remote) => {
  361. if (remote) {
  362. this.destroyAndRebuild(newValue);
  363. typeof this.onChange === 'function' && this.onChange(this.getConfig());
  364. }
  365. });
  366. const expandBox = document.createElement('div');
  367. expandBox.className = 'block_obj_expand_box';
  368. expandBox.onmouseenter = function () {
  369. this.classList.add('block_obj_show_expand_box');
  370. };
  371. expandBox.onmouseleave = function () {
  372. this.classList.remove('block_obj_show_expand_box');
  373. };
  374. const hoverButton = {};
  375. if (initialization.hover_button) {
  376. Object.assign(hoverButton, initialization.hover_button);
  377. }
  378. const expandSpan = document.createElement('span');
  379. expandSpan.id = this.id + '_expandSpan';
  380. expandSpan.className = 'block_obj_expand_span';
  381. expandSpan.textContent = hoverButton.label == null ? '屏蔽' : hoverButton.label;
  382. expandSpan.title = hoverButton.title == null ? '显示/隐藏屏蔽设置' : hoverButton.title;
  383. expandSpan.addEventListener('click', () => {
  384. this.expandWrap();
  385. if (hoverButton.click && typeof hoverButton.click === 'function') {
  386. hoverButton.click(expandSpan);
  387. }
  388. });
  389. expandBox.appendChild(expandSpan);
  390. document.body.appendChild(expandBox);
  391. }
  392. settingsPanel() {
  393. if (Array.isArray(this.field)) {
  394. this.field.forEach(ele => {
  395. if (!this.wrapDiv.querySelector('#' + this.id + '_' + (ele.id ? ele.id : ''))) {
  396. switch (ele.type.toLowerCase()) {
  397. case 'separator':
  398. case 's':
  399. this.insertSeparator(ele.id, ele.label, ele.title, ele.classname);
  400. break;
  401. case 'br':
  402. case 'b':
  403. this.insertBr(ele.classname);
  404. break;
  405. case 'input':
  406. case 'i':
  407. this.insertInput(ele.list_id, ele.id, ele.label, ele.title, ele.placeholder, ele.classname, ele.campare);
  408. break;
  409. case 'list':
  410. case 'l':
  411. this.insertList(ele.id, this.config[ele.id] == null ? ele.default : this.config[ele.id], ele.label, ele.title, ele.classname);
  412. break;
  413. case 'checkbox':
  414. case 'c':
  415. default:
  416. this.insertCheckbox(
  417. ele.id,
  418. ele.label,
  419. ele.title,
  420. this.config[ele.id] == null ? ele.default : this.config[ele.id],
  421. ele.classname,
  422. ele.move_right
  423. );
  424. break;
  425. }
  426. }
  427. });
  428. }
  429. const saveButton = this.createSpanBtn('block_obj_button block_obj_save_button', '保存并关闭', '保存设置并关闭设置窗口', e => {
  430. this.expandWrap();
  431. this.saveConfig();
  432. });
  433. const onlySaveButton = this.createSpanBtn('block_obj_button block_obj_save_button', '仅保存', '仅保存设置', e => {
  434. onlySaveButton.textContent = '已保存';
  435. this.saveTimer && window.clearTimeout(this.saveTimer);
  436. this.saveTimer = null;
  437. this.saveTimer = window.setTimeout(() => {
  438. onlySaveButton.textContent = '仅保存';
  439. }, 1000);
  440. this.saveConfig();
  441. });
  442. const cancelButton = this.createSpanBtn('block_obj_button block_obj_cancel_button', '取消', '关闭设置窗口', e => {
  443. this.expandWrap();
  444. this.cancelTimer && window.clearTimeout(this.cancelTimer);
  445. this.cancelTimer = null;
  446. this.cancelTimer = window.setTimeout(() => {
  447. this.display = false;
  448. this.destroyAndRebuild();
  449. }, 800);
  450. e.stopPropagation();
  451. });
  452. this.ulNode.appendChild(saveButton);
  453. this.ulNode.appendChild(onlySaveButton);
  454. this.ulNode.appendChild(cancelButton);
  455. document.body.appendChild(this.wrapDiv);
  456. }
  457. getConfig() {
  458. const realConfig = {};
  459. Object.assign(realConfig, this.config);
  460. this.regConversion.forEach(item => {
  461. const { key } = item;
  462. realConfig[key] = this.convertArray(realConfig[key]);
  463. });
  464. return realConfig;
  465. }
  466. async readConfig() {
  467. let config = {};
  468. if (this.configKey) {
  469. config = await Block_Obj.GM.getValue(this.configKey, {});
  470. }
  471. return config;
  472. }
  473. saveConfig() {
  474. this.saveField.forEach(item => {
  475. if (item.type == 'checkbox') {
  476. this.config[item.key] = document.getElementById(this.id + '_' + item.key).checked;
  477. } else if (item.type == 'list') {
  478. this.config[item.key] = this.extractList(this.id + '_' + item.key);
  479. }
  480. });
  481. Block_Obj.GM.setValue(this.configKey, this.config);
  482. typeof this.onSave === 'function' && this.onSave(this.getConfig());
  483. }
  484. createSettingsPanel() {
  485. this.wrapDiv = document.createElement('div');
  486. this.wrapDiv.id = this.id + '_wrapDiv';
  487. this.wrapDiv.className = 'block_obj_wrap_div ' + (this.display ? 'block_obj_show_wrap' : 'block_obj_hidden_wrap');
  488. this.mainFieldset = document.createElement('fieldset');
  489. this.mainFieldset.id = this.id + '_mainFieldset';
  490. this.mainFieldset.className = 'block_obj_main_fieldset';
  491. this.wrapDiv.appendChild(this.mainFieldset);
  492. this.ulNode = document.createElement('ul');
  493. this.ulNode.id = this.id + '_ulNode';
  494. this.ulNode.className = 'block_obj_ul_node';
  495. this.mainFieldset.appendChild(this.ulNode);
  496. document.body.appendChild(this.wrapDiv);
  497. }
  498. destroyAndRebuild(new_config = null) {
  499. this.config = new_config || this.config;
  500. document.body.removeChild(this.wrapDiv);
  501. this.createSettingsPanel();
  502. this.settingsPanel();
  503. }
  504. expandWrap() {
  505. const panel = document.getElementById(this.id + '_wrapDiv');
  506. if (panel) {
  507. if (panel.classList.contains('block_obj_show_wrap')) {
  508. this.display = false;
  509. panel.classList.remove('block_obj_show_wrap');
  510. panel.classList.add('block_obj_hidden_wrap');
  511. } else {
  512. this.display = true;
  513. panel.classList.remove('block_obj_hidden_wrap');
  514. panel.classList.add('block_obj_show_wrap');
  515. }
  516. }
  517. }
  518. insertCheckbox(id, label = '', title = '', checked = false, classname = null, moveRight = false) {
  519. const checkboxLi = document.createElement('li');
  520. checkboxLi.className = 'block_obj_checkbox_li';
  521. classname && checkboxLi.classList.add(classname);
  522. moveRight && checkboxLi.classList.add('block_obj_move_right');
  523. const checkboxInput = document.createElement('input');
  524. checkboxInput.type = 'checkbox';
  525. checkboxInput.className = 'block_obj_checkbox_input';
  526. checkboxInput.id = this.id + '_' + id;
  527. checkboxInput.checked = checked ? true : false;
  528. const checkboxLabel = document.createElement('label');
  529. checkboxLabel.className = 'block_obj_checkbox_label';
  530. checkboxLabel.setAttribute('for', this.id + '_' + id);
  531. checkboxLabel.textContent = label;
  532. checkboxLabel.title = title;
  533. checkboxLi.appendChild(checkboxInput);
  534. checkboxLi.appendChild(checkboxLabel);
  535. this.ulNode.appendChild(checkboxLi);
  536. this.saveField.push({
  537. key: id,
  538. type: 'checkbox',
  539. });
  540. }
  541. insertSeparator(id = null, label = null, title = null, liClassname = null) {
  542. const separatorLi = document.createElement('li');
  543. separatorLi.className = 'block_obj_separator_li';
  544. liClassname && separatorLi.classList.add('block_obj_' + liClassname);
  545. const separatorDiv = document.createElement('div');
  546. if (id) {
  547. separatorDiv.id = this.id + '_' + id;
  548. }
  549. if (label) {
  550. separatorDiv.className = 'block_obj_separator_text';
  551. separatorDiv.textContent = label;
  552. } else {
  553. separatorDiv.className = 'block_obj_separator_symbol';
  554. }
  555. separatorDiv.title = title ? title : '';
  556. separatorLi.appendChild(separatorDiv);
  557. this.ulNode.appendChild(separatorLi);
  558. }
  559. insertBr(classname = null) {
  560. const br = document.createElement('br');
  561. br.className = classname ? classname : '';
  562. this.ulNode.appendChild(br);
  563. }
  564. insertInput(listId, id = null, label = '', title = '', placeholder = '', liClassname = null, campare = null) {
  565. const inputLi = document.createElement('li');
  566. inputLi.className = liClassname ? 'block_obj_' + liClassname : '';
  567. const inputDiv = document.createElement('div');
  568. inputDiv.className = 'block_obj_input_div';
  569. const inputSpan = document.createElement('span');
  570. inputSpan.className = 'block_obj_input_span';
  571. inputSpan.textContent = label;
  572. inputDiv.appendChild(inputSpan);
  573. const input = document.createElement('input');
  574. if (id) {
  575. input.id = this.id + '_' + id;
  576. }
  577. input.title = title;
  578. input.placeholder = placeholder;
  579. input.type = 'text';
  580. input.className = 'block_obj_input block_obj_keyword_input';
  581. inputSpan.appendChild(input);
  582. const theListId = this.id + '_' + listId;
  583. input.addEventListener('keyup', e => {
  584. if (e.key === 'Enter') {
  585. this.addListItem(input, theListId, campare);
  586. }
  587. });
  588. const addBtn = this.createSpanBtn('block_obj_input_btn', '添加', '添加内容到列表中', _e => {
  589. if (this.addListItem(input, theListId, campare)) {
  590. this.buttonClicked(addBtn, '添加成功', 'block_obj_button_clicked');
  591. }
  592. });
  593. const deleteBtn = this.createSpanBtn('block_obj_input_btn', '删除', '从列表中删除符合的项目', _e => {
  594. if (this.delListItem(input, theListId)) {
  595. this.buttonClicked(deleteBtn, '删除成功', 'block_obj_button_clicked');
  596. }
  597. });
  598. const clearBtn = this.createSpanBtn('block_obj_input_btn', '清空', '清空列表', _e => {
  599. document.getElementById(theListId).innerHTML = '';
  600. this.buttonClicked(clearBtn, '清除成功', 'block_obj_button_clicked');
  601. });
  602. const copyBtn = this.createSpanBtn('block_obj_input_btn', '复制', '复制列表', _e => {
  603. Block_Obj.GM.setClipboard(this.extractList(theListId).toString());
  604. this.buttonClicked(copyBtn, '复制成功', 'block_obj_button_clicked');
  605. });
  606. const expandBtn = this.createSpanBtn('block_obj_input_btn', '展开', '展开列表', _e => {
  607. liClassname && this.toggleList('block_obj_' + liClassname);
  608. if (expandBtn.textContent == '展开') {
  609. expandBtn.textContent = '恢复';
  610. expandBtn.title = '收缩列表';
  611. } else {
  612. expandBtn.textContent = '展开';
  613. expandBtn.title = '展开列表';
  614. }
  615. });
  616. inputDiv.appendChild(addBtn);
  617. inputDiv.appendChild(deleteBtn);
  618. inputDiv.appendChild(clearBtn);
  619. inputDiv.appendChild(copyBtn);
  620. inputDiv.appendChild(expandBtn);
  621. inputLi.appendChild(inputDiv);
  622. this.ulNode.appendChild(inputLi);
  623. }
  624. insertList(id, saveArray = [], label = '', title = '', liClassname = '') {
  625. const listLi = document.createElement('li');
  626. listLi.className = liClassname ? 'block_obj_' + liClassname : '';
  627. const listDiv = document.createElement('div');
  628. listDiv.className = 'block_obj_list_div';
  629. listDiv.textContent = label;
  630. listDiv.title = title;
  631. const listTextareaDiv = document.createElement('div');
  632. listTextareaDiv.id = this.id + '_' + id;
  633. listTextareaDiv.className = 'block_obj_list_textarea_div';
  634. for (const item of saveArray) {
  635. item && listTextareaDiv.insertAdjacentElement('afterbegin', this.createListItem(item));
  636. }
  637. listDiv.appendChild(listTextareaDiv);
  638. listLi.appendChild(listDiv);
  639. this.ulNode.appendChild(listLi);
  640. this.saveField.push({
  641. key: id,
  642. type: 'list',
  643. });
  644. }
  645. addListItem(input, listId, campare = null) {
  646. const textValue = input.value;
  647. if (textValue) {
  648. const textArr = this.stringToArray(textValue);
  649. const saveArr = this.extractList(listId);
  650. textArr.forEach(item => {
  651. let status = true;
  652. if (typeof campare === 'function') {
  653. const tempStatus = campare(item);
  654. if (typeof tempStatus === 'boolean') {
  655. status = tempStatus;
  656. }
  657. }
  658. if (status) {
  659. !saveArr.includes(item) && document.getElementById(listId).insertAdjacentElement('afterbegin', this.createListItem(item));
  660. }
  661. });
  662. input.value = '';
  663. return true;
  664. }
  665. return false;
  666. }
  667. delListItem(input, listId) {
  668. const textValue = input.value;
  669. if (textValue) {
  670. let delStatus = false;
  671. const textArr = this.stringToArray(textValue);
  672. const saveArr = this.extractList(listId);
  673. textArr.forEach(item => {
  674. if (saveArr.includes(item)) {
  675. const totalChild = document.getElementById(listId).getElementsByClassName('block_obj_child_span');
  676. try {
  677. document.getElementById(listId).removeChild(totalChild[totalChild.length - 1 - saveArr.indexOf(item)]);
  678. delStatus = true;
  679. } catch (e) {
  680. delStatus = false;
  681. console.error('Block_Obj: Error deleting element.');
  682. console.error(e);
  683. }
  684. }
  685. });
  686. if (delStatus) {
  687. input.value = '';
  688. return true;
  689. }
  690. }
  691. return false;
  692. }
  693. createSpanBtn(classname, label, title, callback) {
  694. const btnSpan = this.createBasicBtn('span', label, title, classname);
  695. btnSpan.addEventListener('click', e => typeof callback === 'function' && callback(e));
  696. return btnSpan;
  697. }
  698. createListItem(text_value) {
  699. const childSpan = document.createElement('span');
  700. childSpan.className = 'block_obj_child_span';
  701. const textSpan = document.createElement('span');
  702. textSpan.className = text_value.match(/^\/.+\/[a-z]*$/i) ? 'block_obj_child_text block_obj_child_green' : 'block_obj_child_text';
  703. textSpan.textContent = text_value.length > 9 ? text_value.slice(0, 3) + ' ... ' + text_value.slice(-3) : text_value;
  704. if (text_value.length > 9) {
  705. textSpan.title = text_value;
  706. }
  707. const delSpan = document.createElement('span');
  708. delSpan.textContent = 'X';
  709. delSpan.title = '移除';
  710. delSpan.className = 'block_obj_child_del';
  711. delSpan.addEventListener('click', e => childSpan.remove());
  712. childSpan.appendChild(textSpan);
  713. childSpan.appendChild(delSpan);
  714. return childSpan;
  715. }
  716. createBasicBtn(type, text, title, classname) {
  717. let btnType = 'span';
  718. if (typeof type === 'string') {
  719. switch (type.toLowerCase()) {
  720. case 'div':
  721. case 'd':
  722. btnType = 'div';
  723. break;
  724. case 'a':
  725. btnType = 'a';
  726. break;
  727. case 'button':
  728. btnType = 'button';
  729. break;
  730. case 'input':
  731. btnType = 'input';
  732. break;
  733. case 'i':
  734. btnType = 'i';
  735. break;
  736. case 'b':
  737. btnType = 'b';
  738. break;
  739. case 'span':
  740. case 's':
  741. default:
  742. btnType = 'span';
  743. break;
  744. }
  745. }
  746. const btn = document.createElement(btnType);
  747. btn.textContent = text ? text : '';
  748. btn.title = title ? title : '';
  749. btn.className = classname ? classname : '';
  750. return btn;
  751. }
  752. createBlockBtn(value, listId, classname, type = 'span', text = '', title = '', campare = null) {
  753. const blockBtn = this.createBasicBtn(type, text, title, classname);
  754. blockBtn.addEventListener('click', e => {
  755. e.stopPropagation();
  756. if (value && listId) {
  757. let status = true;
  758. if (typeof campare === 'function') {
  759. const tempStatus = campare(value);
  760. if (typeof tempStatus === 'boolean') {
  761. status = tempStatus;
  762. }
  763. }
  764. if (status) {
  765. const theListId = this.id + '_' + listId;
  766. const saveArr = this.extractList(theListId);
  767. !saveArr.includes(value) &&
  768. document.getElementById(theListId) &&
  769. document.getElementById(theListId).insertAdjacentElement('afterbegin', this.createListItem(value));
  770. }
  771. }
  772. this.saveConfig();
  773. });
  774. return blockBtn;
  775. }
  776. createBigBangBtn(value, listId, classname, type = 'span', text = '', title = '', campare = null) {
  777. const bigBangBtn = this.createBasicBtn(type, text, title, classname);
  778. bigBangBtn.addEventListener('click', e => {
  779. e.stopPropagation();
  780. if (value && listId) {
  781. const theListId = this.id + '_' + listId;
  782. this.injectionBigBangPanel(value, theListId, campare);
  783. }
  784. });
  785. return bigBangBtn;
  786. }
  787. injectionBigBangPanel(value, listId, campare = null) {
  788. const presentationDiv = document.createElement('div');
  789. presentationDiv.id = this.id + '_presentationDiv';
  790. presentationDiv.className = 'block_obj_presentation_div';
  791. presentationDiv.addEventListener('click', function (event) {
  792. if (event.target === this) {
  793. if (presentationDiv) {
  794. presentationDiv.remove();
  795. }
  796. }
  797. });
  798. const dialogDiv = document.createElement('div');
  799. dialogDiv.className = 'block_obj_dialog_div';
  800. presentationDiv.appendChild(dialogDiv);
  801. const topPart = document.createElement('div');
  802. topPart.className = 'block_obj_big_bang_top_part';
  803. const h3 = document.createElement('h3');
  804. h3.className = 'block_obj_big_bang_h3';
  805. h3.textContent = '大爆炸';
  806. topPart.appendChild(h3);
  807. const deselectBtn = this.createSpanBtn('block_obj_big_bang_deselect_btn', '取消选择', '取消全部已选择的内容', e => {
  808. e.stopPropagation();
  809. const selectArr = document.querySelectorAll('.block_obj_big_bang_text_selected');
  810. for (const s of selectArr) {
  811. s.classList.remove('block_obj_big_bang_text_selected');
  812. }
  813. });
  814. topPart.appendChild(deselectBtn);
  815. const valueArray = value.replace(/\s| /gi, '').split('');
  816. const middlePart = document.createElement('div');
  817. middlePart.className = 'block_obj_big_bang_middle_part';
  818. const nodeArray = valueArray.map((ele, index) => {
  819. const eleNode = this.createBasicBtn('span', ele, '', 'block_obj_big_bang_text');
  820. eleNode.setAttribute('data-index', index);
  821. eleNode.addEventListener('click', e => {
  822. e.stopPropagation();
  823. eleNode.classList.contains('block_obj_big_bang_text_selected')
  824. ? eleNode.classList.remove('block_obj_big_bang_text_selected')
  825. : eleNode.classList.add('block_obj_big_bang_text_selected');
  826. });
  827. return eleNode;
  828. });
  829. nodeArray.forEach(item => {
  830. middlePart.appendChild(item);
  831. });
  832. const bottomPart = document.createElement('div');
  833. bottomPart.className = 'block_obj_big_bang_bottom_part';
  834. const addBtn = this.createSpanBtn('block_obj_big_bang_add_btn', '添加', '添加选择的内容到列表中', e => {
  835. e.stopPropagation();
  836. const textValue = this.getSelectedText('block_obj_big_bang_text_selected');
  837. if (textValue && listId) {
  838. const textArr = this.stringToArray(textValue);
  839. const saveArr = this.extractList(listId);
  840. textArr.forEach(item => {
  841. let status = true;
  842. if (typeof campare === 'function') {
  843. const tempStatus = campare(item);
  844. if (typeof tempStatus === 'boolean') {
  845. status = tempStatus;
  846. }
  847. }
  848. if (status) {
  849. !saveArr.includes(item) && document.getElementById(listId).insertAdjacentElement('afterbegin', this.createListItem(item));
  850. }
  851. });
  852. this.saveConfig();
  853. presentationDiv.remove();
  854. }
  855. });
  856. bottomPart.appendChild(addBtn);
  857. const copyBtn = this.createSpanBtn('block_obj_big_bang_copy_btn', '复制', '复制选择的内容到剪贴板中', e => {
  858. e.stopPropagation();
  859. const textValue = this.getSelectedText('block_obj_big_bang_text_selected');
  860. if (textValue) {
  861. Block_Obj.GM.setClipboard(textValue);
  862. presentationDiv.remove();
  863. }
  864. });
  865. bottomPart.appendChild(copyBtn);
  866. dialogDiv.appendChild(topPart);
  867. dialogDiv.appendChild(middlePart);
  868. dialogDiv.appendChild(bottomPart);
  869. document.body.appendChild(presentationDiv);
  870. }
  871. getSelectedText(classname) {
  872. const selectedArray = document.getElementsByClassName(classname);
  873. let lastIndex = -1;
  874. let textValue = '';
  875. for (const selected of selectedArray) {
  876. const index = selected.getAttribute('data-index') || -1;
  877. if (Number(index) == lastIndex + 1) {
  878. textValue += selected.textContent;
  879. } else {
  880. textValue = textValue ? textValue + ',' + selected.textContent : selected.textContent;
  881. }
  882. lastIndex = Number(index);
  883. }
  884. return textValue;
  885. }
  886. buttonClicked(button, clickTitle, click_class) {
  887. const originalTitle = button.title;
  888. button.title = clickTitle;
  889. click_class && button.classList.add(click_class);
  890. this.timer && window.clearTimeout(this.timer);
  891. this.timer = null;
  892. this.timer = window.setTimeout(() => {
  893. button.title = originalTitle;
  894. button.classList.remove(click_class);
  895. }, 1000);
  896. }
  897. extractList(listId) {
  898. const reArr = [];
  899. const listDom = document.getElementById(listId);
  900. const listArr = listDom.getElementsByClassName('block_obj_child_text');
  901. for (let i = listArr.length - 1; i >= 0; i--) {
  902. listArr[i].title ? reArr.push(listArr[i].title) : reArr.push(listArr[i].textContent);
  903. }
  904. return reArr;
  905. }
  906. stringToArray(textString = '') {
  907. const tempArray = textString.match(/^\/.+\/[a-z]*$/i) ? [textString] : textString.split(',');
  908. const returnArray = [];
  909. for (let i = 0, l = tempArray.length; i < l; i++) {
  910. for (let j = i + 1; j < l; j++) {
  911. if (tempArray[i] === tempArray[j]) {
  912. ++i;
  913. j = i;
  914. }
  915. }
  916. returnArray.push(tempArray[i]);
  917. }
  918. return returnArray;
  919. }
  920. toggleList(liClassname) {
  921. for (const li of this.ulNode.querySelectorAll('li')) {
  922. if (li.classList.contains(liClassname)) {
  923. const listTextareaDiv = li.querySelector('.block_obj_list_textarea_div');
  924. if (listTextareaDiv) {
  925. listTextareaDiv.classList.contains('block_obj_list_textarea_expand')
  926. ? listTextareaDiv.classList.remove('block_obj_list_textarea_expand')
  927. : listTextareaDiv.classList.add('block_obj_list_textarea_expand');
  928. }
  929. } else {
  930. li.classList.contains('block_obj_li_hide') ? li.classList.remove('block_obj_li_hide') : li.classList.add('block_obj_li_hide');
  931. }
  932. }
  933. for (const br of this.ulNode.querySelectorAll('br')) {
  934. br.classList.contains('block_obj_li_hide') ? br.classList.remove('block_obj_li_hide') : br.classList.add('block_obj_li_hide');
  935. }
  936. }
  937. convertArray(stringArray) {
  938. const reArr = [];
  939. if (Array.isArray(stringArray)) {
  940. for (const str of stringArray) {
  941. if (str.match(/^\/.+\/[a-z]*$/i)) {
  942. try {
  943. const newReg = new RegExp(str.replace(/^\/|\/[a-z]*$/gi, ''), str.replace(/^\/.*\/[^a-z]*/i, ''));
  944. reArr.push(newReg);
  945. } catch (e) {
  946. console.error('Block_Obj: The transformation contains invalid regular expressions.');
  947. console.error(e);
  948. }
  949. } else {
  950. reArr.push(str);
  951. }
  952. }
  953. }
  954. return reArr;
  955. }
  956. }
  957. Block_Obj.count = 0;
  958. Block_Obj.GM = {
  959. isError: false,
  960. menuCount: 0,
  961. error: message => {
  962. if (!Block_Obj.GM.isError) {
  963. Block_Obj.GM.isError = true;
  964. alert('The required ' + message + ' method is incomplete!!!');
  965. }
  966. },
  967. warn: message => {
  968. console.warn('The required ' + message + ' method is incomplete!!!');
  969. },
  970. tips: message => {
  971. console.info('Tips: ' + message);
  972. },
  973. info: () => {
  974. if (typeof GM_info === 'object') {
  975. return GM_info;
  976. } else if (typeof GM.info === 'object') {
  977. return GM.info;
  978. } else {
  979. Block_Obj.GM.warn('GM_info or GM.info');
  980. return {
  981. script: {
  982. version: 0,
  983. },
  984. scriptHandler: 'Unknown',
  985. version: 0,
  986. };
  987. }
  988. },
  989. getValue: (name, defaultValue) => {
  990. if (typeof GM_getValue === 'function') {
  991. return GM_getValue(name, defaultValue);
  992. } else if (typeof GM.getValue === 'function') {
  993. return GM.getValue(name, defaultValue);
  994. } else {
  995. Block_Obj.GM.error('GM_getValue or GM.getValue');
  996. return null;
  997. }
  998. },
  999. setValue: (name, value) => {
  1000. if (typeof GM_setValue === 'function') {
  1001. GM_setValue(name, value);
  1002. } else if (typeof GM.setValue === 'function') {
  1003. GM.setValue(name, value);
  1004. } else {
  1005. Block_Obj.GM.error('GM_setValue or GM.setValue');
  1006. }
  1007. },
  1008. deleteValue: async name => {
  1009. if (typeof GM_deleteValue === 'function') {
  1010. await GM_deleteValue(name);
  1011. } else if (typeof GM.deleteValue === 'function') {
  1012. await GM.deleteValue(name);
  1013. } else {
  1014. Block_Obj.GM.error('GM_deleteValue or GM.deleteValue');
  1015. }
  1016. },
  1017. listValues: () => {
  1018. if (typeof GM_listValues === 'function') {
  1019. return GM_listValues();
  1020. } else if (typeof GM.listValues === 'function') {
  1021. return GM.listValues();
  1022. } else {
  1023. Block_Obj.GM.error('GM_listValues or GM.listValues');
  1024. }
  1025. },
  1026. openInTab: (url, options) => {
  1027. if (typeof GM_openInTab === 'function') {
  1028. GM_openInTab(url, options);
  1029. } else if (typeof GM.openItTab === 'function') {
  1030. GM.openInTab(url, options.active);
  1031. } else {
  1032. Block_Obj.GM.error('GM_openInTab or GM.openInTab');
  1033. }
  1034. },
  1035. hasOpenIntTabMethods: () => {
  1036. return typeof GM_openInTab === 'function' || typeof GM.openItTab === 'function';
  1037. },
  1038. hasRegisterMenuCommandMethods: () => {
  1039. return typeof GM_registerMenuCommand === 'function';
  1040. },
  1041. hasAddValueChangeListenerMethods: () => {
  1042. return typeof GM_addValueChangeListener === 'function';
  1043. },
  1044. registerMenuCommand: (name, fn) => {
  1045. let menuId = null;
  1046. if (typeof GM_registerMenuCommand === 'function') {
  1047. if (Block_Obj.GM.info().scriptHandler === 'Violentmonkey') {
  1048. Block_Obj.GM.menuCount++;
  1049. GM_registerMenuCommand(Block_Obj.GM.menuCount + '.' + name, fn);
  1050. menuId = Block_Obj.GM.menuCount + '.' + name;
  1051. } else if (Block_Obj.GM.info().scriptHandler === 'Tampermonkey') {
  1052. menuId = GM_registerMenuCommand(name, fn);
  1053. }
  1054. } else {
  1055. Block_Obj.GM.warn('GM_registerMenuCommand');
  1056. }
  1057. return menuId;
  1058. },
  1059. unregisterMenuCommand: menuId => {
  1060. if (typeof GM_unregisterMenuCommand === 'function') {
  1061. GM_unregisterMenuCommand(menuId);
  1062. if (Block_Obj.GM.info().scriptHandler === 'Violentmonkey') {
  1063. Block_Obj.GM.menuCount--;
  1064. if (Block_Obj.fn.compare('2.12.5', Block_Obj.GM.info().version)) {
  1065. Block_Obj.GM.tips('Maybe you should update Violentmonkey to 2.12.5 or higher.');
  1066. }
  1067. }
  1068. } else {
  1069. Block_Obj.GM.warn('GM_unregisterMenuCommand');
  1070. }
  1071. },
  1072. addValueChangeListener: (name, callback) => {
  1073. if (typeof GM_addValueChangeListener === 'function') {
  1074. return GM_addValueChangeListener(name, callback);
  1075. } else {
  1076. Block_Obj.GM.warn('GM_addValueChangeListener');
  1077. return null;
  1078. }
  1079. },
  1080. removeValueChangeListener: listenerId => {
  1081. if (typeof GM_removeValueChangeListener === 'function') {
  1082. GM_removeValueChangeListener(listenerId);
  1083. } else {
  1084. Block_Obj.GM.warn('GM_removeValueChangeListener');
  1085. }
  1086. },
  1087. setClipboard: text => {
  1088. if (typeof GM_setClipboard === 'function') {
  1089. GM_setClipboard(text);
  1090. } else if (typeof GM.setClipboard === 'function') {
  1091. GM.setClipboard(text);
  1092. } else {
  1093. Block_Obj.GM.error('GM_setClipboard or GM.setClipboard');
  1094. }
  1095. },
  1096. };
  1097. Block_Obj.fn = {
  1098. hideOperation: (node, hide_status, method = 0) => {
  1099. if (node && node instanceof HTMLElement) {
  1100. if (hide_status) {
  1101. if (method === 0) {
  1102. node.classList.add('block_obj_none');
  1103. } else if (method === 1) {
  1104. node.classList.add('block_obj_hidden');
  1105. } else if (method === 2) {
  1106. node.style.display = 'none';
  1107. } else if (method === 3) {
  1108. node.style.visibility = 'hidden';
  1109. }
  1110. } else {
  1111. if (method === 0) {
  1112. node.classList.remove('block_obj_none');
  1113. } else if (method === 1) {
  1114. node.classList.remove('block_obj_hidden');
  1115. } else if (method === 2) {
  1116. node.style.display = '';
  1117. } else if (method === 3) {
  1118. node.style.visibility = '';
  1119. }
  1120. }
  1121. }
  1122. },
  1123. compare(str1, str2, symbol = '.', equal = false) {
  1124. const arr1 = str1.split(symbol);
  1125. const arr2 = str2.split(symbol);
  1126. let compareStatus = false;
  1127. const len = arr1.length < arr2.length ? arr1.length : arr2.length;
  1128. for (let i = len - 1; i >= 0; i--) {
  1129. if (Number(arr1[i]) > Number(arr2[i])) {
  1130. compareStatus = true;
  1131. } else if (equal && Number(arr1[i]) == Number(arr2[i])) {
  1132. compareStatus = true;
  1133. } else {
  1134. compareStatus = false;
  1135. }
  1136. }
  1137. return compareStatus;
  1138. },
  1139. getVersion: () => '3.0.1',
  1140. };