Reddit - fix "new"

Fix "new" reddit behaviour: long-lived page, internal links, moderator page

目前為 2024-06-15 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Reddit - fix "new"
// @namespace    https://github.com/Procyon-b
// @version      0.4.6
// @description  Fix "new" reddit behaviour: long-lived page, internal links, moderator page
// @author       Achernar
// @match        https://*.reddit.com/*
// @grant   GM_setValue
// @grant   GM_getValue
// @grant   GM_deleteValue
// @grant   GM.registerMenuCommand
// @run-at  document-start
// ==/UserScript==

(function() {
"use strict";

//à

var react, tit={}, options={}, updated={};
const version='0.4.6';
const defOpts={
  version: '',

  enable_LLP: true,
  enable_LLPv2_2: false,
  enable_LLPv3: true,
  timed_LLP: false,
  LLP_TO: 1000,
  hide_NP: false,
  no_tit: false,
  loadMsg: false,

  lnk_rw_intf: true,
  lnk_rw_cmt_www: true,
  lnk_rw_cmt_old: false,
  lnk_rw_chat: true,

  stay_new: true,
  stay_new_old: false,
  force_new: false,

  mod_modLog_r: true,
  mod_modLog_hide: false,
  mod_fix_modmail: true,

  lnk_ext_noref: true,

  misc_mark: false,
  misc_rst_o: false,
  misc_nolabel: false,
  misc_noblur: false,
  },
 dlgT=[
  ['-', '<span new>New options have been added.</span><a new id="dismiss">Dismiss</a>'],
  ['{','"Long-lived" page:'],
  ['enable_LLP', 'Trigger long-lived page', 'checkbox'],
  ['-'],
  ['{'],
  ['enable_LLPv3', 'Use "forced" method (experimental)', 'checkbox', ['data-grp=enable_LLPv', 'new_0_4_6'] ],
  ['enable_LLPv2_2', 'Use "redirect" method (last resort)', 'checkbox', ['data-grp=enable_LLPv', 'new_0_4_6'] ],
  ['-'],
  ['timed_LLP', 'Delay "new post" closing', 'checkbox'],
  ['LLP_TO', '"new post" display time (ms)', 'text', ['style="width: 4em;"', 'onchange="this.value=/^\\D*(\\d+).*$/.exec(this.value)[1]"'] ],
  ['}'],
  ['-'],
  ['hide_NP', 'Hide "new post" form during the trick (empty screen)', 'checkbox'],
  ['no_tit', 'Don\'t try to fix incorrect page title', 'checkbox'],
  ['loadMsg', 'Show loading sign', 'checkbox', ['new_0_4_6']],
  ['}'],
  ['-'],
  ['{', 'Rewrite links:'],
  ['', 'Notifications links are already rewritten to "new." by default. You can change the behavior of other links.'],
  ['-'],
  ['lnk_rw_intf', 'Rewrite interface links', 'checkbox'],
  ['lnk_rw_cmt_www', 'Rewrite "www." links in posts & comments', 'checkbox'],
  ['lnk_rw_cmt_old', 'Rewrite "old." links in posts & comments', 'checkbox'],
  ['lnk_rw_chat', 'Rewrite in "Chat" too', 'checkbox', ['new_0_4_0']],
  ['-'],
  ['stay_new', 'Try to keep navigating on "new."', 'checkbox'],
  ['stay_new_old', '... on "new." also from "old." all comments', 'checkbox', ['new_0_4_0']],
  ['force_new', 'Force-redirect all access on "www." to "new."', 'checkbox'],
  ['}'],
  ['-'],
  ['{','Moderation page:'],
  ['mod_modLog_r', 'Add menu item to old "Mod Log" page', 'checkbox'],
  ['mod_modLog_hide', 'Hide current "Mod Log" menu item', 'checkbox'],
  ['mod_fix_modmail', 'Fix links also in Modmail', 'checkbox'],
  ['}'],
  ['-'],
  ['{','Misc:'],
  ['lnk_ext_noref', 'Add <code>rel="noreferrer"</code> to external links', 'checkbox'],
  ['}'],
  ['-'],
  ['{','This dialog:'],
  ['misc_mark', 'Mark option difference from current and default value', 'checkbox'],
  ['misc_rst_o', 'Clicking on the diff mark resets the value', 'checkbox'],
  ['misc_nolabel', 'Clicking on text label of options doesn\'t toggle option', 'checkbox'],
  ['misc_noblur', 'Don\'t blur background', 'checkbox', ['new_0_4_6']],
  ['}'],
  ['-'],
  ['{','Infos:'],
  ['', '<a href="https://procyon-b.github.io/programming/" target="_blank" rel="noreferrer noopener">Homepage</a> &ndash; <a href="https://greasyfork.org/scripts/493986" target="_blank" rel="noreferrer noopener">Script page</a><version>v'+version+'</version>'],
  ['}'],
  ];


function getOpts() {
  try{
  options=GM_getValue('options');
  options=Object.assign({}, defOpts, options);
  }catch(e){
  Object.assign(options, defOpts);
  }
  try{
    updated=GM_getValue('updated', {});
  }catch(e){}
  }

function saveOpts(opt = options) {
  var o, k;
  for (k in opt) {
    if (opt[k] != defOpts[k]) {
      if (!o) o={};
      o[k]=opt[k];
      }
    }
  if (o) GM_setValue('options', o);
  else GM_deleteValue('options');
  if (Object.keys(updated).length) GM_setValue('updated', updated);
  else GM_deleteValue('updated');
  }

getOpts();
if (!options.version) {
  options.version=version;
  saveOpts();
  }
if (options.version != version) {
  updated['new_'+version.replace(/\./g,'_')]=0;
  options.version=version;
  saveOpts();
  }
const showNew = 1209600000;
if (Object.keys(updated).length) {
  let k, now=Date.now();
  for (k in updated) {
    if ( updated[k] && ((updated[k] + showNew) < now) ) delete updated[k];
    }
  saveOpts();
  }

var st=document.createElement('style');

function ins() {
  document.removeEventListener('DOMContentLoaded', ins);
  window.removeEventListener('load', ins);

  document.documentElement.appendChild(st);
  document.body.addEventListener('click', function(ev){
    if (ev.target.classList.contains('icon-views')) {
      setOptions();
      }
    });
  }

if (document.readyState != 'loading') ins();
else {
  document.addEventListener('DOMContentLoaded', ins);
  window.addEventListener('load', ins);
  }

function tryUntil(F) {
  try{F();}
  catch(e){setTimeout(function(){tryUntil(F);}, 150)}
  }

tryUntil( function(){document.documentElement.appendChild(st);} );

st.textContent=`.icon-views {cursor: pointer;}
body.trick #SHORTCUT_FOCUSABLE_DIV > div:has( #AppRouter-main-content .ListingLayout-outerContainer > ._3ozFtOe6WpJEMUtxDOIvtU > div:first-child:empty + div[style] + div[style*="px"]) ~ div > ._1DK52RbaamLOWw5UPaht_S,
body.trick #AppRouter-main-content .ListingLayout-outerContainer > ._3ozFtOe6WpJEMUtxDOIvtU > div:first-child:empty + div[style] + div[style*="px"] {display: none;}
html.loadMsg::before {
  content: "Loading...";
  position: fixed;
  z-index: 99999999;
  font: 30pt arial;
  margin: calc(50vh - 1em) calc(50% - 2.5em);
  background: #ff4500;
  padding: .5em;
  border-radius: 10px;
  box-shadow: 5px 10px rgba(0, 0, 0, .5);
}
`;


if (window === window.top) GM.registerMenuCommand('Settings'+(Object.keys(updated).length ?' (new option(s))':''), function(){
  setOptions();
  });

var dlg=false;
function setOptions() {
  if (dlg) return;

  let k, now=Date.now();
  for (k in updated) {
    if (!updated[k]) updated[k]=now;
    else if ( (updated[k] + showNew) < now ) delete updated[k];
    }
  if (k) saveOpts();

  dlg=document.createElement('div');
  dlg.id='triggerLLP-dialog';
  dlg.className="triggerLLP-bg";
  dlg.innerHTML=`<style>
#triggerLLP-options {
  position: relative;
  --margins: 40px;
  max-height: calc( 100vh - 2 * var(--margins) );
  max-width: 530px;
  margin: var(--margins) auto;
  background: var( --color-neutral-background, var(--color-tone-8, white) );
  border: 2px solid gray;
  box-shadow: var( --boxshadow-modal );
  box-sizing: border-box;
}
html > body:not(.res-console-open) #RESNotifications, html >body:not(.res-console-open) #RESShortcutsAddFormContainer,
html > body:not(.res-console-open) .RESDropdownList, html > body:not(.res-console-open):not(.modal-open) .side #search {
  z-index: 2147483646!important;
}
.triggerLLP-bg {
  position: fixed;
  z-index: 2147483647;
  width: calc( 100vw + 40px);
  height: 100vh;
  top: 0;
  left: 0;
  overflow: auto;
  overscroll-behavior: contain;
}
span.tLLP-close {
  position: absolute;
  right: 5px;
  top: 5px;
  border-radius: 15px;
  width: 30px;
  height: 23px;
  text-align: center;
  padding-top: 7px;
  background: var( --color-interactive-background-disabled  );
  cursor: pointer;
}
span.tLLP-close:hover {
  background: var(--color-button-plain-background-hover);
}
span.tLLP-close svg {
  pointer-events: none;
}
#triggerLLP-options h2 {
  font-size: revert;
  background: var( --color-secondary-background-selected, lightgray);
  height: 40px;
  min-height: 40px;
  margin: 0;
  padding-left: 2em;
  line-height: 1.5em;
}
#triggerLLP-options .content {
  padding: 1em;
  margin: 0;
  overflow: auto;
  height: 100%;
  overscroll-behavior: contain;
}
#triggerLLP-options input {
  margin: 0;
  margin-right: 1em;
}
#triggerLLP-options div {
  line-height: 1.5em !important;
}
#triggerLLP-options .empty {
  margin-bottom: 1em;
}
#triggerLLP-options {
  display: flex;
  flex-direction: column;
  pointer-events: initial;
}
#triggerLLP-options .buttons {
  background: var( --color-secondary-background-selected, lightgray);
  padding: 0.5em;
  text-align: center;
  font-size: small;
}
#triggerLLP-options button,
#triggerLLP-options fieldset,
#triggerLLP-options legend {
  margin: revert;
  padding: revert;
  border: revert;
  vertical-align: revert;
}
html.theme-light #triggerLLP-options button {
  background: revert;
  color: revert;
}
html.theme-light #triggerLLP-options input[type="text"] {
  border: revert;
}
#triggerLLP-dialog .cont {
  position: fixed;
  width: calc( 100vw - 18px );
  pointer-events: none;
}
#triggerLLP-dialog:not(.noblur) .cont {
  backdrop-filter: blur(1px);
}
#triggerLLP-dialog.diff input,
#triggerLLP-dialog.diff span.diff {
  position: relative;
}
#triggerLLP-dialog.diff input[type="checkbox"]:not(:disabled):checked:not([data-checked])::before,
#triggerLLP-dialog.diff input[type="checkbox"]:not(:disabled)[data-checked]:not(:checked)::before,
#triggerLLP-dialog.diff span:first-child.diff:not(:has(+ :disabled))::before
{
  color: red;
  content: "*";
  left: -.5em;
  position: absolute;
}
#triggerLLP-dialog.diff input[type="checkbox"]:not(:disabled):checked:not([data-o_checked])::after,
#triggerLLP-dialog.diff input[type="checkbox"]:not(:disabled)[data-o_checked]:not(:checked)::after,
#triggerLLP-dialog.diff input:not(:disabled) + span.diff::after
{
  color: green;
  content: "*";
  right: -.5em;
  position: absolute;
}
#triggerLLP-dialog.diff input + span.diff::after {
  left: -.8em;
  right: unset;
}
#triggerLLP-dialog.diff.rst span.diff {
  cursor: pointer;
}
#triggerLLP-dialog:not(.rst) span.diff,
#triggerLLP-dialog:not(.rst) input::after,
#triggerLLP-dialog:not(.rst) input::before {
  pointer-events: none;
}
#triggerLLP-dialog :disabled ~ *, #triggerLLP-dialog :has(~ :disabled) {
  color: gray;
}
#triggerLLP-dialog a {
  color: #3a80e9;
  text-decoration: revert;
}
#triggerLLP-dialog a:hover {
  color: #47b0db;
}
body[class]:not([class=""]) #triggerLLP-options input[type="text"] {
  padding: 0;
}
body[class]:not([class=""]) #triggerLLP-dialog {
  font-family: IBMPlexSans, Arial, sans-serif !important;
  font-size: 16px !important;
}
body[class]:not([class=""]) #triggerLLP-dialog :not(input[type="text"]):not(h2):not(code) {
  font: inherit;
  text-transform: none;
  letter-spacing: unset;
}
#triggerLLP-options label {
  color: inherit;
}
#triggerLLP-dialog.nolabel label {
  pointer-events: none;
}
#triggerLLP-options code {
  font: revert;
}
#triggerLLP-options version {
  float: right;
}
#triggerLLP-options #dismiss {
  float: right;
  font-size: small;
  cursor: pointer;
}
#triggerLLP-options .content.noNew div:has(>[new]) {
  display: none;
}
`+(
Object.keys(updated).length ? '#triggerLLP-options .content:not(.noNew) div:has(> :is([new], ['+Object.keys(updated).join('], [')+'])) { background: rgba(255, 69, 0, .3); }':`
#triggerLLP-options div:has(>[new]) {
  display: none;
}
`
)+`</style>
<div class="cont">
<div id="triggerLLP-options">
<span class="tLLP-close"><svg fill="currentColor" height="16" viewBox="0 0 20 20" width="16">
<path d="m18.442 2.442-.884-.884L10 9.116 2.442 1.558l-.884.884L9.116 10l-7.558 7.558.884.884L10 10.884l7.558 7.558.884-.884L10.884 10l7.558-7.558Z"></path>
</svg></span>
<h2>Fix "New" Reddit - Userscript options</h2>
<diV class="content">
</div>
<div class="buttons"><div><button class="tLLP-save">Save</button> <button class="tLLP-close">Cancel</button> &nbsp; &nbsp; <button class="tLLP-reset">Reset</button> <button class="tLLP-defaults">Defaults</button></div></div>
</div>
</div>
<div style="min-height:101vh;"></div>`;
  document.body.appendChild(dlg);

  var c=dlg.querySelector('.content');
  if (c) fillContent();

  function fillContent(opts = options) {
    let s='';
    for (let v of dlgT) {
      let k =v[0];
      if (k == '-') s+='<div class="empty">'+(v[1]||'')+'</div>';
      else if (k == '') s+='<div>'+v[1]+'</div>';
      else if (k == '{') s+='<fieldset>'+(v[1]?'<legend>'+v[1]+'</legend>':'');
      else if (k == '}') s+='</fieldset>';
      else {
        s+='<div><span></span><input type="'+v[2]+'" name="'+v[0]+'" '+
            (typeof opts[k] == 'boolean' ? 'id="'+v[0]+'"'+( opts[k] ? 'checked ':'') + (options[k] ? 'data-checked ':'') + (defOpts[k] ? 'data-o_checked ':'')
            :'value="'+opts[k]+'" data-value="'+options[k]+'" data-o_value="'+defOpts[k]+'" ')+
            (v[3] ? v[3].join(' ') : '')+
            '><span></span><label for="'+v[0]+'">'+v[1]+'</label></div>';
        }
      }
    c.innerHTML='<form onsubmit="return false">'+s+'</form>';
    dlg.classList.toggle('diff', options.misc_mark);
    dlg.classList.toggle('rst', options.misc_rst_o);
    dlg.classList.toggle('nolabel', options.misc_nolabel);
    dlg.classList.toggle('noblur', options.misc_noblur);
    dlg.querySelectorAll('input[type="text"]').forEach(txt_diff);
    }

  dlg.addEventListener('click', hevents);
  dlg.addEventListener('change', hevents);

  function hevents(ev){
    var t=ev.target;
    if (t.className == 'tLLP-close') {
      dlg.remove();
      dlg=undefined;
      }
    else if (t.className == 'tLLP-save') {
      let newOpts=JSON.parse(JSON.stringify(options));
      dlg.querySelectorAll('[name]').forEach(function(k){
        if (k.name in defOpts) {
          if (typeof defOpts[k.name] == 'boolean') newOpts[k.name]=k.checked;
          else newOpts[k.name]=k.value;
          }
        });

      saveOpts(newOpts);
      getOpts();
      dlg.remove();
      dlg=undefined;
      }
    else if (t.className == 'tLLP-reset') {
      fillContent();
      }
    else if (t.className == 'tLLP-defaults') {
      fillContent(defOpts);
      }
    else if ( (t.tagName == 'INPUT') && (t.type == 'text') ) {
      txt_diff(t);
      }
    else if ( (t.tagName == 'INPUT') && (t.name=='misc_mark') ) {
      dlg.classList.toggle('diff', t.checked);
      }
    else if ( (t.tagName == 'INPUT') && (t.name=='misc_rst_o') ) {
      dlg.classList.toggle('rst', t.checked);
      }
    else if ( (t.tagName == 'INPUT') && (t.name=='misc_nolabel') ) {
      dlg.classList.toggle('nolabel', t.checked);
      }
    else if ( (t.tagName == 'INPUT') && (t.name=='misc_noblur') ) {
      dlg.classList.toggle('noblur', t.checked);
      }
    else if ( (t.tagName == 'SPAN') && t.classList.contains('cur') ) {
      t.nextElementSibling.value=t.nextElementSibling.dataset.value;
      txt_diff(t.nextElementSibling);
      }
    else if ( (t.tagName == 'SPAN') && t.classList.contains('def') ) {
      t.previousElementSibling.value=t.previousElementSibling.dataset.o_value;
      txt_diff(t.previousElementSibling);
      }
    else if (t.id == 'dismiss') {
      updated={};
      saveOpts();
      c.classList.add('noNew');
      }

    if (t.dataset.grp) {
      let a=t.closest('form').querySelectorAll('[data-grp="'+t.dataset.grp+'"]').forEach(function(e){
        if (e != t) e.checked=false;
        });
      }
    }
  function txt_diff(e) {
    e.previousElementSibling.classList.toggle('diff', e.value != e.dataset.value);
    e.previousElementSibling.classList.toggle('cur', e.value != e.dataset.value);
    e.nextElementSibling.classList.toggle('diff', e.value != e.dataset.o_value);
    e.nextElementSibling.classList.toggle('def', e.value != e.dataset.o_value);
    }
  }




// Reddit - fix links

var isNew = (location.host == "new.reddit.com");
var isWww = (location.host == "www.reddit.com");
var isOld = (location.host == "old.reddit.com");
var isChat = (location.host == "chat.reddit.com");
var AS=HTMLElement.prototype.attachShadow;

function fixLinks() {

if (isChat && !options.lnk_rw_chat) return;
var clicks={}, delay=10000;
Ccl();
setTimeout(Ccl,12000);

var oldForNew = false, forNew = false;
if (options.stay_new || options.stay_new_old) {
  Gcl();
  forNew=document.referrer.startsWith('https://new.reddit.com/');
  if (!forNew && options.stay_new_old) forNew=/^https:\/\/old\.reddit\.com\/r\/[^\/]+\/comments\//.test(document.referrer);
  if (!isNew && !forNew) {
    forNew=clicks['_staynew_'+location.href];
    // if user reloads, reload as New
    if (forNew) window.addEventListener('unload', function(){
      clicks['_staynew_'+location.href]=Date.now();
      Scl();
      });
    }
  }
var onNew = isNew || forNew;
var toNew = onNew && !isNew;

if (options.force_new) toNew=true;
if ( /^\/r\/[^/]+\/comments\/$/.test(location.pathname)
  || location.href.startsWith('https://www.reddit.com/media')
   ) toNew=false;

if (clicks[location.href]) onNew=true;
if (options.mod_fix_modmail && (location.host == "mod.reddit.com") ) onNew=true;
if (isOld) {
  if (forNew && options.stay_new_old && /^\/r\/[^\/]+\/comments\/$/.test(location.pathname) ) oldForNew=true;
  else return;
  }

if (toNew) {
  if (location.host.startsWith('www.')) {
    let L=location.href.replace(/^https:\/\/www\.reddit\./, 'https://new.reddit.');
    if (!clicks[L]) {
      clicks[L]=Date.now();
      Scl();
      window.stop();
      location.host='new.reddit.com';
      }
    }
  }

if (!onNew) return;

if (isWww || isChat) {
  HTMLElement.prototype.attachShadow=function(m){/*[native */
    var e=this;
    e.sr=AS.call(e,m);
    newObs(e.sr);
    return e.sr;
    }
  }

if (document.readyState != 'loading') init();
else {
  document.addEventListener('DOMContentLoaded', init);
  window.addEventListener('load', init);
  }

function newObs(r) {
  var o=new MutationObserver(cb), config = { attributes: false, childList: true, subtree: true};
  o.observe(r, config);
  return o;
}

var done=false;
function init() {
  if (done) return;
  done=true;
  document && document.body && chk();

  var obs=newObs(document.body);
  }

function stayNew(ev) {
  if (this.hostname == 'i.redd.it') clicks['_staynew_https://www.reddit.com/media?url='+ encodeURIComponent(this.href) ]=Date.now();
  clicks['_staynew_'+this.href]=Date.now();
  Scl();
  }

function chk(r) {
  var a=(r||document).getElementsByTagName("a");
  if (r && (r.nodeName == 'A')) a=[r, ...a];
  for (let i=0,e; e=a[i]; i++) {
    if (e._fixed) continue;
    e._fixed=true;
    if ( (e.hostname == 'i.redd.it')
      || (e.hostname == 'preview.redd.it') ) {
      e.rel=e.rel.replace('noreferrer', '');
      if (!isNew && options.stay_new) {
        e.addEventListener('click',stayNew);
        e.addEventListener('contextmenu',stayNew);
        }
      }
    else if ( !e.hostname.endsWith('redd.it') && !e.hostname.endsWith('reddit.com') ) {
      if (options.lnk_ext_noref && !(e.rel ||'').includes('noreferrer')) e.rel=(e.rel ||'')+' noreferrer';
      }
    else if (/^https?:\/\/(www\.|mod\.|old\.)?reddit\.com\//.test(e.href)) {

      if (/sticky\?num/.test(e.href)) continue;

      if ( e.href.match('^'+location.origin+location.pathname+'(\\?.*)?$') ) {
        if (options.stay_new) {
          e.addEventListener('click',stayNew);
          e.addEventListener('contextmenu',stayNew);
          }
        continue;
        }
      e.oriHref=e.href;
      let uLnk=e.classList.contains('_3t5uN8xUmg0TOwRCOGQEcU');
      if ( (options.lnk_rw_intf && !uLnk) ||
           (options.lnk_rw_cmt_www && uLnk) ||
           e.classList.contains('_1tpiOc0IxpDU113wUs4zi1') ) e.href=e.href.replace(/^https?:\/\/(www\.)?reddit\.com\//,'https://new.reddit.com/');
      if ( (options.lnk_rw_cmt_old && uLnk) ||
           oldForNew ) e.href=e.href.replace(/^https?:\/\/(old\.)?reddit\.com\//,'https://new.reddit.com/');
      }
    }
  }

function cb(mutL) {
  for(let mut of mutL) {
    if (mut.type == 'childList') {
      for (let e,i=0; e=mut.addedNodes[i]; i++) {
        if (e.nodeType == 1) chk(e);
        }
      }
    }
  }


function Scl() {
  if (!Object.keys(clicks).length) localStorage.removeItem("__newL__");
  else localStorage.setItem("__newL__", JSON.stringify(clicks) );
  }

function Gcl() {
  clicks=JSON.parse(localStorage.getItem("__newL__") || '{}');
  return clicks;
  }

function Ccl() {
  Gcl();
  var now=Date.now();
  for (let k in clicks) {
    if ( (clicks[k]+delay) < now ) delete clicks[k];
    }
  Scl();
  }

} // END fixLinks()

fixLinks();




// Reddit - trigger LLP

var noLLP=false, skipSub=0;

if (isNew) {

  if (options.enable_LLP) {
    if (options.enable_LLPv2_2) {
      if (/^\/r\/[^\/]+\/wiki\//.test(location.pathname)) {
        noLLP=true;
        }
      else if (!location.pathname.endsWith('/submit')) {
        window.stop();
        location=location.origin+'/submit#'+location.href;
        return;
        }
      else if (location.hash) {
        tryUntil(hideNP);
        tryUntil(function(){document.title='Reddit';});
        }
      }

    else if (options.enable_LLPv3) {
      if (location.pathname.endsWith('/submit')) {
        skipSub=1;
        if (location.hash.startsWith('#back')) {
          tryUntil(hideNP);
          tryUntil(function(){document.title='Reddit';});
          skipSub=2;
          tit[location.href.split('#back#')[1]]='oo';
          }
        }
      }

    if (location.pathname.endsWith('/submit') && !location.hash) {
      skipSub=1;
      }

    }

  window.addEventListener('load', LLP);
  if ( (window === window.top) && options.loadMsg && (document.readyState != 'complete') ) {
    if (document.documentElement) document.documentElement.classList.add('loadMsg');
    else {
      document.addEventListener('DOMContentLoaded', function(){document.documentElement.classList.add('loadMsg')} );
      tryUntil( function(){document.documentElement.classList.add('loadMsg')} );
      }
    }
  }

var LMTO=0;
function clrLoad(t = 0) {
  if (LMTO) clearTimeout(LMTO);
  return LMTO=setTimeout( function(){document.documentElement.classList.remove('loadMsg');} , t);
  }

function hideNP() {
  if (!options.hide_NP) return;

  function rmCls() {
    setTimeout(function(){document.body.classList.remove('trick');}, t);
    }

  document.body.classList.add('trick');
  let t = (options.timed_LLP ? options.LLP_TO || 1000 : 0)*1 + 10000;
  if (document.readyState != 'loading') rmCls();
    else {
      window.addEventListener('load', rmCls);
      }
  clrLoad(t);
  }

function LLP() {
  clrLoad();
  if (location.pathname.endsWith('/submit')) ;

  if (noLLP) return;
  if (location.pathname.endsWith('/settings/')) return;
  if (location.pathname.endsWith('/settings')) return;
  if (location.pathname.startsWith('/message/')) return;
  if (location.search.includes('styling')) return;
  var r=document.querySelector('#SHORTCUT_FOCUSABLE_DIV');

  // fix no title set in bg win/tab
  setBgTitle();

  if ( !options.enable_LLP
    || !r
     ) return;

  for (let k in r) {
    if (k.startsWith('__reactEventHandlers$')) {
      react=k;
      break;
      }
    }
  if (!react) return;

  // find link without sub-R
  var e, btn;
  if (options.enable_LLPv3 && !skipSub) {
    btn='a[href="/settings"]';
    e=document.querySelector(btn);
    }
  else {
    btn='a[href="/submit"]';
    e=document.querySelector(btn);
    }

  if (!e && !skipSub) {
    // try to find in drop-down
    let c=document.querySelector('header button img + i.icon-caret_down, header button svg + i.icon-caret_down, header button i + i.icon-caret_down');
    if (c) {
      c=c.closest('button');
      c[react].onMouseDown({target: c});
      }
    e=document.querySelector(btn);
    }

  // use "+" icon
  if (!e && !options.enable_LLPv3) e=document.querySelector('header button:not([role="menuitem"]) > .icon-add');

  if (e || skipSub) {
    if (!skipSub) {
      hideNP();
      tit[location.href]=document.title;
      let oriLoc=location.href;
      if (!options.enable_LLPv2_2) e.click();
      else document.title='Reddit';
      if (options.enable_LLPv3) {
        history.replaceState({},null, location.origin+'/submit#back#'+oriLoc);
        window.stop();
        location.reload();
        return;
        }
      }
    findField();
    }
  }

var max=1000;
function findField() {
  if (!max) return;
  max--;
  var b=document.querySelector('textarea[placeholder][maxlength="300"][rows="1"]');
  if (!b) { setTimeout(findField, 10); return; }
  let tt;
  if ( (tt=document.querySelector('html head title')) && !options.no_tit) obsTit.observe(tt, {attributes: false, subtree: true, childList: true, characterData: true });
  b.value='e';
  b[react].onChange({target:b});
  b.value='';
  b[react].onChange({target:b});
  if (!(skipSub & 1)) setTimeout(function(){
    var L;
    if (options.enable_LLPv2_2 && (L=location.hash.substr(1)).startsWith('https://') ) {
      history.replaceState({},null, L);
      history.pushState({},null, L);
      setTimeout(setBgTitle, 2000);
      history.back();
      setTimeout(function(){history.forward();}, 8000); // fix title
      }
    else history.back();
    clickDiscard();
    clrLoad();
    }, options.timed_LLP ? options.LLP_TO || 1000 : 0);
  }

var max2=20;
function clickDiscard(){
  if (!max2) return;
  max2--;
  var b=document.querySelector('div[aria-modal="true"] footer button');
  if (!b) { setTimeout(clickDiscard, 10); return; }
  b.click();
  }

function setBgTitle(x) {
  if (document.visibilityState != 'hidden') return;
  if (options.enable_LLPv2_2) {
    if (location.pathname == '/') document.title='Reddit';
    else if (location.pathname.startsWith('/user')) document.title=location.pathname.split('/')[2];
    else if (/^\/(r\/[^\/])+\//.test(location.pathname) ) document.title=RegExp.$1;
    }
  if (location.pathname == '/') return;
  try{
  let t=document.querySelector('h1')?.textContent;
  if (!t && /^\/r\/[^\/]+\/comments\/./.test(location.pathname) ) t=document.querySelector('[data-adclicklocation="title"]')?.textContent;
  if (/^\/r\/[^/]+\/wiki\/([^/]+)/.test(location.pathname)) t=null;
  if (t && (document.title != t) ) document.title = t;
  }catch(e){}
  }


var title;
// monitor title to prevent "submit" to appear
function validTit(s) {
  const S='Submit to |Einreichen bei |Enviar a |Envoyer à |Invia a |Postar no |Enviar para ';
  const H='|Reddit – Entdecke ohne Ende|Reddit - Dive into anything|Reddit - Explora lo que quieras|Reddit: Explora lo que quieras|Reddit - Explorez sans limite|Reddit - Scopri ciò che ti piace|Reddit - Explore o que quiser|Reddit - Explora tudo o que quiseres';
  var RE=new RegExp('^(\([0-9]+\) *)?('+S+(location.pathname=='/' ? '' : H)+')');
  return !RE.test(s);
  }

const obsTit=new MutationObserver(function(muts){
  if (!title) title=muts[0].addedNodes[0].textContent;
  var titleOK, skipT=false;
  for (let t,i=muts.length-1; i >= 0 ; i--) {
    t=muts[i].addedNodes[0].textContent;
    if (validTit(t)) {
      titleOK=t;
      skipT=(i==muts.length-1);
      break;
      }
    else {
      let q=RegExp.$1, t=muts[i].removedNodes[0].textContent;
      if (validTit(t)) titleOK=t.replace(/^(\([0-9]+\) *)?/, q);
      }
    }
  let t=tit[location.href];
  if (!t) {this.disconnect()}
  if (!t || !titleOK) return;
  if (!skipT) setTimeout(function(){
    document.title=titleOK;
    },0);
  });
var TO;





// Reddit - fix mod log
// 0.2

  // if on "new"
if (isNew) {

var hpushState=history.pushState;

history.pushState=function(a,b,u){
  if (location.pathname.endsWith('/about/log') && u.includes('?')) {
    arguments[2]=u.replace(/\/about\/[^?]*/, '/about/log');
    if (!location.search) setTimeout(function(){
      history.back();
      setTimeout(function(){history.forward()},100);
      },0);
    }
  return hpushState.apply(history, arguments);
  }

function viewed(a, c='viewed') {
  a.forEach(function(e){
    e.classList.add(c);
    });
  }


// find deepest root
var R;
const obsRoot=new MutationObserver(function(muts){
  for (let mut of muts) {
    if (mut.addedNodes.length) {
      if (R=document.querySelector('#AppRouter-main-content')) {
        this.disconnect();
        o_pg.observe(R, {attributes: false, subtree: false, childList: true});
        fixlocs();
        return;
        }
      }
    }
  });

function startObs() {obsRoot.observe(document.body, {attributes: false, subtree: true, childList: true});}
if (document.body) startObs();
else {
  document.addEventListener('DOMContentLoaded', startObs);
  }



function fixlocs(muts){
  if (/^\/r\/[^/]+\/about/.test(location.pathname) ) fixMod();
  }

const o_pg=new MutationObserver(fixlocs);
var obsmnu;

function fixMod() {
  function find(muts){
    if (mnu) {
      let e=mnu.shadowRoot.querySelector('a[href^="/mod/"][href$="/log"]');
      if (e && options.mod_modLog_r) {
        let R=e.pathname.split('/')[2];
        obsmnu && obsmnu.disconnect();
        var st=document.createElement('style');
        mnu.shadowRoot.appendChild(st);
        st.textContent=`
.flex.items-center a > :first-child:not(.selected):not(._selected) {
  background-color: unset !important;
}
.flex.items-center:has(.selected) ~ .flex.items-center a[href^="/r/"][href$="/about/log"] > :first-child,
.flex.items-center:has(~ .flex.items-center .selected) a[href^="/r/"][href$="/about/log"] > :first-child {
  background: none !important;
}`;
        let p=e.closest('div')
        let a=p.cloneNode(true);
        p.parentNode.insertBefore(a,p);
        if (options.mod_modLog_hide) p.style.display='none';
        e=a.querySelector('a');
        let et=e.querySelector('span.items-center');
        if (et) et.innerHTML+=' (old)';
        e.href='/r/'+R+'/about/log';
        e.onclick=function(ev){
          history.pushState({},null, this.href);
          e.firstElementChild.classList.add('_selected');
          e.firstElementChild.style="background-color: #FF4500;";
          history.back();
          setTimeout(function(){
            history.forward();
            setTimeout(function(){ p.parentNode.querySelectorAll('.selected').forEach( (e) => e.classList.remove('selected') ); },1000);
            },100);
          };
        }
      }
    else {
      if (mnu=R.querySelector('mod-nav')) {
        obsmnu && obsmnu.disconnect();
        obsmnu.observe(mnu.shadowRoot, {attributes: false, subtree: true, childList: true});
        return true;
        }
      }
    }

  var mnu;
  if(obsmnu) obsmnu.disconnect();
  obsmnu=new MutationObserver(find);
  if (!find(0)) obsmnu.observe(R, {attributes: false, subtree: true, childList: true});
  }

} // if (isNew)


})();