Style shadowRoot

Allow stylus to target elements in shadow-root

目前为 2023-02-10 提交的版本。查看 最新版本

// ==UserScript==
// @name         Style shadowRoot
// @namespace    https://github.com/Procyon-b
// @version      0.1
// @description  Allow stylus to target elements in shadow-root
// @author       Achernar
// @match        http://NOTHING/
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
"use strict";
var id=Date.now()

//console.info('%c shadow CSS ', 'background: lightblue', {document}, {'body':document ? document.body:'-'}, {dE:document ? document.documentElement : '-'})

// patch attachShadow()
var AS=HTMLElement.prototype.attachShadow;
//console.info('%c shadow CSS ', 'background: #6699FF', id,{AS},location.href);

HTMLElement.prototype.attachShadow=function(m){/*[native */
  var e=this;
//console.info('%c shadow CSS ', 'background: #6699FF', id,{e, m})
  e.sr=AS.call(e,m);
  shadows.push(e.sr);
  inject(e.sr);
  shadowMod(e.sr);
  return e.sr;
  }
// END patch

var sheets={}, order=[],
    shadows=[], sCSS={}, injCSS='', oldInjCSS='';

// catch stylus injections
const obs=new MutationObserver(function(muts){
  for (let mut of muts) {
//console.info('%c shadow CSS ', 'background: #6699FF', {mut});
    for (let n of mut.addedNodes) {
      if ( (n.tagName == 'STYLE') && (n.className == 'stylus') && n.id.startsWith('stylus-') ) {
        addCSS(n);
        }
      }

    for (let n of mut.removedNodes) {
      if ( (n.tagName == 'STYLE') && (n.className == 'stylus') && n.id.startsWith('stylus-') ) {
        remCSS(n);
        }
      }
    }
  });
// END catch

function init() {
  if (!document.documentElement) {
    setTimeout(init, 0);
    return;
    }

  obs.observe(document.documentElement, {attributes: false, subtree: false, childList: true });
  // check for stylesheets
  document.documentElement.querySelectorAll('style[id^="stylus-"].stylus').forEach( (e) => addCSS(e,2) );
  }

init();

// get only shadow-specific css
function parseSheet(s) {
  var R=s.sheet.cssRules, sels, sel, shCSS='';
  for (let i=0; i < R.length; i++) {
    sel=R[i].selectorText;
//console.info('%c shadow CSS ', 'background: #6699FF', sel);
    if (!sel.includes(':host')) continue;
//console.info('%c shadow CSS ', 'background: #6699FF',  {sels, f:sels.filter(function(v){ return v.includes(':host') })} );
    sels=sel.split(',').filter(function(v){ return v.includes(':host') }).join(',');
    shCSS+=sels.trim()+ R[i].cssText.substr(sel.length)+'\n';
    }

  if (shCSS) shCSS='/*'+s.id+'*/\n'+shCSS;
//console.info('%c shadow CSS ', 'background: lightgreen', shCSS)
  return shCSS;
  }

// inject in this shadow
function inject(e) {
  if (injCSS == '') {
    if (e._inj_) {
      e._inj_.remove();
      delete e._inj_;
      }
    return;
    }
  if (!e._inj_ || !e._inj_.parentNode ) {
    let s=e._inj_=document.createElement('style');
    s.className='sh-stylus';
    e.appendChild(s);
    }
  e._inj_.textContent=injCSS;
  }

// inject style
function injectAll() {
  for (let i=0; i < shadows.length; i++) inject(shadows[i]);
  }

// create & inject style in shadows
function injUpd() {
  oldInjCSS=injCSS;
  injCSS='';
  for (let i=0; i < order.length; i++) injCSS+=sCSS[order[i]];
  if (injCSS !== oldInjCSS) injectAll();
  }

// get stylus stylesheet order
function getStylusOrder() {
  order=[];
  for (let i=0; i < document.styleSheets.length; i++) {
    let s=document.styleSheets[i].ownerNode;
    if (s.className == 'stylus') order.push(s.id);
    }
  }

// handle new stylesheet
function addCSS(n, k=1) {
  if (n.id in sheets) return;
  sheets[n.id]=n;
  if (n.__k__) ;//console.info('%c shadow CSS ', 'background: #6699FF', 'already known', n.id, n.__k__, k);
  else {
    n.__k__=k;

    // monitor modification
    const obs=new MutationObserver(function(muts){
      if (muts[0].addedNodes.length) {
        // === reparse stylesheet and reinject it
        sCSS[muts[0].target.id]=parseSheet(muts[0].target);
        injUpd();
        }
      });
    obs.observe(n, {attributes: false, subtree: false, childList: true });
    }

  sCSS[n.id]=parseSheet(n);
  getStylusOrder();
  injUpd();
  }

// handle stylesheet removal
function remCSS(n) {
  // is it only moved?
  if (n.parentNode == null) delete sheets[n.id];
  getStylusOrder();
  injUpd();
  }

// monitor shadow modification
function shadowMod(e) {
  const obs=new MutationObserver(function(muts){
    if (e._inj_ && (!e._inj_.parentNode || e._inj_.nextElementSibling) ) e.appendChild(e._inj_);
    });
  obs.observe(e, {attributes: false, subtree: false, childList: true });
  }

})();

QingJ © 2025

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