Twitter - 为用户添加备注

为用户添加备注功能,以帮助识别和搜索; 鼠标移至网页右下角弹出搜索按钮

当前为 2020-06-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Twitter - Add notes to the user
  3. // @name:zh-CN Twitter - 为用户添加备注
  4. // @name:zh-TW Twitter - 為使用者新增備註
  5. // @namespace https://gf.qytechs.cn/zh-CN/users/193133-pana
  6. // @homepage https://www.sailboatweb.com
  7. // @version 1.1.7
  8. // @description Add a note for users to help identify and search; the search button pops up in the lower right corner
  9. // @description:zh-CN 为用户添加备注功能,以帮助识别和搜索; 鼠标移至网页右下角弹出搜索按钮
  10. // @description:zh-TW 為使用者新增備註功能,以幫助識別和搜尋; 滑鼠移至網頁右下角彈出搜尋按鈕
  11. // @author pana
  12. // @license GNU General Public License v3.0 or later
  13. // @include http*://*twitter.com/*
  14. // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js
  15. // @grant GM_getValue
  16. // @grant GM_setValue
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21. const LANG = {
  22. 'EN': {
  23. 'title': 'Note',
  24. 'add_button_text': 'Add note',
  25. 'add_button_title': 'Add notes to the user',
  26. 'modify_button_text': 'Modify note',
  27. 'modify_button_title': 'Modify notes for the user',
  28. 'input_placeholder': '(Enter a note, delete it when blanked; press Enter to save)',
  29. 'save_button_text': 'Save',
  30. 'clear_button_text': 'Clear',
  31. 'cancel_button_text': 'Cancel',
  32. 'search_placeholder': 'Search notes',
  33. 'user_id': 'User ID: ',
  34. 'user_name': 'User Name: '
  35. },
  36. 'ZH_CN': {
  37. 'title': '备注',
  38. 'add_button_text': '添加备注',
  39. 'add_button_title': '为用户添加备注',
  40. 'modify_button_text': '修改备注',
  41. 'modify_button_title': '为用户修改备注',
  42. 'input_placeholder': '(请输入备注,置空时删除;按下Enter键保存)',
  43. 'save_button_text': '保存',
  44. 'clear_button_text': '清除',
  45. 'cancel_button_text': '取消',
  46. 'search_placeholder': '搜索备注',
  47. 'user_id': '用户 ID: ',
  48. 'user_name': '用户名: '
  49. },
  50. 'ZH_TW': {
  51. 'title': '備註',
  52. 'add_button_text': '新增備註',
  53. 'add_button_title': '為使用者新增備註',
  54. 'modify_button_text': '修改備註',
  55. 'modify_button_title': '為使用者修改備註',
  56. 'input_placeholder': '(請輸入備註,置空時刪除;按下Enter鍵儲存)',
  57. 'save_button_text': '儲存',
  58. 'clear_button_text': '清除',
  59. 'cancel_button_text': '取消',
  60. 'search_placeholder': '搜尋備註',
  61. 'user_id': '使用者 ID: ',
  62. 'user_name': '使用者名稱: '
  63. }
  64. };
  65. const ICON = {
  66. 'NOTE_GRAY': 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMTAxLCAxMTksIDEzNCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigxMDEsIDExOSwgMTM0KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)',
  67. 'NOTE_BLUE': 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)',
  68. 'SEARCH': 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9InNlYXJjaEljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ic2VhcmNoSWNvblRpdGxlIj5TZWFyY2g8L3RpdGxlPiA8cGF0aCBkPSJNMTQuNDEyMTEyMiwxNC40MTIxMTIyIEwyMCwyMCIvPiA8Y2lyY2xlIGN4PSIxMCIgY3k9IjEwIiByPSI2Ii8+IDwvc3ZnPg==)'
  69. };
  70. const STYLE_VALUE = `
  71. .my_twitter_note_btn {
  72. background-image: ${ICON.NOTE_GRAY};
  73. background-repeat: no-repeat;
  74. background-position: center;
  75. background-color: rgba(0, 0, 0, 0);
  76. border-bottom-left-radius: 9999px;
  77. border-bottom-right-radius: 9999px;
  78. border-top-left-radius: 9999px;
  79. border-top-right-radius: 9999px;
  80. transition-property: background-color, box-shadow;
  81. transition-duration: 0.2s;
  82. }
  83. .my_twitter_note_btn:hover {
  84. background-image: ${ICON.NOTE_BLUE};
  85. background-color: rgba(29, 161, 242, 0.1);
  86. }
  87. .base_tool_bar_btn {
  88. height: 32px;
  89. width: 32px;
  90. margin: -8px -45px -8px 70px;
  91. background-size: 18px auto;
  92. }
  93. .comment_tool_bar_btn {
  94. height: 42px;
  95. width: 42px;
  96. margin: 2px 0px 0px -15px;
  97. background-size: 22px auto;
  98. cursor: pointer;
  99. }
  100. .my_before_follow_note_btn {
  101. height: 39px;
  102. width: 39px;
  103. background-image: ${ICON.NOTE_BLUE};
  104. background-repeat: no-repeat;
  105. background-size: 19px auto;
  106. background-position: center;
  107. margin-bottom: 10px;
  108. margin-right: 10px;
  109. cursor: pointer;
  110. border: 1px solid rgba(29,161,242,1.00);
  111. border-bottom-left-radius: 9999px;
  112. border-bottom-right-radius: 9999px;
  113. border-top-left-radius: 9999px;
  114. border-top-right-radius: 9999px;
  115. background-color: rgba(0, 0, 0, 0);
  116. transition-property: background-color, box-shadow;
  117. transition-duration: 0.2s;
  118. }
  119. .my_before_follow_note_btn:hover {
  120. background-color: rgba(29, 161, 242, 0.1);
  121. }
  122. .list_show, .show_separator {
  123. display: block !important;
  124. }
  125. #presentation_div_for_user {
  126. display: flex;
  127. position: fixed;
  128. background-color: rgba(0, 0, 0, .5);
  129. top: 0;
  130. bottom: 0;
  131. left: 0;
  132. right: 0;
  133. z-index: 101;
  134. align-items: center;
  135. justify-content: center;
  136. }
  137. .dialog_div_for_user {
  138. position: relative;
  139. width: 400px;
  140. background-color: rgb(21, 32, 43);
  141. border: 0 solid #000;
  142. border-radius: 12px;
  143. display: flex;
  144. flex-direction: column;
  145. }
  146. .user_title_span_for_user {
  147. min-height: 48px;
  148. text-align: center;
  149. border: 1px solid rgba(0, 0, 0, .5);
  150. color: #1da1f2;
  151. font-weight: bold;
  152. background-color: rgba(0, 0, 0, 0);
  153. border-top-left-radius: 12px;
  154. border-top-right-radius: 12px;
  155. white-space: pre-wrap;
  156. cursor: text;
  157. user-select: text;
  158. line-height: 24px;
  159. }
  160. .tag_input_for_user {
  161. min-height: 32px;
  162. margin: 5px;
  163. border: 1px solid rgba(29, 161, 242, 0.1);
  164. padding-left: 5px;
  165. background-color: #253341;
  166. color: #fff;
  167. }
  168. .button_for_user {
  169. min-height: 48px;
  170. cursor: pointer;
  171. border: 1px solid rgba(0, 0, 0, .5);
  172. background-color: rgba(0, 0, 0, 0);
  173. color: #fff;
  174. }
  175. .button_for_user:hover {
  176. color: #1da1f2;
  177. }
  178. .cancel_button_for_user {
  179. border-bottom-left-radius: 12px;
  180. border-bottom-right-radius: 12px;
  181. }
  182. #searchFrame {
  183. position: relative;
  184. }
  185. #myInputSearch {
  186. width: 350px;
  187. height: 40px;
  188. border: 2px solid #000;
  189. border-radius: 40px;
  190. padding: 0 20px;
  191. position: relative;
  192. background-color: rgb(37, 51, 65);
  193. color: #fff;
  194. outline: none;
  195. }
  196. #tagsList {
  197. width: 350px;
  198. height: 250px;
  199. overflow-y: scroll;
  200. text-align: left;
  201. display: none;
  202. position: absolute;
  203. margin: 0 20px;
  204. z-index: 100;
  205. background-color: rgb(37, 51, 65);
  206. border: 1px solid rgba(29, 161, 242, 0.1);
  207. }
  208. .ins_list_item {
  209. cursor: pointer;
  210. color: #fff;
  211. padding-left: 5px;
  212. height: 25px;
  213. line-height: 25px;
  214. }
  215. .ins_highlight {
  216. background-color: #6699cc;
  217. }
  218. .ins_hide {
  219. display: none;
  220. }
  221. .ins_tag_span {
  222. color: #336699;
  223. }
  224. .my_note_btn_hide {
  225. display: none;
  226. }
  227. ol.script-list li:hover .my_twitter_note_btn {
  228. display: inline !important;
  229. }
  230. .expand_box {
  231. bottom: 0px;
  232. height: 50px;
  233. position: fixed;
  234. right: -50px;
  235. transition: 0.5s;
  236. width: 100px;
  237. z-index: 99;
  238. }
  239. .show_expand_box {
  240. right: 0;
  241. width: 50px;
  242. }
  243. #expandSpan {
  244. border-radius: 99px;
  245. border: 1px solid #00A1D6;
  246. bottom: 1vh;
  247. color: #FFF;
  248. cursor: pointer;
  249. display: block;
  250. font-size: 13px;
  251. height: 38px;
  252. line-height: 38px;
  253. position: absolute;
  254. right: 1vw;
  255. text-align: center;
  256. width: 38px;
  257. z-index: 98;
  258. background-image: ${ICON.SEARCH};
  259. background-repeat: no-repeat;
  260. background-size: 24px auto;
  261. background-position: center;
  262. }
  263. #my_search_bottom_layer_div {
  264. display: flex;
  265. position: fixed;
  266. background-color: rgba(0, 0, 0, .5);
  267. top: -50vh;
  268. bottom: 0;
  269. left: 0;
  270. right: 0;
  271. z-index: 100;
  272. align-items: center;
  273. justify-content: center;
  274. }
  275. `;
  276. var selector = {
  277. 'body': 'body',
  278. 'root': '#react-root div .r-13awgt0.r-12vffkv',
  279. 'homepage': {
  280. 'article': 'article',
  281. 'tool_bar': '.css-1dbjc4n.r-18u37iz.r-1wtj0ep.r-156q2ks.r-1mdbhws',
  282. 'show_name': '.css-901oao.css-bfa6kz.r-1qd0xha.r-a023e6.r-vw2c0b.r-ad9z0x.r-bcqeeo.r-3s2u2q.r-qvutc0 > span',
  283. 'id': '.css-901oao.css-bfa6kz.r-18u37iz.r-1qd0xha.r-a023e6.r-16dba41.r-ad9z0x.r-bcqeeo.r-qvutc0 > span',
  284. 'reprint_a': '.css-1dbjc4n.r-1iusvr4.r-16y2uox.r-5f2r5o.r-m611by a',
  285. 'reprint_name': '.css-1dbjc4n.r-1iusvr4.r-16y2uox.r-5f2r5o.r-m611by a > span > span',
  286. 'at': 'a.css-4rbku5.css-18t94o4.css-901oao.css-16my406.r-1loqt21.r-1qd0xha.r-ad9z0x.r-bcqeeo.r-qvutc0',
  287. 'user_frame': '.css-18t94o4.css-1dbjc4n.r-1ny4l3l.r-1j3t67a.r-1w50u8q.r-o7ynqc.r-6416eg',
  288. 'blockquote': 'div[role="blockquote"]'
  289. },
  290. 'userpage': {
  291. 'main_user_id': '.css-1dbjc4n.r-15d164r.r-1g94qm0 .css-1dbjc4n.r-18u37iz.r-1wbh5a2 > div > span',
  292. 'main': '.css-1dbjc4n.r-ku1wi2.r-1j3t67a.r-m611by',
  293. 'id': '.css-1dbjc4n.r-18u37iz.r-1wbh5a2 > div > span',
  294. 'follow': '.css-1dbjc4n.r-obd0qt.r-18u37iz.r-1w6e6rj.r-1h0z5md.r-dnmrzs',
  295. 'show_name': '.css-901oao.r-1qd0xha.r-1b6yd1w.r-1vr29t4.r-ad9z0x.r-bcqeeo.r-qvutc0 > span'
  296. },
  297. 'comment': {
  298. 'tool_bar': '.css-1dbjc4n.r-1oszu61.r-1efd50x.r-5kkj8d.r-18u37iz.r-ahm1il.r-a2tzq0'
  299. }
  300. };
  301. var modify_style = selector.homepage.show_name + ' { white-space: normal; }\n';
  302. class Twitter_Note {
  303. constructor(config, lang, show_list = []) {
  304. this.config = config;
  305. this.lang = lang;
  306. this.showList = show_list;
  307. }
  308. createNoteBtn(user_id, user_name, callback, class_name = "my_twitter_note_btn") {
  309. let btn = document.createElement('div');
  310. btn.className = class_name;
  311. if (this.judgeUsers(user_id)) {
  312. btn.title = this.lang.modify_button_title;
  313. } else {
  314. btn.title = this.lang.add_button_title;
  315. }
  316. btn.addEventListener('click', (event) => {
  317. event.stopPropagation();
  318. document.body.appendChild(this.createNoteFrame(user_id, user_name, () => {
  319. if (this.judgeUsers(user_id)) {
  320. btn.title = this.lang.modify_button_title;
  321. } else {
  322. btn.title = this.lang.add_button_title;
  323. }
  324. if (typeof(callback) == 'function') {
  325. callback();
  326. }
  327. }));
  328. });
  329. return btn;
  330. }
  331. doneHandle(user_id, ele, path_name, w = false) {
  332. if (w) {
  333. if (path_name) {
  334. if (ele.querySelector(path_name)) {
  335. let source_dom = ele.querySelector(path_name);
  336. if (this.judgeUsers(user_id)) {
  337. source_dom.textContent = this.getUserAtTag(user_id);
  338. } else {
  339. source_dom.textContent = user_id;
  340. }
  341. }
  342. } else {
  343. if (this.judgeUsers(user_id)) {
  344. ele.textContent = this.getUserAtTag(user_id);
  345. } else {
  346. ele.textContent = user_id;
  347. }
  348. }
  349. } else {
  350. if (path_name) {
  351. if (ele.querySelector(path_name + ' .ins_tag_span')) {
  352. let tag_dom = ele.querySelector(path_name + ' .ins_tag_span');
  353. if (this.judgeUsers(user_id)) {
  354. tag_dom.textContent = this.getUserFormatTag(user_id);
  355. } else {
  356. ele.querySelector(path_name).removeChild(tag_dom);
  357. }
  358. } else {
  359. if (this.judgeUsers(user_id)) {
  360. ele.querySelector(path_name).appendChild(this.createNoteSpan(user_id));
  361. }
  362. }
  363. } else {
  364. if (ele.querySelector('.ins_tag_span')) {
  365. let an_tag_dom = ele.querySelector('.ins_tag_span');
  366. if (this.judgeUsers(user_id)) {
  367. an_tag_dom.textContent = this.getUserFormatTag(user_id);
  368. } else {
  369. ele.removeChild(an_tag_dom);
  370. }
  371. } else {
  372. if (this.judgeUsers(user_id)) {
  373. ele.appendChild(this.createNoteSpan(user_id));
  374. }
  375. }
  376. }
  377. }
  378. }
  379. isUsersFromLink(link) {
  380. return /^\/[^/]+$/i.test(link.replace(location.origin, ""));
  381. }
  382. getUserIdFromLink(link) {
  383. return link.replace(location.origin + '/', '@');
  384. }
  385. judgeUsers(user_id) {
  386. if (this.getUserIndex(user_id) == -1) {
  387. return false;
  388. }
  389. return true;
  390. }
  391. getUserIndex(user_id) {
  392. for (let i in this.config.users_array) {
  393. if (user_id == this.config.users_array[i].id) {
  394. return i;
  395. }
  396. }
  397. return -1;
  398. }
  399. getUserTag(user_id) {
  400. if (this.judgeUsers(user_id)) {
  401. return this.config.users_array[this.getUserIndex(user_id)].tag;
  402. }
  403. return '';
  404. }
  405. getUserFormatTag(user_id) {
  406. if (this.judgeUsers(user_id)) {
  407. return '[' + this.getUserTag(user_id) + ']';
  408. }
  409. return '';
  410. }
  411. getUserAtTag(user_id) {
  412. if (this.judgeUsers(user_id)) {
  413. return '@' + this.getUserTag(user_id);
  414. }
  415. return '';
  416. }
  417. writeUsers(user_id, tag_value) {
  418. if (this.judgeUsers(user_id)) {
  419. let index = this.getUserIndex(user_id);
  420. if (tag_value) {
  421. this.config.users_array[index].tag = tag_value;
  422. } else {
  423. this.config.users_array.splice(index, 1);
  424. }
  425. } else {
  426. if (tag_value) {
  427. let temp_scripts_obj = {
  428. 'id': user_id,
  429. 'tag': tag_value
  430. };
  431. this.config.users_array.push(temp_scripts_obj);
  432. }
  433. }
  434. GM_setValue('twitter_config', this.config);
  435. }
  436. removeNoteFrame(frame_id = 'presentation_div_for_user') {
  437. let temp_ele = document.getElementById(frame_id);
  438. if (temp_ele) {
  439. temp_ele.parentNode.removeChild(temp_ele);
  440. }
  441. }
  442. createNoteFrame(user_id, user_name, callback) {
  443. let that = this;
  444. let presentation_div = document.createElement('div');
  445. presentation_div.id = 'presentation_div_for_user';
  446. presentation_div.addEventListener('click', function (event) {
  447. if (event.target === this) {
  448. that.removeNoteFrame();
  449. }
  450. });
  451. let dialog_div = document.createElement('div');
  452. dialog_div.className = 'dialog_div_for_user';
  453. let user_title_p = document.createElement('button');
  454. user_title_p.className = 'user_title_span_for_user';
  455. user_title_p.textContent = this.lang.user_id + user_id + '\n' + this.lang.user_name + user_name;
  456. let tag_input = document.createElement('input');
  457. tag_input.className = 'tag_input_for_user';
  458. tag_input.type = 'text';
  459. tag_input.placeholder = this.lang.input_placeholder;
  460. if (this.judgeUsers(user_id)) {
  461. tag_input.value = this.config.users_array[this.getUserIndex(user_id)].tag;
  462. } else {
  463. tag_input.value = '';
  464. }
  465. tag_input.addEventListener('keyup', (e) => {
  466. if (e.keyCode === 13) {
  467. this.writeUsers(user_id, tag_input.value);
  468. this.resetSearchFrame();
  469. if (typeof(callback) == 'function') {
  470. callback();
  471. }
  472. this.removeNoteFrame();
  473. }
  474. });
  475. setTimeout(function() {
  476. try {
  477. tag_input.focus();
  478. tag_input.select();
  479. } catch(e) {
  480. console.error(e);
  481. }
  482. }, 200);
  483. let save_button = document.createElement('button');
  484. save_button.className = 'button_for_user';
  485. save_button.type = 'button';
  486. save_button.innerText = this.lang.save_button_text;
  487. save_button.addEventListener('click', () => {
  488. this.writeUsers(user_id, tag_input.value);
  489. this.resetSearchFrame();
  490. if (typeof(callback) == 'function') {
  491. callback();
  492. }
  493. this.removeNoteFrame();
  494. });
  495. let clear_button = document.createElement('button');
  496. clear_button.className = 'button_for_user';
  497. clear_button.type = 'button';
  498. clear_button.innerText = this.lang.clear_button_text;
  499. clear_button.addEventListener('click', () => {
  500. this.writeUsers(user_id, '');
  501. this.resetSearchFrame();
  502. if (typeof(callback) == 'function') {
  503. callback();
  504. }
  505. this.removeNoteFrame();
  506. });
  507. let cancel_button = document.createElement('button');
  508. cancel_button.className = 'button_for_user cancel_button_for_user';
  509. cancel_button.type = 'button';
  510. cancel_button.innerText = this.lang.cancel_button_text;
  511. cancel_button.addEventListener('click', () => {
  512. this.removeNoteFrame();
  513. });
  514. dialog_div.appendChild(user_title_p);
  515. dialog_div.appendChild(tag_input);
  516. dialog_div.appendChild(save_button);
  517. dialog_div.appendChild(clear_button);
  518. dialog_div.appendChild(cancel_button);
  519. presentation_div.appendChild(dialog_div);
  520. return presentation_div;
  521. }
  522. resetSearchFrame() {
  523. let tags_list = document.getElementById('tagsList');
  524. if (tags_list) {
  525. tags_list.innerHTML = "";
  526. this.config.users_array.forEach((item, index) => {
  527. tags_list.appendChild(this.createListDiv(index, item));
  528. });
  529. }
  530. }
  531. removeSearchFrame(frame_id = 'my_search_bottom_layer_div') {
  532. let search_frame = document.getElementById(frame_id);
  533. if (search_frame) {
  534. search_frame.parentNode.removeChild(search_frame);
  535. }
  536. }
  537. cretaeSearchFrame() {
  538. let that = this;
  539. let bottom_layer_div = document.createElement('div');
  540. bottom_layer_div.id = 'my_search_bottom_layer_div';
  541. bottom_layer_div.addEventListener('click', function(event) {
  542. if (event.target === this) {
  543. that.removeSearchFrame();
  544. }
  545. });
  546. let search_frame = document.createElement('div');
  547. search_frame.id = 'searchFrame';
  548. bottom_layer_div.appendChild(search_frame);
  549. let search_input = document.createElement('input');
  550. search_input.id = 'myInputSearch';
  551. search_input.type = 'text';
  552. search_input.placeholder = this.lang.search_placeholder;
  553. search_input.value = "";
  554. search_input.addEventListener('focusin', () => {
  555. document.getElementById('tagsList').classList.add('list_show');
  556. this.searchEvent(search_input);
  557. });
  558. setTimeout(function() {
  559. try {
  560. search_input.focus();
  561. search_input.select();
  562. } catch(e) {
  563. console.error(e);
  564. }
  565. }, 200);
  566. search_frame.appendChild(search_input);
  567. let tags_list = document.createElement('div');
  568. tags_list.id = 'tagsList';
  569. for (let i = 0; i < this.config.users_array.length; i ++) {
  570. tags_list.appendChild(this.createListDiv(i, this.config.users_array[i]));
  571. }
  572. search_frame.appendChild(tags_list);
  573. return bottom_layer_div;
  574. }
  575. createListDiv(id_number, users_obj) {
  576. let list_div = document.createElement('div');
  577. list_div.id = 'tags_' + id_number;
  578. list_div.className = 'ins_list_item';
  579. list_div.textContent = users_obj.tag;
  580. list_div.addEventListener('mouseenter', function() {
  581. for (let ele of document.querySelectorAll('#tagsList div')) {
  582. ele.classList.remove('ins_highlight');
  583. }
  584. this.classList.add('ins_highlight');
  585. });
  586. list_div.addEventListener('click', function() {
  587. location.pathname = users_obj.id.replace(/^@/, '/');
  588. });
  589. return list_div;
  590. }
  591. searchEvent(input_dom) {
  592. let list_arr = [];
  593. for (let ele of document.querySelectorAll('#tagsList div')) {
  594. let arr_obj = {
  595. 'eleContainer': ele.textContent,
  596. 'ele': ele
  597. };
  598. list_arr.push(arr_obj);
  599. }
  600. let current_index = 0;
  601. input_dom.addEventListener('keyup', (event) => {
  602. document.getElementById('tagsList').classList.add('list_show');
  603. let search_val;
  604. switch (event.keyCode) {
  605. case 38:
  606. case 40:
  607. case 37:
  608. case 39:
  609. event.returnValue = false;
  610. break;
  611. case 13:
  612. this.showList[current_index].click();
  613. break;
  614. default:
  615. search_val = input_dom.value;
  616. this.showList = [];
  617. list_arr.forEach((item) => {
  618. if (item.eleContainer.indexOf(search_val) !== -1) {
  619. item.ele.classList.remove('ins_hide');
  620. this.showList.push(item.ele);
  621. } else {
  622. item.ele.classList.add('ins_hide');
  623. }
  624. });
  625. current_index = 0;
  626. break;
  627. }
  628. this.showList.forEach(function(item, index) {
  629. if (index === current_index) {
  630. item.classList.add('ins_highlight');
  631. document.getElementById('tagsList').scrollTop = item.offsetTop;
  632. } else {
  633. item.classList.remove('ins_highlight');
  634. }
  635. });
  636. let list_height = 25 * this.showList.length;
  637. if (list_height < 250) {
  638. document.getElementById('tagsList').style.height = list_height + 'px';
  639. } else {
  640. document.getElementById('tagsList').style.height = '250px';
  641. }
  642. });
  643. input_dom.addEventListener('keydown', (event) => {
  644. if (event.keyCode === 38) {
  645. current_index --;
  646. if (current_index < 0) {
  647. current_index = 0;
  648. }
  649. } else if (event.keyCode === 40) {
  650. current_index ++;
  651. if (current_index >= this.showList.length) {
  652. current_index = this.showList.length - 1;
  653. }
  654. }
  655. this.showList.forEach(function(item, index) {
  656. if (index === current_index) {
  657. item.classList.add('ins_highlight');
  658. document.getElementById('tagsList').scrollTop = item.offsetTop;
  659. } else {
  660. item.classList.remove('ins_highlight');
  661. }
  662. });
  663. });
  664. }
  665. createNoteSpan(user_id, an_class_name = "") {
  666. let note_span = document.createElement('span');
  667. note_span.className = 'ins_tag_span';
  668. if (an_class_name) {
  669. note_span.classList.add(an_class_name);
  670. }
  671. note_span.textContent = this.getUserFormatTag(user_id);
  672. return note_span;
  673. }
  674. }
  675. function save_Event(user_id, note_obj) {
  676. for (let ele of document.querySelectorAll(selector.homepage.article)) {
  677. let ele_id = "";
  678. if (ele.querySelector(selector.homepage.id)) {
  679. ele_id = ele.querySelector(selector.homepage.id).textContent;
  680. }
  681. let ele_reprint_id = "";
  682. if (ele.querySelector(selector.homepage.reprint_a)) {
  683. ele_reprint_id = note_obj.getUserIdFromLink(ele.querySelector(selector.homepage.reprint_a).href);
  684. }
  685. if (ele_id == user_id) {
  686. note_obj.doneHandle(user_id, ele, selector.homepage.show_name);
  687. }
  688. if (ele_reprint_id == user_id) {
  689. note_obj.doneHandle(user_id, ele, selector.homepage.reprint_name);
  690. }
  691. for (let ele_at_user of ele.querySelectorAll(selector.homepage.at)) {
  692. if (note_obj.isUsersFromLink(ele_at_user.href)) {
  693. let ele_at_user_id = note_obj.getUserIdFromLink(ele_at_user.href);
  694. if (ele_at_user_id == user_id) {
  695. note_obj.doneHandle(user_id, ele_at_user, "", true);
  696. }
  697. }
  698. }
  699. }
  700. for (let user_ele of document.querySelectorAll(selector.userpage.main)) {
  701. let user_ele_id = user_ele.querySelector(selector.userpage.id).textContent;
  702. if (user_ele_id == user_id) {
  703. note_obj.doneHandle(user_id, user_ele, selector.userpage.show_name);
  704. }
  705. }
  706. for (let user_frame_ele of document.querySelectorAll(selector.homepage.user_frame)) {
  707. let user_frame_ele_id = user_frame_ele.querySelector(selector.userpage.id).textContent;
  708. if (user_frame_ele_id == user_id) {
  709. note_obj.doneHandle(user_id, user_frame_ele, selector.homepage.show_name);
  710. }
  711. }
  712. for (let blockquote_ele of document.querySelectorAll(selector.homepage.blockquote)) {
  713. let blockquote_ele_id = blockquote_ele.querySelector(selector.homepage.id).textContent;
  714. if (blockquote_ele_id == user_id) {
  715. note_obj.doneHandle(user_id, blockquote_ele, selector.homepage.show_name);
  716. }
  717. }
  718. }
  719. function init(twitter_config) {
  720. let style_dom = document.createElement('style');
  721. style_dom.type = 'text/css';
  722. style_dom.innerHTML = STYLE_VALUE;
  723. document.body.appendChild(style_dom);
  724. let modify_style_dom = document.createElement('style');
  725. modify_style_dom.type = 'text/css';
  726. modify_style_dom.innerHTML = modify_style;
  727. document.body.appendChild(modify_style_dom);
  728. let lang_str = document.documentElement.lang;
  729. let lang_value;
  730. switch (lang_str) {
  731. case 'zh':
  732. case 'zh-cn':
  733. case 'zh-CN':
  734. lang_value = LANG.ZH_CN;
  735. break;
  736. case 'zh-hk':
  737. case 'zh-HK':
  738. case 'zh-tw':
  739. case 'zh-TW':
  740. case 'zh-Hant':
  741. lang_value = LANG.ZH_TW;
  742. break;
  743. case 'en':
  744. default:
  745. lang_value = LANG.EN;
  746. break;
  747. }
  748. let note_obj = new Twitter_Note(twitter_config, lang_value);
  749. let expand_box = document.createElement('div');
  750. expand_box.className = 'expand_box';
  751. expand_box.onmouseenter = function() {
  752. this.classList.add('show_expand_box');
  753. };
  754. expand_box.onmouseleave = function() {
  755. this.classList.remove('show_expand_box');
  756. };
  757. let search_btn = document.createElement('span');
  758. search_btn.id = 'expandSpan';
  759. search_btn.title = note_obj.lang.search_placeholder;
  760. search_btn.addEventListener('click', function(event) {
  761. event.stopPropagation();
  762. document.body.appendChild(note_obj.cretaeSearchFrame());
  763. });
  764. expand_box.appendChild(search_btn);
  765. document.body.appendChild(expand_box);
  766. document.querySelector(selector.root).arrive(selector.homepage.article, {fireOnAttributesModification: true, existing: true}, function() {
  767. if (this.querySelector(selector.homepage.id)) {
  768. let user_id = this.querySelector(selector.homepage.id).textContent;
  769. let user_name = this.querySelector(selector.homepage.show_name).textContent;
  770. if (this.querySelector(selector.homepage.tool_bar)) {
  771. this.querySelector(selector.homepage.tool_bar).appendChild(note_obj.createNoteBtn(user_id, user_name, function() {
  772. save_Event(user_id, note_obj);
  773. }, 'my_twitter_note_btn base_tool_bar_btn css-1dbjc4n'));
  774. }
  775. if (this.querySelector(selector.comment.tool_bar)) {
  776. this.querySelector(selector.comment.tool_bar).appendChild(note_obj.createNoteBtn(user_id, user_name, function() {
  777. save_Event(user_id, note_obj);
  778. }, 'my_twitter_note_btn comment_tool_bar_btn css-1dbjc4n'));
  779. }
  780. note_obj.doneHandle(user_id, this, selector.homepage.show_name);
  781. }
  782. if (this.querySelector(selector.homepage.reprint_a)) {
  783. let reprint_id = note_obj.getUserIdFromLink(this.querySelector(selector.homepage.reprint_a).href);
  784. note_obj.doneHandle(reprint_id, this, selector.homepage.reprint_name);
  785. }
  786. if (this.querySelector(selector.homepage.blockquote)) {
  787. let blockquote_user = this.querySelector(selector.homepage.blockquote);
  788. let blockquote_user_id = blockquote_user.querySelector(selector.homepage.id).textContent;
  789. note_obj.doneHandle(blockquote_user_id, blockquote_user, selector.homepage.show_name);
  790. }
  791. for (let at_user of this.querySelectorAll(selector.homepage.at)) {
  792. if (note_obj.isUsersFromLink(at_user.href)) {
  793. let at_user_id = note_obj.getUserIdFromLink(at_user.href);
  794. note_obj.doneHandle(at_user_id, at_user, "", true);
  795. }
  796. }
  797. });
  798. document.querySelector(selector.root).arrive(selector.userpage.main, {fireOnAttributesModification: true, existing: true}, function() {
  799. let user_id = this.querySelector(selector.userpage.id).textContent;
  800. let user_name = this.querySelector(selector.userpage.show_name).textContent;
  801. var follow_note_btn;
  802. if (this.querySelector(selector.userpage.follow)) {
  803. follow_note_btn = note_obj.createNoteBtn(user_id, user_name, function() {
  804. save_Event(user_id, note_obj);
  805. }, 'my_before_follow_note_btn css-901oao');
  806. this.querySelector(selector.userpage.follow).insertAdjacentElement('afterbegin', follow_note_btn);
  807. }
  808. note_obj.doneHandle(user_id, this, selector.userpage.show_name);
  809. let user_id_change = new MutationObserver(() => {
  810. let new_user_id = this.querySelector(selector.userpage.id).textContent;
  811. note_obj.doneHandle("", this, selector.userpage.show_name);
  812. let new_user_name = this.querySelector(selector.userpage.show_name).textContent;
  813. if (follow_note_btn) {
  814. follow_note_btn.parentNode.removeChild(follow_note_btn);
  815. follow_note_btn = note_obj.createNoteBtn(new_user_id, new_user_name, function() {
  816. save_Event(new_user_id, note_obj);
  817. }, 'my_before_follow_note_btn css-901oao');
  818. this.querySelector(selector.userpage.follow).insertAdjacentElement('afterbegin', follow_note_btn);
  819. }
  820. note_obj.doneHandle(new_user_id, this, selector.userpage.show_name);
  821. });
  822. let user_id_change_container = this.querySelector(selector.userpage.main_user_id);
  823. let user_id_change_option = {
  824. 'subtree': true,
  825. 'characterData': true
  826. };
  827. user_id_change.observe(user_id_change_container, user_id_change_option);
  828. });
  829. document.querySelector(selector.root).arrive(selector.homepage.user_frame, {fireOnAttributesModification: true, existing: true}, function() {
  830. let user_id = this.querySelector(selector.userpage.id).textContent;
  831. note_obj.doneHandle(user_id, this, selector.homepage.show_name);
  832. });
  833. }
  834. Promise.all([GM_getValue('twitter_config')]).then(function(data) {
  835. let twitter_config = {
  836. users_array: []
  837. };
  838. if (data[0] !== undefined) {
  839. twitter_config = data[0];
  840. }
  841. init(twitter_config);
  842. }).catch(function(e) {
  843. console.error('Script error.');
  844. console.error(e);
  845. });
  846. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址