InoReader Filter

Highlight or remove articles in Inoreader. / Inoreaderの記事を消去もしくは強調表示します。

  1. // ==UserScript==
  2. // @name InoReader Filter
  3. // @description Highlight or remove articles in Inoreader. / Inoreaderの記事を消去もしくは強調表示します。
  4. // @description:en Highlight or remove articles in InoReader.
  5. // @description:ja Inoreaderの記事を消去もしくは強調表示します。
  6. // @namespace https://userscripts.org/scripts/show/352673
  7. // @homepage https://greasyfork.org/scripts/895-inoreader-filter
  8. // @match https://*.inoreader.com/*
  9. // @exclude *inoreader.com/stream*
  10. // @exclude *inoreader.com/m/*
  11. // @grant GM_registerMenuCommand
  12. // @noframes
  13. // @version 1.24
  14. // ==/UserScript==
  15.  
  16. (() => {
  17. 'use strict';
  18.  
  19. if (!/Ino\s?Reader/i.test(document.title)) return;
  20. let appVersion = 0,
  21. aNgTextarea = [],
  22. aNg = [],
  23. aNgId = [],
  24. aHiTextarea = [],
  25. aHi = [],
  26. aHiId = [],
  27. aAd = [],
  28. aAdId = [],
  29. aAdTemp,
  30. bExclude = false,
  31. nArticles = 0,
  32. nExcludes = 0,
  33. nUnread = 0,
  34. nUnreadEx = 0,
  35. st = {},
  36. LOC;
  37. const reAd =
  38. '^\\s*(?:ad|pr|広告)\\s*[::]|^\\s*[\\[[【](?:ad|pr|広告)[\\]]】]|[\\[[【](?:ad|pr|広告)[\\]]】]\\s*$|[::]\\s*(?:ad|pr|広告)\\s*$',
  39. $id = function (id) {
  40. return document.getElementById(id);
  41. },
  42. notType = function (t, a) {
  43. return Object.prototype.toString.call(a).slice(8, 11) !== t
  44. ? true
  45. : false;
  46. },
  47. target = $id('reader_pane'),
  48. config = {
  49. childList: true,
  50. },
  51. config2 = {
  52. childList: true,
  53. subtree: true,
  54. };
  55.  
  56. const convertRules = () => {
  57. aNg = [];
  58. aHi = [];
  59. aNgTextarea = st.ngdata ? st.ngdata.split(/\r\n|\n|\r/) : [];
  60. aHiTextarea = st.hidata ? st.hidata.split(/\r\n|\n|\r/) : [];
  61. const wildcardToRegexp = function (s) {
  62. return s
  63. .replace(/~\*/g, '<InoReaderFilterAM>')
  64. .replace(/~\?/g, '<InoReaderFilterQM>')
  65. .replace(/[.+^=!:${}()|[\]/\\]/g, '\\$&')
  66. .replace(/\*/g, '.*')
  67. .replace(/\?/g, '.')
  68. .replace(/<InoReaderFilterAM>/g, '\\*')
  69. .replace(/<InoReaderFilterQM>/g, '\\?');
  70. },
  71. a = [aNg, aNgTextarea, aHi, aHiTextarea];
  72. for (let n = 0, m = a.length; n < m; n = n + 2) {
  73. for (let i = 0, j = a[n + 1].length; i < j; i++) {
  74. const str = a[n + 1][i];
  75. let sFeed = '',
  76. sTitle = '',
  77. sText = '';
  78. a[n][i] = {};
  79. a[n][i].feedPattern = '';
  80. a[n][i].feedFlag = '';
  81. a[n][i].titlePattern = '';
  82. a[n][i].titleFlag = '';
  83. a[n][i].textPattern = '';
  84. a[n][i].textFlag = '';
  85. a[n][i].task = '';
  86. if (str.indexOf(st.delimiter) !== -1) {
  87. const arr = str.split(st.delimiter);
  88. sFeed = arr[0];
  89. if (arr.length === 2) sText = arr[1];
  90. else if (arr.length > 2) {
  91. sTitle = arr[1];
  92. sText = str.slice(
  93. arr[0].length + arr[1].length + st.delimiter.length * 2
  94. );
  95. if (!arr[1]) a[n][i].task = 'text';
  96. }
  97. } else sText = str;
  98. if (sFeed) {
  99. if (/^\/.+\/g?i?y?$/.test(sFeed)) {
  100. a[n][i].feedPattern = sFeed.slice(
  101. sFeed.indexOf('/') + 1,
  102. sFeed.lastIndexOf('/')
  103. );
  104. a[n][i].feedFlag = sFeed.slice(sFeed.lastIndexOf('/') + 1);
  105. } else a[n][i].feedPattern = wildcardToRegexp(sFeed);
  106. }
  107. if (sTitle) {
  108. if (/^\/.+\/g?i?y?$/.test(sTitle)) {
  109. a[n][i].titlePattern = sTitle.slice(
  110. sTitle.indexOf('/') + 1,
  111. sTitle.lastIndexOf('/')
  112. );
  113. a[n][i].titleFlag = sTitle.slice(sTitle.lastIndexOf('/') + 1);
  114. } else a[n][i].titlePattern = wildcardToRegexp(sTitle);
  115. }
  116. if (sText) {
  117. if (/^\/.+\/g?i?y?$/.test(sText)) {
  118. a[n][i].textPattern = sText.slice(
  119. sText.indexOf('/') + 1,
  120. sText.lastIndexOf('/')
  121. );
  122. a[n][i].textFlag = sText.slice(sText.lastIndexOf('/') + 1);
  123. } else a[n][i].textPattern = wildcardToRegexp(sText);
  124. }
  125. }
  126. }
  127. };
  128.  
  129. const checkArticle = (a, ft, at, du, tdu) => {
  130. const feed = a.feedPattern,
  131. title = a.titlePattern,
  132. text = a.textPattern,
  133. task = a.task;
  134. if ((!title && !text) || /^\s+$/.test(title + text)) return false;
  135. const bFeed = new RegExp(feed, `${a.feedFlag}m`).test(ft),
  136. bTitle = new RegExp(title, a.titleFlag).test(at),
  137. bDU = new RegExp(text, `${a.textFlag}m`).test(du),
  138. bTDU = new RegExp(text, `${a.textFlag}m`).test(tdu);
  139. if (!feed) {
  140. if (!title && bDU && task === 'text') return `DU: ${text}`;
  141. if (!title && bTDU && !task) return `TDU: ${text}`;
  142. if (bTitle && !text) return `T: ${title}`;
  143. if (bTitle && bDU) return `T: ${title} DU: ${text}`;
  144. }
  145. if (bFeed) {
  146. if (!title && bDU && task === 'text') {
  147. return `F: ${feed} DU: ${text}`;
  148. }
  149. if (!title && bTDU && !task) return `F: ${feed} TDU: ${text}`;
  150. if (bTitle && !text) return `F: ${feed} T: ${title}`;
  151. if (bTitle && bDU) return `F: ${feed} T: ${title} DU: ${text}`;
  152. }
  153. return '';
  154. };
  155.  
  156. const currentArticle = () => {
  157. if (target) return target.getElementsByClassName('article_current');
  158. return [];
  159. };
  160.  
  161. const currentExpandedArticle = () => {
  162. if (target) {
  163. return target.getElementsByClassName('article_current article_expanded');
  164. }
  165. return [];
  166. };
  167.  
  168. const currentTreeName = () => {
  169. const tlf = document
  170. .getElementById('tree')
  171. .getElementsByClassName('selected');
  172. if (tlf.length && tlf[0] && tlf[0].textContent) return tlf[0].textContent;
  173. return '';
  174. };
  175.  
  176. const articleData = (e) => {
  177. const o = {};
  178. o.sId = '';
  179. o.sFeed = '';
  180. o.sTitle = '';
  181. o.sDesc = '';
  182. o.sUrl = '';
  183. o.sDate = '';
  184. o.bUnread = false;
  185. o.sId = e && e.id ? e.id.slice(e.id.lastIndexOf('_') + 1) : '';
  186. if (!o.sId) return o;
  187. const eArticleFeed =
  188. $id(`article_feed_info_link_${o.sId}`) ||
  189. e.getElementsByClassName('article_feed_title')[0] ||
  190. e.querySelector('.article_tile_footer_feed_title > a'),
  191. eArticleTitle =
  192. $id(`at_${o.sId}`) ||
  193. $id(`article_title_link_inline_${o.sId}`) ||
  194. e.getElementsByClassName('article_title_link')[0] ||
  195. e.getElementsByClassName('article_magazine_title_link')[0],
  196. eArticleDesc =
  197. $id(`article_contents_inner_${o.sId}`) ||
  198. $id(`article_short_contents_${o.sId}`) ||
  199. e.getElementsByClassName('article_short_contents')[0] ||
  200. e.getElementsByClassName('article_tile_content')[0],
  201. eArticleUrl =
  202. $id(`aurl_${o.sId}`) ||
  203. $id(`burl_${o.sId}`) ||
  204. $id(`article_title_link_${o.sId}`),
  205. eArticleDate =
  206. $id(`header_date_${o.sId}`) ||
  207. $id(`header_date_tile_${o.sId}`) ||
  208. e.getElementsByClassName('article_sub_date')[0] ||
  209. e.getElementsByClassName('article_magazine_date')[0];
  210. o.sFeed = eArticleFeed ? eArticleFeed.textContent : currentTreeName();
  211. o.sTitle = eArticleTitle ? eArticleTitle.textContent : '';
  212. o.sDesc = eArticleDesc ? eArticleDesc.textContent : '';
  213. o.sUrl =
  214. eArticleUrl && eArticleUrl.hasAttribute('href')
  215. ? eArticleUrl.getAttribute('href')
  216. : '';
  217. o.sDate =
  218. eArticleDate && eArticleDate.hasAttribute('title')
  219. ? eArticleDate.getAttribute('title').trim()
  220. : '';
  221. if (/^\s+$/.test(o.sFeed)) o.sFeed = '';
  222. if (/^\s+$/.test(o.sTitle)) o.sTitle = '';
  223. if (/^\s+$/.test(o.sDesc)) o.sDesc = '';
  224. if (/^\s+$/.test(o.sUrl)) o.sUrl = '';
  225. if (/^\s+$/.test(o.sDate)) o.sDate = '';
  226. if (o.sDesc) {
  227. o.sDesc = o.sDesc.replace(/^\s+-\s+(.+)/, '$1').replace(/(.+)\s+$/, '$1');
  228. }
  229. if (o.sDate?.length >= 20) {
  230. o.sDate = o.sDate.slice(o.sDate.lastIndexOf(': ') + 2);
  231. }
  232. if (e.classList.contains('article_unreaded')) o.bUnread = true;
  233. return o;
  234. };
  235.  
  236. const changedArticles = () => {
  237. if (!target) return;
  238. const articles = target.getElementsByClassName('ar'),
  239. treeTitle = currentTreeName(),
  240. eAc = currentExpandedArticle(),
  241. eUct =
  242. appVersion < 14
  243. ? $id('unread_cnt_top')
  244. : document.querySelector('#show_articles_menu label[for="option_0"]');
  245. let bFoundCurrentArticle = false,
  246. eExpandedCurrentArticle,
  247. nCnt = 0,
  248. aCnt;
  249. if (!articles.length || nArticles > articles.length + nExcludes + 3) {
  250. aHiId = [];
  251. aNgId = [];
  252. aAdId = [];
  253. bExclude = false;
  254. nArticles = 0;
  255. nExcludes = 0;
  256. nUnread = 0;
  257. nUnreadEx = 0;
  258. return;
  259. }
  260. if (eAc.length) eExpandedCurrentArticle = eAc[0];
  261. if (eUct && eUct.textContent && articles.length + nExcludes) {
  262. aCnt = eUct.textContent.match(/\d+/);
  263. if (aCnt && aCnt.length) {
  264. nCnt = Number(aCnt[0]);
  265. if (
  266. nCnt !== 1000 &&
  267. nCnt !== 10000 &&
  268. (!nUnread || nCnt !== nUnread - nUnreadEx)
  269. ) {
  270. nUnread = nCnt;
  271. }
  272. }
  273. }
  274. nArticles = articles.length + nExcludes;
  275. loop1: for (let n1 = 0, l1 = articles.length; n1 < l1; n1++) {
  276. if (n1 === 0 && !st.hi && !st.ng) break;
  277. const eArticle = articles[n1],
  278. oA = articleData(eArticle);
  279. if (!oA.sId) continue;
  280. if (eArticle === eExpandedCurrentArticle) bFoundCurrentArticle = true;
  281. if (st.hi) {
  282. for (let n2 = 0, l2 = aHiId.length; n2 < l2; n2++) {
  283. if (oA.sId === aHiId[n2]) continue loop1;
  284. }
  285. }
  286. if (st.ng) {
  287. for (let n3 = 0, l3 = aNgId.length; n3 < l3; n3++) {
  288. if (oA.sId === aNgId[n3]) {
  289. if (oA.bUnread) nUnreadEx += 1;
  290. nExcludes += 1;
  291. continue loop1;
  292. }
  293. }
  294. }
  295. if (st.ad) {
  296. for (let n4 = 0, l4 = aAdId.length; n4 < l4; n4++) {
  297. if (oA.sId === aAdId[n4]) {
  298. if (oA.bUnread) nUnreadEx += 1;
  299. nExcludes += 1;
  300. continue loop1;
  301. }
  302. }
  303. }
  304. if (treeTitle) oA.sFeed += `\n${treeTitle}`;
  305. const sArticleDU = `${oA.sDesc}\n${oA.sUrl}`,
  306. sArticleTDU = `${oA.sTitle}\n${oA.sDesc}\n${oA.sUrl}`;
  307. let sCa = '';
  308. if (st.hi) {
  309. for (let i1 = 0, j1 = aHi.length; i1 < j1; i1++) {
  310. sCa = checkArticle(
  311. aHi[i1],
  312. oA.sFeed,
  313. oA.sTitle,
  314. sArticleDU,
  315. sArticleTDU
  316. );
  317. if (sCa) {
  318. if (st.log) {
  319. console.log('highlight: ', oA.sTitle, ' / matching rule ', sCa);
  320. }
  321. $id(`article_${oA.sId}`).classList.add(
  322. 'inoreader_filter_highlight'
  323. );
  324. aHiId.push(oA.sId);
  325. continue loop1;
  326. }
  327. }
  328. }
  329. if (bExclude) break;
  330. if (st.ad) {
  331. const sT = oA.sTitle
  332. .replace(/^\s*(?:ad|pr|広告)\s?[::]\s*(.+)$/i, '$1')
  333. .replace(/^\s*[[[【](?:ad|pr|広告)[\]]】]\s*(.+)$/i, '$1')
  334. .replace(/^(.+)\s*[[[【](?:ad|pr|広告)[\]]】]\s*$/i, '$1');
  335. for (let i2 = 0, j2 = aAd.length, a; i2 < j2; i2++) {
  336. if (
  337. !aAd[i2] ||
  338. notType('Str', aAd[i2]) ||
  339. aAd[i2].indexOf('<>') === -1
  340. ) {
  341. continue;
  342. } else if (
  343. aAd[i2].slice(0, aAd[i2].lastIndexOf('<>')).indexOf(sT) !== -1
  344. ) {
  345. a = aAd[i2].slice(aAd[i2].lastIndexOf('<>') + 2).split('@');
  346. if (
  347. (!eAc.length || bFoundCurrentArticle) &&
  348. a.length === 2 &&
  349. Number(a[1]) &&
  350. $id(`article_${oA.sId}`) !== eExpandedCurrentArticle
  351. ) {
  352. if (st.log) console.log('remove ad: ', oA.sTitle);
  353. target.removeChild($id(`article_${oA.sId}`));
  354. aAdId.push(oA.sId);
  355. if (oA.bUnread) nUnreadEx += 1;
  356. nExcludes += 1;
  357. n1 -= 1;
  358. l1 -= 1;
  359. continue loop1;
  360. }
  361. }
  362. }
  363. }
  364. if (st.ng) {
  365. if (
  366. st.ad &&
  367. new RegExp(st.adfilter, 'im').test(`${oA.sTitle}\n${oA.sDesc}`) &&
  368. oA.sDate &&
  369. (oA.sDate.length <= 5 ||
  370. (oA.sDate.length > 5 &&
  371. new Date(oA.sDate).getTime() + 86400000 * 60 > Date.now()))
  372. ) {
  373. continue;
  374. }
  375. for (let i3 = 0, j3 = aNg.length; i3 < j3; i3++) {
  376. sCa = checkArticle(
  377. aNg[i3],
  378. oA.sFeed,
  379. oA.sTitle,
  380. sArticleDU,
  381. sArticleTDU
  382. );
  383. if (sCa) {
  384. if (st.log) {
  385. console.log('remove: ', oA.sTitle, ' / matching rule ', sCa);
  386. }
  387. target.removeChild($id(`article_${oA.sId}`));
  388. aNgId.push(oA.sId);
  389. if (oA.bUnread) nUnreadEx += 1;
  390. nExcludes += 1;
  391. n1 -= 1;
  392. l1 -= 1;
  393. continue loop1;
  394. }
  395. }
  396. }
  397. }
  398. if (!eUct?.hasAttribute('data-irf_ngcheck')) changedNumberOfUnreadArticles();
  399. if (appVersion < 14) {
  400. observer2.observe($id('unread_cnt_top'), config);
  401. } else {
  402. observer2.observe($id('header_pane'), config2);
  403. }
  404. };
  405. const observer1 = new MutationObserver(changedArticles);
  406.  
  407. const changedNumberOfUnreadArticles = () => {
  408. if (st.ngcount === 2) return;
  409. observer2.disconnect();
  410. const eUct =
  411. appVersion < 14
  412. ? $id('unread_cnt_top')
  413. : document.querySelector('#show_articles_menu label[for="option_0"]');
  414. if (!eUct) return;
  415. let nDeduct = nUnread ? nUnread - nUnreadEx : 0,
  416. nCnt = 0,
  417. aCnt;
  418. eUct.removeAttribute('data-irf_ngcount');
  419. if (st.ngcount === 0) {
  420. if (nUnreadEx) {
  421. eUct.setAttribute('data-irf_ngcount', `(${nUnreadEx})`);
  422. }
  423. } else if (st.ngcount === 1) {
  424. aCnt = eUct.textContent.match(/\d+/);
  425. if (aCnt && aCnt.length) {
  426. nCnt = Number(aCnt[0]);
  427. if (nCnt !== 1000 && nCnt !== 10000) {
  428. nUnread = nCnt;
  429. nDeduct = nUnread ? nUnread - nUnreadEx : 0;
  430. if (nDeduct < 0) nDeduct = 0;
  431. eUct.textContent = eUct.textContent.replace(
  432. /([^\d]*)\d+([^\d]*)/,
  433. `$1${nDeduct}$2`
  434. );
  435. }
  436. }
  437. }
  438. if (nArticles >= 50 && nExcludes / nArticles >= 0.8) {
  439. if (!bExclude) window.alert(LOC.t30);
  440. bExclude = true;
  441. }
  442. observer2.observe(eUct, config);
  443. eUct.setAttribute('data-irf_ngcheck', '1');
  444. };
  445. const observer2 = new MutationObserver(changedNumberOfUnreadArticles);
  446.  
  447. const createAdtable = (type, flag) => {
  448. let html = '';
  449. const at = aAdTemp || flag ? aAdTemp.concat() : aAd.concat();
  450. switch (Number(type)) {
  451. case 0:
  452. at.sort((a, b) => {
  453. const tA = a.slice(0, a.lastIndexOf('<>')),
  454. tB = b.slice(0, b.lastIndexOf('<>'));
  455. if (tA > tB) return 1;
  456. if (tA < tB) return -1;
  457. return 0;
  458. });
  459. break;
  460. case 1:
  461. at.sort((a, b) => {
  462. const tA = a.slice(0, a.lastIndexOf('<>')),
  463. tB = b.slice(0, b.lastIndexOf('<>'));
  464. if (tA < tB) return 1;
  465. if (tA > tB) return -1;
  466. return 0;
  467. });
  468. break;
  469. case 2:
  470. at.sort((a, b) => {
  471. const nA = a.slice(a.lastIndexOf('<>') + 2, -2),
  472. nB = b.slice(b.lastIndexOf('<>') + 2, -2);
  473. return Number(nB) - Number(nA);
  474. });
  475. break;
  476. case 3:
  477. at.sort((a, b) => {
  478. const nA = a.slice(a.lastIndexOf('<>') + 2, -2),
  479. nB = b.slice(b.lastIndexOf('<>') + 2, -2);
  480. return Number(nA) - Number(nB);
  481. });
  482. break;
  483. }
  484. for (let i = 0, j = at.length, a, t, d; i < j; i++) {
  485. if (!at[i] || notType('Str', at[i]) || at[i].indexOf('<>') === -1) {
  486. continue;
  487. }
  488. t = at[i].slice(0, at[i].lastIndexOf('<>'));
  489. a = at[i].slice(at[i].lastIndexOf('<>') + 2).split('@');
  490. d = a.length === 2 && Number(a[0]) >= 0 ? a[0] : '';
  491. if (!d) continue;
  492. html += `<div class="irf_tr"><div class="irf_ad_td1"><label><input id="irf_ad_switch_${d}" type="checkbox"${
  493. Number(a[1]) ? ' checked' : ''
  494. } value="${a[1]}" /><span title="${LOC.t22} : ${new Date(
  495. Number(a[0])
  496. ).toLocaleString()}">${t}</span></label></div><div class="irf_ad_td2"><input id="irf_ad_remove_${d}" type="button" value="${
  497. LOC.t12
  498. }" /></div></div>`;
  499. }
  500. $id('irf_ad_table').innerHTML = html;
  501. };
  502.  
  503. const getAppVersion = () => {
  504. const extractNumber = (str) => {
  505. if (typeof str !== 'string' || str === '') return 0;
  506. const [first, second] = str.split('.');
  507. return first && second ? parseFloat(`${first}.${second}`) : 0;
  508. };
  509. try {
  510. /* global application_version */
  511. /* @ts-expect-error */
  512. appVersion = extractNumber(application_version);
  513. } catch (e) {
  514. if (st.log) console.log('getAppVersion', e);
  515. }
  516. };
  517.  
  518. const setSettingsTab = (s) => {
  519. for (let t = ['ng', 'hi', 'ad', 'etc'], i = 0; i < 4; i++) {
  520. $id(`irf_tab_${t[i]}`).classList.remove('irf_tab_selected');
  521. $id(`irf_form_${t[i]}`).style.display = 'none';
  522. }
  523. $id(`irf_tab_${s}`).classList.add('irf_tab_selected');
  524. $id(`irf_form_${s}`).style.display = 'block';
  525. if (s === 'ng' || s === 'hi') {
  526. if ($id(`irf_${s}_add_word`).getBoundingClientRect().left > 0) {
  527. $id(`irf_${s}_add_word`).focus();
  528. } else if ($id(`irf_${s}_ta`).getBoundingClientRect().left > 0) {
  529. $id(`irf_${s}_ta`).focus();
  530. }
  531. }
  532. };
  533.  
  534. const settingsMode = (s) => {
  535. const e = $id('irf_settings').getElementsByClassName('irf_advance');
  536. for (let i = 0, j = e.length; i < j; i++) {
  537. if (s === 'simple') e[i].classList.add('inoreader_filter_hide');
  538. else if (s === 'advance') e[i].classList.remove('inoreader_filter_hide');
  539. }
  540. };
  541.  
  542. const viewSettings = () => {
  543. const se = $id('irf_settings');
  544. if (!se) return;
  545. if (se.style.display !== 'block') {
  546. setSettingsTab('ng');
  547. $id('irf_ng_add_bt').classList.add('inoreader_filter_hide');
  548. $id('irf_hi_add_bt').classList.add('inoreader_filter_hide');
  549. $id('irf_ng_fill_bt').classList.remove('inoreader_filter_hide');
  550. $id('irf_hi_fill_bt').classList.remove('inoreader_filter_hide');
  551. $id('irf_ng_cb').checked = st.ng;
  552. $id('irf_hi_cb').checked = st.hi;
  553. $id('irf_ad_cb').checked = st.ad;
  554. if (st.ng) $id('irf_ng_fs').removeAttribute('disabled');
  555. else $id('irf_ng_fs').setAttribute('disabled', '');
  556. if (st.hi) $id('irf_hi_fs').removeAttribute('disabled');
  557. else $id('irf_hi_fs').setAttribute('disabled', '');
  558. $id('irf_ng_add_word').value = '';
  559. $id('irf_hi_add_word').value = '';
  560. $id('irf_ng_add_feed').value = '';
  561. $id('irf_hi_add_feed').value = '';
  562. $id('irf_ng_add_title').value = '';
  563. $id('irf_hi_add_title').value = '';
  564. $id('irf_ng_ta').value = st.ngdata;
  565. $id('irf_hi_ta').value = st.hidata;
  566. $id('irf_ad_filter').value = st.adfilter;
  567. $id('irf_ad_sort_type')[Number(st.adsort)].selected = true;
  568. if (st.mode === 'simple') $id('irf_etc_mode-s').checked = true;
  569. else if (st.mode === 'advance') $id('irf_etc_mode-a').checked = true;
  570. $id('irf_etc_key_settings').value = st.keywindow;
  571. $id('irf_etc_delimiter').value = st.delimiter;
  572. $id('irf_etc_ngcount')[Number(st.ngcount)].selected = true;
  573. $id('irf_etc_log').checked = st.log;
  574. aAdTemp = null;
  575. createAdtable(st.adsort);
  576. settingsMode(st.mode);
  577. se.style.display = 'block';
  578. if ($id('irf_ng_add_word').getBoundingClientRect().left > 0) {
  579. $id('irf_ng_add_word').focus();
  580. } else if ($id('irf_ng_ta').getBoundingClientRect().left > 0) {
  581. $id('irf_ng_ta').focus();
  582. }
  583. } else {
  584. se.style.display = 'none';
  585. $id('irf_ok').removeAttribute('disabled');
  586. }
  587. };
  588.  
  589. const loadSettings = () => {
  590. st = {};
  591. try {
  592. st = JSON.parse(localStorage.getItem('InoReaderFilter_settings')) || {};
  593. } catch (er) {
  594. if (st.log) console.log('loadSettings', er);
  595. alert('InoReaderFilter Error: Load Settings');
  596. }
  597. if (notType('Num', st.format)) st.format = 1;
  598. if (notType('Boo', st.ng)) st.ng = true;
  599. if (notType('Boo', st.hi)) st.hi = true;
  600. if (notType('Boo', st.ad)) st.ad = true;
  601. if (notType('Str', st.ngdata)) st.ngdata = '';
  602. if (notType('Str', st.hidata)) st.hidata = '';
  603. if (notType('Str', st.adfilter)) st.adfilter = reAd;
  604. if (notType('Num', st.adcount)) st.adcount = 0;
  605. if (notType('Num', st.adsort)) st.adsort = 0;
  606. if (notType('Str', st.mode)) st.mode = 'simple';
  607. if (notType('Str', st.keywindow)) st.keywindow = 'F';
  608. if (notType('Str', st.delimiter)) st.delimiter = '<>';
  609. if (notType('Num', st.ngcount)) st.ngcount = 0;
  610. if (notType('Boo', st.log)) st.log = false;
  611. convertRules();
  612. };
  613.  
  614. const saveSettings = (flag) => {
  615. try {
  616. localStorage.setItem('InoReaderFilter_settings', JSON.stringify(st));
  617. } catch (er) {
  618. if (st.log) console.log('saveSettings', er);
  619. alert('InoReaderFilter Error: Save Settings');
  620. }
  621. if (!flag) convertRules();
  622. };
  623.  
  624. const loadAddata = () => {
  625. try {
  626. aAd = JSON.parse(localStorage.getItem('InoReaderFilter_addata')) || [];
  627. } catch (er) {
  628. if (st.log) console.log('loadAddata', er);
  629. alert('InoReaderFilter Error: Load AdData');
  630. }
  631. };
  632.  
  633. const saveAddata = (a) => {
  634. if (aAdTemp) {
  635. aAd = aAdTemp.concat();
  636. aAdTemp = null;
  637. }
  638. try {
  639. localStorage.setItem('InoReaderFilter_addata', JSON.stringify(a));
  640. } catch (er) {
  641. if (st.log) console.log('saveAddata', er);
  642. alert('InoReaderFilter Error: Save AdData');
  643. }
  644. loadAddata();
  645. };
  646.  
  647. const init = () => {
  648. if (!target) return;
  649. getAppVersion();
  650. loadSettings();
  651. loadAddata();
  652. let CSS =
  653. '#unread_cnt_top:after { content: attr(data-irf_ngcount); margin-left: 2px; opacity: 0.75; }' +
  654. '.inoreader_filter_highlight span[id^="at_"], .inoreader_filter_highlight a[id^="article_title_link_"], .inoreader_filter_highlight .article_title_link, .inoreader_filter_highlight.article_unreaded .article_header_title, .inoreader_filter_highlight.article_tile.article_unreaded .article_title_link, .inoreader_filter_highlight.article_unreaded .article_magazine_title_link { color: #B65F06; }' +
  655. '.high_contrast .inoreader_filter_highlight span[id^="at_"], .high_contrast .inoreader_filter_highlight a[id^="article_title_link_"], .high_contrast .inoreader_filter_highlight .article_title_link, .high_contrast .inoreader_filter_highlight.article_unreaded .article_header_title, .high_contrast .inoreader_filter_highlight.article_tile.article_unreaded .article_title_link, .high_contrast .inoreader_filter_highlight.article_unreaded .article_magazine_title_link { color: #D66F16; }' +
  656. '.inoreader_filter_hide { display: none; }' +
  657. '#irf_settings { display: none; color: black; padding: 0; position: absolute; top: 48px; left: 48px; z-index: 90300; background: rgba(255, 255, 255, 0.98); border: 1px solid #999999; border-radius: 4px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); min-width: 20em; -moz-user-select: none; -webkit-user-select: none; font-size: 13px; position: fixed; }' +
  658. '#irf_settings input[type="text"], #irf_settings textarea { padding: 0 2px; }' +
  659. '#irf_settings input[type="button"] { font-size: 90%; height: 2em; }' +
  660. '#irf_settings input[type=checkbox] { position: static; opacity: 1; pointer-events: auto; }' +
  661. '#irf_settings select { font-size: 100%; padding: 1px 2px; }' +
  662. '#irf_settings fieldset { border: 1px solid #CCCCCC }' +
  663. '#irf_settings fieldset, #irf_settings input[type="text"], #irf_settings input[type="number"], #irf_settings textarea { color: black; background-color: transparent; }' +
  664. '#irf_settings legend { font-size: 13px; margin: 0; }' +
  665. '#irf_titlebar { background-color: #666666; border-radius: 4px 4px 0 0; padding: 2px 0 0 4px; height: 2em; }' +
  666. '#irf_title a { font-weight: bold; color: white; text-decoration: none; }' +
  667. '#irf_title a:hover { color: #FF9; }' +
  668. '#irf_title_btn { position: absolute; top: 2px; right: 4px; }' +
  669. '#irf_desc { padding: 0 0.5em; margin: 0.5em 0 1em 0; }' +
  670. '#irf_tab { padding: 0 0.5em; margin-top: 1em; }' +
  671. '#irf_tab span { background-color: #E9E9E9; background-image: -webkit-linear-gradient(#F9F9F9, #E9E9E9); background-image: linear-gradient(#F9F9F9, #E9E9E9); border: 1px solid #999999; padding: 3px 16px; border-radius: 4px 4px 0 0; cursor: pointer; }' +
  672. '#irf_tab span:hover { background-color: #F3F3F3; }' +
  673. '#irf_tab .irf_tab_selected, #irf_tab .irf_tab_selected:hover { background-color: #FFFFFF; background-image: none; border-bottom-color: #FFFFFF; }' +
  674. '#irf_form { padding: 8px 4px 4px 4px; border-top: 1px solid #999999; margin-top: 2px; }' +
  675. '#irf_form input[type="checkbox"], #irf_form input[type="radio"] { vertical-align: inherit; }' +
  676. '#irf_form input[type="checkbox"] { margin: 2px 4px 2px 0; }' +
  677. '#irf_form label { vertical-align: top; }' +
  678. '#irf_form textarea { margin: 0; width: 100%; height: 200px; }' +
  679. '#irf_form input, #irf_form textarea { color: black; }' +
  680. '#irf_form fieldset { padding: 4px; margin: 0 0 0.5em 0; border-color: #999; min-width: 490px; }' +
  681. '#irf_form fieldset:disabled > label { color: gray; }' +
  682. '#irf_form fieldset:disabled input, #irf_form fieldset:disabled textarea { color: #666666; background-color: #EEEEEE; }' +
  683. '#irf_form fieldset + fieldset { margin: 0.5em auto; }' +
  684. '#irf_form_hi, #irf_form_ad, #irf_form_etc { display: none; }' +
  685. '#irf_form_etc input[type="checkbox"] { margin: 2px 4px 2px 2px; }' +
  686. '.irf_form_add-row-button { text-align: right; }' +
  687. '.irf_form_add-row-input + .irf_form_add-row-caption, .irf_form_add-row-input + .irf_form_add-row-button { margin-top: 0.5em; }' +
  688. '.irf_form_add-row-textarea { margin-top: 1em; }' +
  689. '.inoreader_filter_hide + .irf_form_add-row-textarea { margin-top: 0; }' +
  690. '.irf_form_add-input { width: 95%; }' +
  691. '.irf_form_add-button:active { position:relative; top:1px; }' +
  692. '.irf_table_wrapper { max-height: 400px; overflow-y: scroll; }' +
  693. '.irf_table { display: table; width: 100%; }' +
  694. '.irf_tr { display: table-row; border: 1px solid red; }' +
  695. '.irf_tr:hover div { background-color: #EFEFEF; }' +
  696. '#irf_ad_sort { margin-left: 2em; font-weight: normal; }' +
  697. '#irf_ad_sort_type { padding: 0; margin-top: -4px; }' +
  698. '.irf_ad_td1, .irf_ad_td2 { display: table-cell; padding: 4px 2px; }' +
  699. '.irf_ad_td1 { max-width: 50em; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }' +
  700. '.irf_ad_td2 { width: 5em; }' +
  701. '.irf_ad_td2 input { width: 4.8em; }' +
  702. '#irf_etc_key_settings { width: 7ex; text-align: center; margin: 0 0.5em; }' +
  703. '#irf_ok { margin-right: 0.5em; padding: 0 2em; }' +
  704. '#irf_cancel { padding: 0 1ex; }' +
  705. '#irf_ok, #irf_cancel { width: 8em; }' +
  706. '.irf_form_add-button { width: 12em; }' +
  707. '#irf_form textarea, .irf_form_add-input { width: -moz-available; width: -webkit-fill-available; width: available; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }';
  708. if ($id('sb_rp_settings_menu')) {
  709. CSS +=
  710. '.inoreader_filter_adarticle:before { font-family: "InoReader-UI-Icons-Font"; content: "\\e684"; padding-right: 5px; }';
  711. } else if ($id('read_articles_button')) {
  712. const img = $id('read_articles_button').firstChild;
  713. if (img && img.hasAttribute('src')) {
  714. CSS += `.inoreader_filter_adarticle:before { background: url("${img.getAttribute(
  715. 'src'
  716. )}") no-repeat; content: " "; padding: 0 10px; }`;
  717. }
  718. }
  719. const style = document.createElement('style');
  720. style.textContent = CSS;
  721. document.head.appendChild(style);
  722. const LOCALE_JA = {
  723. t00: '設定',
  724. t01: 'OK',
  725. t02: 'キャンセル',
  726. t03: 'NGワード',
  727. t04: 'ハイライト',
  728. t05: '広告記事',
  729. t06: 'その他',
  730. t07: 'フィード・フォルダ・タグ',
  731. t08: '記事タイトル',
  732. t09: '記事タイトル・記事概要・記事URL',
  733. t10: '記事概要・記事URL',
  734. t11: 'ルールを追加',
  735. t12: '削除',
  736. t13: '設定モード',
  737. t14: 'シンプル',
  738. t15: 'アドバンス',
  739. t16: '区切り文字',
  740. t17: 'コンソールにログを表示',
  741. t18: '選択記事をフォームに記入',
  742. t19: '累計',
  743. t20: 'ソート',
  744. t21: 'タイトル',
  745. t22: '登録日時',
  746. t23: '昇順',
  747. t24: '降順',
  748. t25: '新しい順',
  749. t26: '古い順',
  750. t27: 'ショートカットキー',
  751. t28: '設定欄の開閉',
  752. t29: 'キー',
  753. t30: '消去した記事が多すぎるので、InoReader Filterは記事を消去する機能を一時的に無効化しました。NGワードの設定を確認して下さい。',
  754. t31: 'ルール',
  755. t32: '正規表現',
  756. t33: 'NG記事数',
  757. t34: '未読記事数の後にNG記事数を表示する',
  758. t35: '未読記事数からNG記事数を差し引く',
  759. t36: 'NG記事数は表示しない',
  760. };
  761. const LOCALE_EN = {
  762. t00: 'Settings',
  763. t01: 'OK',
  764. t02: 'Cancel',
  765. t03: 'Exclude words',
  766. t04: 'Highlight words',
  767. t05: 'Advertising articles',
  768. t06: 'Etc',
  769. t07: 'Feed, folder, tag',
  770. t08: 'Article title',
  771. t09: 'Article title, summary, url',
  772. t10: 'Article summary, url',
  773. t11: 'Add rule',
  774. t12: 'Remove',
  775. t13: 'Settings mode',
  776. t14: 'Simple',
  777. t15: 'Advanced',
  778. t16: 'Delimiter',
  779. t17: 'Logging to console',
  780. t18: 'Fill in the selected article',
  781. t19: 'cumulative total',
  782. t20: 'Sort by',
  783. t21: 'Title',
  784. t22: 'Registered date',
  785. t23: 'A-Z',
  786. t24: 'Z-A',
  787. t25: 'newest',
  788. t26: 'oldest',
  789. t27: 'Shortcut keys',
  790. t28: 'Open/close the settings',
  791. t29: 'key',
  792. t30: 'Articles that was removed is too many. InoReader Filter has temporarily disabled the ability to remove the articles. Please check the settings of the exclude words.',
  793. t31: 'Rule',
  794. t32: 'regular expression',
  795. t33: 'The number of remove articles',
  796. t34: 'Show the number of remove articles after the number of unread articles',
  797. t35: 'Subtracting the number of remove articles from the number of unread articles',
  798. t36: 'Do not show the number of remove articles',
  799. };
  800. LOC = /^ja$|^ja-jp$/i.test(window.navigator.language)
  801. ? LOCALE_JA
  802. : LOCALE_EN;
  803.  
  804. const div = document.createElement('div');
  805. let html = `<div id="irf_titlebar"><div id="irf_title"><a href="https://greasyfork.org/scripts/895-inoreader-filter" target="_blank">InoReader Filter ${LOC.t00}</a></div><div id="irf_title_btn"><input id="irf_ok" type="button" value="${LOC.t01}" /><input id="irf_cancel" type="button" value="${LOC.t02}" /></div></div><div id="irf_tab"><span id="irf_tab_ng" class="irf_tab_selected">${LOC.t03}</span><span id="irf_tab_hi">${LOC.t04}</span><span id="irf_tab_ad" class="irf_advance">${LOC.t05}</span><span id="irf_tab_etc">${LOC.t06}</span></div><div id="irf_form">`;
  806. html += `<div id="irf_form_ng"><fieldset id="irf_ng_fs"><legend><label><input id="irf_ng_cb" type="checkbox" />${LOC.t03}</label></legend><div class="irf_advance"><div class="irf_form_add-row-caption">${LOC.t07} :</div><div class="irf_form_add-row-input"><input id="irf_ng_add_feed" class="irf_form_add-input" type="input" /></div><div class="irf_form_add-row-caption">${LOC.t08} :</div><div class="irf_form_add-row-input"><input id="irf_ng_add_title" class="irf_form_add-input" type="input" /></div><div id="irf_ng_add_word-caption" class="irf_form_add-row-caption">${LOC.t09} :</div><div class="irf_form_add-row-input"><input id="irf_ng_add_word" class="irf_form_add-input" type="input" /></div><div class="irf_form_add-row-button"><input id="irf_ng_fill_bt" class="irf_form_fill-button" value="${LOC.t18}" type="button" /><input id="irf_ng_add_bt" class="irf_form_add-button" value="${LOC.t11}" type="button" /></div></div><div class="irf_form_add-row-textarea"><textarea id="irf_ng_ta"></textarea></div></fieldset></div>`;
  807. html += `<div id="irf_form_hi"><fieldset id="irf_hi_fs"><legend><label><input id="irf_hi_cb" type="checkbox" />${LOC.t04}</label></legend><div class="irf_advance"><div class="irf_form_add-row-caption">${LOC.t07} :</div><div class="irf_form_add-row-input"><input id="irf_hi_add_feed" class="irf_form_add-input" type="input" /></div><div class="irf_form_add-row-caption">${LOC.t08} :</div><div class="irf_form_add-row-input"><input id="irf_hi_add_title" class="irf_form_add-input" type="input" /></div><div id="irf_hi_add_word-caption" class="irf_form_add-row-caption">${LOC.t09} :</div><div class="irf_form_add-row-input"><input id="irf_hi_add_word" class="irf_form_add-input" type="input" /></div><div class="irf_form_add-row-button"><input id="irf_hi_fill_bt" class="irf_form_fill-button" value="${LOC.t18}" type="button" /><input id="irf_hi_add_bt" class="irf_form_add-button" value="${LOC.t11}" type="button" /></div></div><div class="irf_form_add-row-textarea"><textarea id="irf_hi_ta"></textarea></div></fieldset></div>`;
  808. html += `<div id="irf_form_ad" class="irf_advance"><fieldset id="irf_ad_filter_fs"><legend>${LOC.t31} (${LOC.t32})</legend><input id="irf_ad_filter" class="irf_form_add-input" type="text"></fieldset><fieldset id="irf_ad_fs"><legend id="irf_ad_legend" title="${LOC.t19} : ${st.adcount}"><label><input id="irf_ad_cb" type="checkbox" />${LOC.t05}</label><span id="irf_ad_sort">( ${LOC.t20} : <select id="irf_ad_sort_type"><option value="0">${LOC.t21} ( ${LOC.t23} )</option><option value="1">${LOC.t21} ( ${LOC.t24} )</option><option value="2">${LOC.t22} ( ${LOC.t25} )</option><option value="3">${LOC.t22} ( ${LOC.t26} )</option></select> )</span></legend><div id="irf_ad_table_wrapper" class="irf_table_wrapper"><div id="irf_ad_table" class="irf_table"></div></div></fieldset></div>`;
  809. html += `<div id="irf_form_etc"><fieldset id="irf_etc_mode_fs"><legend>${LOC.t13}</legend><label><input id="irf_etc_mode-s" name="irf_etc_mode_r" type="radio" value="simple" />${LOC.t14}</label><label><input id="irf_etc_mode-a" name="irf_etc_mode_r" type="radio" value="advance" />${LOC.t15}</label></fieldset><div class="irf_advance"><fieldset><legend>${LOC.t27}</legend><label>${LOC.t28} : Ctrl+Shift+<input id="irf_etc_key_settings" type="text" maxlength="1" />${LOC.t29}</label></fieldset><fieldset id="irf_etc_delimiter_fs"><legend>${LOC.t16}</legend><input id="irf_etc_delimiter" type="input" /></fieldset><fieldset><legend>${LOC.t33}</legend><select id="irf_etc_ngcount"><option value="0">${LOC.t34}</option><option value="1">${LOC.t35}</option><option value="2">${LOC.t36}</option></select></fieldset><label><input id="irf_etc_log" type="checkbox">${LOC.t17}</label></div></div>`;
  810. html += '</div>';
  811. div.innerHTML = html;
  812. div.id = 'irf_settings';
  813. document.body.appendChild(div);
  814.  
  815. for (let i = 0, a; i < aAd.length; i++) {
  816. if (!aAd[i] || notType('Str', aAd[i]) || aAd[i].indexOf('<>') === -1) {
  817. continue;
  818. }
  819. a = aAd[i].slice(aAd[i].lastIndexOf('<>') + 2).split('@');
  820. if (
  821. a.length === 2 &&
  822. Date.now() > new Date(Number(a[0]) + 86400000 * 60).getTime()
  823. ) {
  824. if (st.log) {
  825. console.log(
  826. 'unregister ad: ',
  827. aAd[i].slice(0, aAd[i].lastIndexOf('<>'))
  828. );
  829. }
  830. aAd.splice(i, 1);
  831. }
  832. }
  833. saveAddata(aAd);
  834.  
  835. const addRule = (f, t, w) => {
  836. let word = '';
  837. if (f) {
  838. word = f + st.delimiter;
  839. if (t) {
  840. word += t + st.delimiter;
  841. if (w) word += w;
  842. } else if (w) word += st.delimiter + w;
  843. } else if (t) {
  844. word = st.delimiter + t + st.delimiter;
  845. if (w) word += w;
  846. } else if (w) word = w;
  847. return `${word}\n`;
  848. };
  849.  
  850. const clickAddButton = (s) => {
  851. const sF = $id(`irf_${s}_add_feed`).value,
  852. sT = $id(`irf_${s}_add_title`).value,
  853. sW = $id(`irf_${s}_add_word`).value;
  854. if (!sT && !sW) return;
  855. const sData = $id(`irf_${s}_ta`).value,
  856. sRule = addRule(sF, sT, sW);
  857. if (sData.indexOf(sRule) === -1) {
  858. $id(`irf_${s}_ta`).value +=
  859. !sData || /(?:\r\n|\n|\r)$/.test(sData) ? sRule : `\n${sRule}`;
  860. }
  861. $id(`irf_${s}_add_feed`).value = '';
  862. $id(`irf_${s}_add_title`).value = '';
  863. $id(`irf_${s}_add_word`).value = '';
  864. $id(`irf_${s}_add_word-caption`).textContent = `${LOC.t09} :`;
  865. if (s === 'ng') {
  866. $id('irf_ng_add_bt').classList.add('inoreader_filter_hide');
  867. $id('irf_ng_fill_bt').classList.remove('inoreader_filter_hide');
  868. } else if (s === 'hi') {
  869. $id('irf_hi_add_bt').classList.add('inoreader_filter_hide');
  870. $id('irf_hi_fill_bt').classList.remove('inoreader_filter_hide');
  871. }
  872. };
  873.  
  874. const checkAd = () => {
  875. if (!target) return;
  876. const eAc = currentExpandedArticle();
  877. if (!eAc.length) return;
  878. const sId = eAc[0].id
  879. ? eAc[0].id.slice(eAc[0].id.lastIndexOf('_') + 1)
  880. : '';
  881. if (!sId) return;
  882. const eTitle = $id(`at_${sId}`) || $id(`article_title_link_${sId}`),
  883. sTitle = eTitle ? eTitle.textContent : '';
  884. let bUnregistered = true;
  885. if (!sTitle) return;
  886. for (let i = 0, j = aAd.length; i < j; i++) {
  887. if (!aAd[i] || notType('Str', aAd[i]) || aAd[i].indexOf('<>') === -1) {
  888. continue;
  889. }
  890. if (sTitle === aAd[i].slice(0, aAd[i].lastIndexOf('<>'))) {
  891. bUnregistered = false;
  892. break;
  893. }
  894. }
  895. if (bUnregistered && new RegExp(st.adfilter, 'im').test(sTitle)) {
  896. aAd.push(`${sTitle}<>${Date.now()}@1`);
  897. aAd.sort((a, b) => {
  898. return a - b;
  899. });
  900. if ($id(`at_${sId}`)) {
  901. $id(`at_${sId}`).classList.add('inoreader_filter_adarticle');
  902. }
  903. if ($id(`article_title_link_${sId}`)) {
  904. $id(`article_title_link_${sId}`).classList.add(
  905. 'inoreader_filter_adarticle'
  906. );
  907. }
  908. if (st.log) console.log('register ad: ', sTitle);
  909. saveAddata(aAd);
  910. st.adcount += 1;
  911. saveSettings(true);
  912. $id('irf_ad_legend').setAttribute(
  913. 'title',
  914. `${LOC.t19} : ${st.adcount}`
  915. );
  916. changedArticles();
  917. }
  918. };
  919.  
  920. const escRe = (s) => s.replace(/[.+^=!:${}()|[\]/\\]/g, '\\$&');
  921.  
  922. $id('irf_settings').addEventListener(
  923. 'click',
  924. (e) => {
  925. const tId = e.target.id;
  926. if (!tId) return;
  927. if (
  928. e.target.nodeName === 'INPUT' &&
  929. e.target.getAttribute('type') === 'button'
  930. ) {
  931. e.target.blur();
  932. }
  933. if (tId === 'irf_ok') {
  934. let problem = false;
  935. const adfilter = $id('irf_ad_filter').value,
  936. delim = $id('irf_etc_delimiter').value,
  937. keyWin = $id('irf_etc_key_settings').value;
  938. st.ng = $id('irf_ng_cb').checked;
  939. st.ngdata = $id('irf_ng_ta').value;
  940. st.hi = $id('irf_hi_cb').checked;
  941. st.hidata = $id('irf_hi_ta').value;
  942. st.ad = $id('irf_ad_cb').checked;
  943. st.adfilter = adfilter ? adfilter : reAd;
  944. st.adsort = $id('irf_ad_sort_type').selectedIndex;
  945. st.ngcount = $id('irf_etc_ngcount').selectedIndex;
  946. if ($id('irf_etc_mode-s').checked) st.mode = 'simple';
  947. else if ($id('irf_etc_mode-a').checked) st.mode = 'advance';
  948. if (keyWin.length === 1) {
  949. if (/^[A-Za-z0-9]$/.test(keyWin)) {
  950. st.keywindow = keyWin.toUpperCase();
  951. } else {
  952. problem = true;
  953. setSettingsTab('etc');
  954. $id('irf_etc_key_settings').focus();
  955. }
  956. } else {
  957. $id('irf_etc_key_settings').value = 'F';
  958. st.keywindow = 'F';
  959. }
  960. if (delim) {
  961. if (/[.+^=!:${}()|[\]/\\]/.test(delim)) {
  962. problem = true;
  963. setSettingsTab('etc');
  964. $id('irf_etc_delimiter').focus();
  965. } else st.delimiter = $id('irf_etc_delimiter').value;
  966. } else st.delimiter = '<>';
  967. st.log = $id('irf_etc_log').checked;
  968. if (!problem) {
  969. viewSettings();
  970. saveSettings();
  971. saveAddata(aAdTemp ? aAdTemp : aAd);
  972. }
  973. } else if (tId === 'irf_cancel') {
  974. viewSettings();
  975. } else if (tId.indexOf('irf_tab_') !== -1) {
  976. const sId = tId.slice(tId.indexOf('irf_tab_') + 8);
  977. if (sId) setSettingsTab(sId);
  978. } else if (tId.indexOf('irf_etc_mode-') !== -1) {
  979. if (tId === 'irf_etc_mode-s') settingsMode('simple');
  980. else if (tId === 'irf_etc_mode-a') settingsMode('advance');
  981. } else if (/^irf_(?:ng|hi)_fill_bt$/.test(tId)) {
  982. const eAc = currentArticle(),
  983. sT = currentTreeName();
  984. let sF = '',
  985. sW = '';
  986. if (!eAc.length) return;
  987. const oA = articleData(eAc[0]);
  988. if (sT && oA.sFeed && sT !== oA.sFeed) {
  989. sF = `/^${escRe(sT)}$|^${escRe(oA.sFeed)}$/`;
  990. } else if (sT) sF = sT;
  991. else if (oA.sFeed) sF = oA.sFeed;
  992. if (oA.sDesc) {
  993. sW = `/^${escRe(oA.sDesc)}$|^${escRe(oA.sUrl)}$/`;
  994. } else sW = oA.sUrl;
  995. if (tId === 'irf_ng_fill_bt') {
  996. $id('irf_ng_add_feed').value = sF;
  997. $id('irf_ng_add_title').value = oA.sTitle;
  998. $id('irf_ng_add_word').value = sW;
  999. $id('irf_ng_add_bt').classList.remove('inoreader_filter_hide');
  1000. $id('irf_ng_fill_bt').classList.add('inoreader_filter_hide');
  1001. } else if (tId === 'irf_hi_fill_bt') {
  1002. $id('irf_hi_add_feed').value = sF;
  1003. $id('irf_hi_add_title').value = oA.sTitle;
  1004. $id('irf_hi_add_word').value = sW;
  1005. $id('irf_hi_add_bt').classList.remove('inoreader_filter_hide');
  1006. $id('irf_hi_fill_bt').classList.add('inoreader_filter_hide');
  1007. }
  1008. } else if (tId === 'irf_ng_add_bt') {
  1009. clickAddButton('ng');
  1010. } else if (tId === 'irf_hi_add_bt') {
  1011. clickAddButton('hi');
  1012. } else if (/^irf_ad_switch_|^irf_ad_remove_/.test(tId)) {
  1013. if (!aAdTemp) aAdTemp = aAd.concat();
  1014. for (let i = 0, j = aAdTemp.length, a, d; i < j; i++) {
  1015. if (
  1016. !aAdTemp[i] ||
  1017. notType('Str', aAdTemp[i]) ||
  1018. aAdTemp[i].indexOf('<>') === -1
  1019. ) {
  1020. continue;
  1021. }
  1022. a = aAdTemp[i].slice(aAdTemp[i].lastIndexOf('<>') + 2).split('@');
  1023. d = a.length === 2 && Number(a[0]) >= 0 ? a[0] : '';
  1024. if (d && tId.slice(14) === d) {
  1025. if (/^irf_ad_switch_/.test(tId)) {
  1026. aAdTemp[i] = aAdTemp[i].replace(
  1027. /@\d$/,
  1028. `@${a[1] === '1' ? '0' : '1'}`
  1029. );
  1030. } else if (/^irf_ad_remove_/.test(tId)) {
  1031. aAdTemp.splice(i, 1);
  1032. }
  1033. createAdtable($id('irf_ad_sort_type').selectedIndex, true);
  1034. break;
  1035. }
  1036. }
  1037. }
  1038. },
  1039. false
  1040. );
  1041.  
  1042. $id('irf_ng_cb').addEventListener(
  1043. 'click',
  1044. (e) => {
  1045. if (e.target.checked) $id('irf_ng_fs').removeAttribute('disabled');
  1046. else $id('irf_ng_fs').setAttribute('disabled', '');
  1047. },
  1048. false
  1049. );
  1050.  
  1051. $id('irf_hi_cb').addEventListener(
  1052. 'click',
  1053. (e) => {
  1054. if (e.target.checked) $id('irf_hi_fs').removeAttribute('disabled');
  1055. else $id('irf_hi_fs').setAttribute('disabled', '');
  1056. },
  1057. false
  1058. );
  1059.  
  1060. $id('irf_titlebar').addEventListener(
  1061. 'dblclick',
  1062. (e) => {
  1063. if (e.target.nodeName === 'DIV') {
  1064. $id('irf_tab').classList.toggle('inoreader_filter_hide');
  1065. $id('irf_form').classList.toggle('inoreader_filter_hide');
  1066. $id('irf_title_btn').classList.toggle('inoreader_filter_hide');
  1067. }
  1068. },
  1069. false
  1070. );
  1071.  
  1072. $id('irf_settings').addEventListener(
  1073. 'input',
  1074. (e) => {
  1075. if (e.target.id === 'irf_ng_add_title') {
  1076. if (e.target.value) {
  1077. $id('irf_ng_add_word-caption').textContent = `${LOC.t10} :`;
  1078. } else $id('irf_ng_add_word-caption').textContent = `${LOC.t09} :`;
  1079. } else if (e.target.id === 'irf_hi_add_title') {
  1080. if (e.target.value) {
  1081. $id('irf_hi_add_word-caption').textContent = `${LOC.t10} :`;
  1082. } else $id('irf_hi_add_word-caption').textContent = `${LOC.t09} :`;
  1083. }
  1084. if ($id('irf_tab_ng').classList.contains('irf_tab_selected')) {
  1085. if (
  1086. $id('irf_ng_add_feed').value ||
  1087. $id('irf_ng_add_title').value ||
  1088. $id('irf_ng_add_word').value
  1089. ) {
  1090. $id('irf_ng_add_bt').classList.remove('inoreader_filter_hide');
  1091. $id('irf_ng_fill_bt').classList.add('inoreader_filter_hide');
  1092. } else {
  1093. $id('irf_ng_add_bt').classList.add('inoreader_filter_hide');
  1094. $id('irf_ng_fill_bt').classList.remove('inoreader_filter_hide');
  1095. }
  1096. } else if ($id('irf_tab_hi').classList.contains('irf_tab_selected')) {
  1097. if (
  1098. $id('irf_hi_add_feed').value ||
  1099. $id('irf_hi_add_title').value ||
  1100. $id('irf_hi_add_word').value
  1101. ) {
  1102. $id('irf_hi_add_bt').classList.remove('inoreader_filter_hide');
  1103. $id('irf_hi_fill_bt').classList.add('inoreader_filter_hide');
  1104. } else {
  1105. $id('irf_hi_add_bt').classList.add('inoreader_filter_hide');
  1106. $id('irf_hi_fill_bt').classList.remove('inoreader_filter_hide');
  1107. }
  1108. }
  1109. },
  1110. false
  1111. );
  1112.  
  1113. $id('irf_ad_sort_type').addEventListener(
  1114. 'change',
  1115. () => {
  1116. createAdtable($id('irf_ad_sort_type').selectedIndex);
  1117. },
  1118. false
  1119. );
  1120.  
  1121. $id('reader_pane').addEventListener(
  1122. 'click',
  1123. () => {
  1124. checkAd();
  1125. },
  1126. true
  1127. );
  1128.  
  1129. document.addEventListener(
  1130. 'keyup',
  1131. (e) => {
  1132. if (e.ctrlKey && e.shiftKey && e.key === st.keywindow) {
  1133. viewSettings();
  1134. } else if (/input|textarea/i.test(e.target.tagName)) return;
  1135. checkAd();
  1136. },
  1137. true
  1138. );
  1139. try {
  1140. GM_registerMenuCommand(`${LOC.t00}`, () => viewSettings());
  1141. } catch (e) {
  1142. if (st.log) console.log('GM_registerMenuCommand', e);
  1143. }
  1144.  
  1145. changedArticles();
  1146. changedNumberOfUnreadArticles();
  1147. observer1.observe(target, config);
  1148. if (appVersion < 14) {
  1149. observer2.observe($id('unread_cnt_top'), config);
  1150. } else {
  1151. observer2.observe($id('header_pane'), config2);
  1152. }
  1153. };
  1154.  
  1155. const initInterval = window.setInterval(() => {
  1156. const tree = $id('tree');
  1157. if (/ino\s?reader/i.test(document.title) && tree?.innerHTML) {
  1158. window.clearInterval(initInterval);
  1159. window.setTimeout(() => init(), 1000);
  1160. }
  1161. }, 500);
  1162. })();