// ==UserScript== // @name IframeManager // @version 2026.02.15.01 // @description 修复预览bug // @author You // @include * // @grant GM_setValue // @grant GM_deleteValue // @grant GM_getValue // @grant GM_download // @grant GM_xmlhttpRequest // @require https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js // ==/UserScript== class IframeManager{ box = new IframeManagerBox(); private = { promise : Promise.resolve(), } constructor(origin){ if(!origin) throw("Must set origin"); this.box.AddBox(); this.Post = new IframePoster(origin); } async Open(url) { let $iframe; this.private.count++; this.private.promise = this.private.promise.then(async () => { $iframe = await this.box.AddIframe(url); this.OnOpened($iframe[0]); $iframe.on('load', () => this.OnLoaded($iframe[0])) }); await this.private.promise; } Close(url){ this.private.count--; this.box.RemoveIframe(url); } OnOpened(iframe){} OnLoaded(iframe){} Post = null; } class IframeManagerBox{ static addEvented = false; funul = null; _count = 0; _Counter(v){ this._count+=v; $('.iframe-manager .swith').css('--count',`"${this._count}"`); } AddBox(){ const box = `
` $('body').append(box); this._Event() } _Event(){ const _this = this; if(IframeManagerBox.addEvented) return; IframeManagerBox.addEvented = true; this.funul = new FunUL($('.iframe-manager .item:first')[0],"{{url}}"); $('.iframe-manager') .on('click','.item .close',function(event){ const url = $(event.target).data('url'); if(url) _this.RemoveIframe(url); }) .on('click','.item .retry',function(event){ const iframe = $(event.target).nextAll("iframe"); if(iframe.length==1) iframe[0].src = iframe[0].src; }) $('.iframe-manager .swith').click(function(){ $('.iframe-manager').toggleClass('show'); }) $('.iframe-manager .swith').on('mouseenter',()=>{ if(!$('.iframe-manager').hasClass('show')) $('.iframe-manager').toggleClass('show'); }) $('.iframe-manager .item').hide(); } async AddIframe(url){ this._Counter(1); return this.funul.Add(url).then($item=>{ $item.find('button').data('url',url); return $item.find('iframe').show(); }); } RemoveIframe(url){ this._Counter(-1); this.funul.Remove(url); } } class FunUL{ items = new DictionaryList(); /** * @example new FunUL($('.iframe-manager .item:first')[0],"{{url}}"); */ constructor(templateDom,itemKey){ this.template = templateDom.outerHTML; this.container = $(templateDom).parent(); this.itemKey = itemKey; } async Add(key,values = []){console.log("template",this.template);console.log("itemkey",this.itemKey) let dom = this.template; dom = dom.replace(this.itemKey,key); values.forEach(info=>{ const k = info.key instanceof RegExp && info.key.global ? info.key : new RegExp(info.key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'); dom = dom.replace(k, info.value); });console.log("key",key);console.log("dom",dom); dom = $(dom); this.container.append(dom); await this.items.Push(key,dom); return dom; } async Remove(key){ this.items.Get(key).forEach($item=>$item.remove()); await this.items.Del(key); } } class DictionaryList { _promise = Promise.resolve(); _value = {}; async Push(key, value) { this._promise = this._promise.then(() => { if (!this._value[key]) this._value[key] = [value]; else this._value[key].push(value); }); await this._promise; } async Del(key) { this._promise = this._promise.then(() => { delete this._value[key]; // ✅ 彻底删除 }); await this._promise; } Get(key){ console.log(this._value); console.log(key,this._value[key]); return this._value[key]; } } class IframePoster{ static listenerAdded = false; origin = "*"; constructor(origin,CanIPost) { this.origin = origin; if(IframePoster.listenerAdded) return; IframePoster.listenerAdded = true; window.addEventListener('message', (e) => { if(CanIPost && !CanIPost(e.origin)) return; if (e.data.type === 'ParentPost') this.onFromParent(e.data.data); else if (e.data.type === 'iframeReady') this.onFromIframe(e.data.data); }); } ToIframe(iframe,data){ iframe.contentWindow.postMessage( { type: 'ParentPost', data: data}, iframe.src ); } ToParent(data){ parent.postMessage( { type: 'iframeReady', data: data }, this.origin ); } onFromIframe(data){} onFromParent(data){} } /** * @description 用户只需要Open创建并重写async IframeAction(url){}就行 */ class IframeManagerExtend1 extends IframeManager{ constructor(origin){ super(origin); this._IframePageLinstener(); this._ParentPageLinstener(); } OnLoaded(iframe){ $(iframe).data('url',iframe.src); this.Post.ToIframe(iframe,{autoAction:true,url:iframe.src}); } _IframePageLinstener(){ this.Post.onFromParent = async data =>{ if(!data.autoAction) return; await this.IframeAction(data.url); this.OnIframeActionDone(data.url); } } _ParentPageLinstener(){ this.Post.onFromIframe = data =>{ if(!data.ActionDone) return; this.Close(data.ActionDone); } } async IframeAction(url){ throw new Error('IframeAction must be override'); } OnIframeActionDone(url){ this.Post.ToParent({ActionDone:url}) } } window.IframeManager = IframeManager; window.FunUL = FunUL; window.DictionaryList = DictionaryList; window.IframePoster = IframePoster; window.IframeManagerExtend1 = IframeManagerExtend1;