您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Recompute a new film rating value based on your criterias
// ==UserScript== // @name IMDb - fix rating // @namespace https://github.com/Procyon-b // @version 0.5.4 // @description Recompute a new film rating value based on your criterias // @author Achernar // @include /^https:\/\/www\.imdb\.com\/title\/[^\/]+\/(episodes|reference|ratings)?(\?.*)?$/ // @match https://www.imdb.com/chart/* // @match https://www.imdb.com/search/title/* // @match https://www.imdb.com/list/* // @grant GM_getValue // @grant GM_setValue // @grant GM.registerMenuCommand // @grant GM_listValues // @grant GM_deleteValue // @run-at document-end // ==/UserScript== (function() { "use strict"; var E, Ep, Er, rt, tv, opts, dialog, Layouts={ 'title':{ L:'[data-testid="hero-rating-bar__aggregate-rating"]', rt:'span[class^="AggregateRatingButton__RatingScore-sc-"], [data-testid="hero-rating-bar__aggregate-rating__score"] span', tv:'div[class^="AggregateRatingButton__TotalRatingAmount-sc-"], [data-testid="hero-rating-bar__aggregate-rating__score"] ~ :last-child', divide:true, type:'page' }, 'reference':{ L:'.titlereference-header .ipl-rating-star', rt:'.titlereference-header .ipl-rating-star .ipl-rating-star__rating', tv:'.titlereference-header .ipl-rating-star .ipl-rating-star__total-votes', tvF:function(tv,r) { if (!tv || !r) return; let vtv=r.querySelector('.vtv'); if (!vtv) { let RE=/^(.*?)([^()]+)(.*)$/s.exec(tv.innerText); tv.innerHTML=(RE[1]||'')+'<span class="vtv">'+RE[2]+'</span>'+(RE[3]||''); vtv=tv.querySelector('.vtv'); } return vtv; }, type:'page' }, 'ratings':{ L:'.subpage_title_block__right-column .ipl-rating-widget', rt:'.subpage_title_block__right-column .ipl-rating-widget .ipl-rating-star__rating', type:'page' }, 'EpLst':{ L:'.eplist .list_item', rt:'.ipl-rating-widget .ipl-rating-star .ipl-rating-star__rating', tv:'.ipl-rating-widget .ipl-rating-star .ipl-rating-star__total-votes', tvF:function(tv,r) { if (!tv || !r) return; let vtv=r.querySelector('.vtv'); if (!vtv) { let RE=/^(.*?)([^()]+)(.*)$/s.exec(tv.innerText); tv.innerHTML=(RE[1]||'')+'<span class="vtv">'+RE[2]+'</span>'+(RE[3]||''); vtv=tv.querySelector('.vtv'); } return vtv; }, nm:'a[itemprop="url"]:only-child, a.add-image ~ div', url:'a[itemprop="name"]', tit:'page', type:'list' }, 'Chart':{ k:'chart', L:'.lister-list > tr', rt:'.ratingColumn.imdbRating > strong', url:'.titleColumn a[href*="/title/"]', titF:function(tit, r){ if (!tit || !r) return; let n=tit.nextElementSibling; return tit.innerText + (n?' '+n.innerText:''); }, tit:'item', type:'list' }, 'List':{ k:'list', L:'.article.listo .lister-list > div', rt:'.ipl-rating-widget .ipl-rating-star__rating', tv:'.lister-item-content > p.text-muted.text-small > span[name="nv"]', url:'.lister-item-content a[href*="/title/"]', titF:function(tit, r){ if (!tit || !r) return; let n=tit.nextElementSibling; return tit.innerText + (n?' '+n.innerText:''); }, tit:'item', type:'list' }, 'Search':{ k:'search', L:'.lister-list > div', rt:'.inline-block.ratings-imdb-rating > strong', tv:'.sort-num_votes-visible [name="nv"]', url:'.lister-item-content a[href*="/title/"]', titF:function(tit, r){ if (!tit || !r) return; let n=tit.nextElementSibling; return tit.innerText + (n?' '+n.innerText:''); }, tit:'item', type:'list' }, 'SearchCompact':{ k:'search', L:'.lister-list > div', rt:'.col-imdb-rating > strong', url:'.lister-item-header a[href*="/title/"]', titF:function(tit, r){ if (!tit || !r) return; let n=tit.nextElementSibling; return tit.innerText + (n?' '+n.innerText:''); }, tit:'item', type:'list' } }; var XHRqueue=[], XHRqueueV, purging; function rstXHRq() { XHRqueue=[]; XHRqueueV=Date.now(); } var defOpts={ voters: '', k10: false, k10_max: false, k10_maxmax: false, k9_pc_10: 20, k9_max_do: false, k9_max: false, k9_max_10: false, k10_9_pcOn: false, k10_9_pc: 90, k1: false, purge: 16, search: false, chart: false, list: false }; var List, rtQS, tvQS, nmQS, urlQS, tvF, LO; // look for rates for (let k in Layouts) { LO=Layouts[k]; if (LO.type=='page') { E=document.querySelector(LO.L); if (E) break; continue; } List=document.querySelectorAll(LO.L); if (List.length) { rtQS=LO.rt; // rating found? if (!rtQS || (!List[0].querySelector(rtQS) && (List[1] && !List[1].querySelector(rtQS)) && (List[2] && !List[2].querySelector(rtQS)) ) ) { List=[]; continue;} tvQS=LO.tv; nmQS=LO.nm; urlQS=LO.url; tvF=LO.tvF; break; } } function getOpts() { opts=GM_getValue('opts', {}); opts= Object.assign({}, defOpts, opts); } getOpts(); addSt(` .oldVal::before { content: var(--oldSc); font-size: 0.8em; margin-right: 0.6em; text-decoration: line-through brown; line-height: 1em; color: gray; } .oldVal.noMod::before { content: "=" !important; text-decoration: none !important; } .waiting.oldVal::before { content: "?" !important; text-decoration: none !important; } div[class^="AggregateRatingButton__ContentWrap-sc-"]:hover .oldVal::before, .rating-bar__base-button:hover .oldVal::before, .ipl-rating-star.small:hover .oldVal::before, .oldVal:hover::before { text-decoration: none !important; } [data-testid="hero-rating-bar__aggregate-rating"] { position: relative; } #fix_rating_opt { position: absolute; color: black; background-color: white; top: 5em; z-index: 10000 !important; font-size: 13px; font-family: arial; line-height: 1.4em; padding: 3px 8px; border: 2px solid gray; margin: 0 50%; } #fix_rating_opt.list { position: fixed; } #fix_rating_opt { white-space: nowrap; } #fix_rating_opt #close { float: right; color: red; cursor: pointer; z-index: 2; position: relative; } #fix_rating_opt input[type="number"] { width: 3em; } #fix_rating_opt input[type="checkbox"] { vertical-align: middle; } #fix_rating_opt .mrg { margin-left: 1em; } #fix_rating_opt button, #fix_rating_opt input[type="button"] { font-weight: initial; padding: 1px 6px; cursor: initial; } #fix_rating_opt b { font-weight: bolder; } #fix_rating_opt.list #reset ~ *:not(.show) { display: none; } #fix_rating_opt span { font-size: inherit !important; line-height: inherit !important; } #fix_rating_opt input[type="checkbox"] { margin: 0 3px; } #fix_rating_opt input, #fix_rating_opt button { margin: 0 0 1px 0; } #fix_rating_opt input[type="number"] { padding: 0 !important; line-height: 1em !important; } #fix_rating_opt hr { border: none !important; height: 0 !important; margin-block-start: 0.3em !important; margin-block-end: 0.3em !important; } #fix_rating_opt #cached { display: inline-block; vertical-align: top; } #fix_rating_opt [name="k9_max_do"]:not(:checked) + .mrg { display: none; } #fix_rating_opt #hdr { cursor: grab; background: lightgray; position: absolute; left: 0; right: 0; top: 0; padding: 3px 8px; } #fix_rating_opt.grabbed #hdr { cursor: grabbing; } `); GM.registerMenuCommand('Settings', function(){ showCfg(); }); var trig=E || document.querySelector('h1.header'); if (trig) trig.addEventListener('click', function(ev){ if (ev.ctrlKey && ev.altKey) { ev.preventDefault(); ev.stopPropagation(); showCfg(); } }, {capture:true}); // init dialog if (!E) if ( (!opts.search && (LO.k=='search')) || (!opts.chart && (LO.k=='chart')) || (!opts.list && (LO.k=='list')) ) { List=[]; } function getListRating() { if (!List || !List.length) return; rstXHRq(); getOpts(); let w=10; List.forEach(function(Ep){ var url=urlQS && Ep.querySelector(urlQS), tit=(LO.titF && LO.titF(url,Ep)) || (url && url.innerText), nm=nmQS && Ep.querySelector(nmQS), num=nm? nm.innerText.replace(/^.*?(\d+).*?(\d+).*$/ms, '$1.$2') :'', rt=rtQS && Ep.querySelector(rtQS), tv=tvQS && Ep.querySelector(tvQS); if (!rt && !tv) return; if (tvF) tv=tvF(tv,Ep); if (rt && !decSep) { let RE=/^.*([\D]).*$/.exec(rt.innerText); if (RE) decSep=RE[1]; } if (tv && !thSep) { let RE=/\d([\D])\d\d\d$/.exec(tv.innerText); if (RE) thSep=RE[1]; } if (tit && (LO.tit=='page')) tit=document.title.replace(/ +- imdb *$/i,'')+(num?' - '+num:'')+' - '+tit; setTimeout(function(){display(url.pathname, rt, tv, tit);},w); w+=10; }); } var decSep, thSep; if (E) { rt=document.querySelector(LO.rt); tv=document.querySelector(LO.tv); if (!rt) return; if (tv && LO.tvF) tv=LO.tvF(tv,E); if (rt && !decSep) { let RE=/^.*([\D]).*$/.exec(rt.innerText); if (RE) decSep=RE[1]; } if (tv && !thSep) { let RE=/\d([\D])\d\d\d$/.exec(tv.innerText); if (RE) thSep=RE[1]; } let RE=/^.*([\D]).*$/.exec(rt.innerText); if (RE) decSep=RE[1]; // imdb script rewriting the values let obs=new MutationObserver(function(mutL){ for (let mut of mutL) { if (mut.type=='characterData') { let n=mut.target.parentNode; if (n.curV && (n.curV != n.innerText)) { n.innerText=n.curV; } } } }); obs.observe(E, {childList: false, subtree: true, characterData:true}); display(location.pathname, rt, tv, '', {divide:LO.divide}); } else { getListRating(); if (List.length) { var ec=document.querySelector('#episodes_content'); if (ec) { new MutationObserver(function(mutL){ if (mutL[0].addedNodes.length) { setTimeout(function(){ List=document.querySelectorAll(LO.L); getListRating(); },0); } }).observe(ec, {childList: true, subtree: false}); } else if (ec=document.querySelector('.lister.list.detail.sub-list > .row.lister-working.hidden')) { new MutationObserver(function(mutL){ if ( (mutL[0].attributeName == 'style') && (mutL[0].target.style.display == 'none') ) { setTimeout(function(){ List=document.querySelectorAll(LO.L); getListRating(); },0); } }).observe(ec, {childList: true, subtree: false, attributes: true}); } } } // init dialog if (!dialog) display(); function addSt(s,t) { let st=document.createElement('style'); try{ (document.head || document.documentElement).appendChild(st); st.textContent=s; }catch(e){ if (t) document.addEventListener('DOMContentLoaded',function(){addSt(s);}); else setTimeout(function(){addSt(s,t);},0); } } function showCfg() { let xy=E && E.getBoundingClientRect(); if (E) dialog.style='top:'+(window.scrollY+parseInt(xy.y)+80)+'px;'; else dialog.classList.add('list'); document.body.appendChild(dialog); } function display(href, rt, tv, tit='', o={}) { function waiting(v) { rt && rt.classList.toggle('waiting', v); tv && tv.classList.toggle('waiting', v); } rt && rt.classList.add('oldVal'); tv && tv.classList.add('oldVal'); function sendXHR(a) { if (!a || !a.R) return; a.R.open('GET', '/title/'+a.id+'/ratings'+a.v); a.R.send(); } function getRatings(id, vt=opts.voters) { //TMP new design 202305 vt=''; waiting(true); var v, R=new XMLHttpRequest(), XHRqV=XHRqueueV; R.addEventListener('error',function(){ if (XHRqV != XHRqueueV) return; setTimeout(function(){ sendXHR(XHRqueue.shift()); },0); }); R.addEventListener('load',function(r){ if (XHRqV != XHRqueueV) return; parse(this.responseText, vt); setTimeout(function(){ sendXHR(XHRqueue.shift()); },50); }); switch(vt) { case '': v=''; break; case 'us': v='?demo=us_users'; break; case 'nus': v='?demo=non_us_users'; break; case 'top': v='?demo=top_1000_voters'; break; default: return; } if (!XHRqueue.length) { setTimeout(function(){ sendXHR(XHRqueue.shift()); },0); setTimeout(function(){ sendXHR(XHRqueue.shift()); },400); } XHRqueue.push({R,id,v}); } // END getRatings() var v, pc, tot, A={}, A0={}, A8={}, voters, votersL, h=[-1,-1], H=[], mod; function fill_H(a) { H=[]; for (let k in a) { H.push( ('000000000'+a[k].tot).substr(-10) +'_'+ ('0'+k).substr(-2) ); } H.sort().reverse(); for (let i in H) H[i]=[ parseInt(H[i].split('_')[1]), parseInt(H[i].split('_')[0])]; } function parse(s,voters='') { var parser=new DOMParser(), S=Date.now(), h=parser.parseFromString(s, 'text/html'), data=h.querySelectorAll('table td'), fData=h.querySelector('#__NEXT_DATA__'), R={}; if (fData) { try { fData=JSON.parse(fData.textContent).props.pageProps.contentData.histogramData; }catch(e){fData=null;} } // extract rating value % tot var i, j, k; k=pc=tot=null; A={}; A0={}; h=[-1,-1]; /*H=[];/**/ // formatted data (starting 2023-05) if (fData) { let A=fData.histogramValues; for (let i=0; A[i]; i++) { A0[A[i].rating]={k:A[i].rating, pc:'-', tot: A[i].voteCount}; } } // error in parsing else if ( !data[0] || ((v=parseInt(data[0].innerText)) !==10) ) { R.status='data unavailable'; R.maxAge=S+3600000; // +1h for (k=1; k<11 ; k++) { A0[k]={k,pc:0,tot:0}; } } else for (i=0; v=data[i].innerText; i++) { if (k==null) k=parseInt(v); else if (pc==null) pc=parseFloat(v) || 0; else if (tot==null) { tot=parseInt(v.replace(/\D/g,'')) || 0; if (tot>h[1]) h=[k,tot]; A0[k]={k,pc,tot}; if (k==1) break; k=pc=tot=null; } } data=h=null; fill_H(A0); let d=new Date(), key=id+voters; let ep=document.querySelector('[class*="EpisodeNavigationForEpisode__SeasonEpisodeNumbers-"]') || ''; if (ep) ep=ep.innerText.replace(/^.*?(\d+).*?(\d+).*$/s, '$1.$2'); let t=d.getFullYear()+'/'+String(d.getMonth() + 1).padStart(2, '0')+'/'+ String(d.getDate()).padStart(2, '0') +' '+ String(d.getHours()).padStart(2, '0')+':'+String(d.getMinutes()).padStart(2, '0'); Object.assign(R, {t:S, key, cmt: t +' -- '+ ( tit? tit : document.title.replace(/ +- +imdb *$/i,'').replace(/"(.+?)"/, ep?'$1 - '+ep+' -':'$1') ) , data:JSON.stringify({A0,H}) }); GM_setValue(key, R); fill_vars(R); upd_ratings(); // upd cache date upd_dialog(); } // END parse() function upd_ratings() { if (!ratings || !ratings.key || (ratings.key != id+opts.voters) ) { loadRatings(); return; } A=JSON.parse(JSON.stringify(A0)); mod=false; if (opts.k10_maxmax && (H[0][0]==10) ) { if (A[9].tot < (A[10].tot * opts.k9_pc_10 /100) ) { delete A[10]; mod=true; } } if (opts.k10_max && (H[0][0]==10) ) { let noCv=true; if (noCv) { delete A[10]; mod=true; if (H[1][0]==9) { let _9=A[9].tot, _7=A[7].tot; if (opts.k9_7_pcOn && opts.k9_7_pc) if (A[7].tot / H[1][1] < (opts.k9_7_pc / 100) ) {delete A[9]; mod=true;} } } } if ( (H[0][0]==9) && opts.k9_max_do) { let _9=A[9].tot, _10=A[10].tot; if (opts.k9_max) { delete A[9]; mod=true; } if (opts.k9_max_10) { delete A[10]; mod=true; } else if (opts.k10_9_pcOn && opts.k10_9_pc) if (_10 >= (_9 * opts.k10_9_pc / 100) ) {delete A[10]; mod=true;} } if (opts.k10) delete A[10]; if (opts.k1) delete A[1]; var e, newR=0, newRAlt=0; tot=v=0; for (let i in A) { let k=A[i]; tot += k.tot; v += k.k * k.tot; } // !!!!! temp mod=true; newR=(v/tot) || 0; for (let i in A) { let k=A[i]; newRAlt += k.k * k.tot / tot; } waiting(false); if (e=rt) { if (!e.style.cssText) { e.style='--oldSc:"'+e.innerText+'"'; e.oldV=e.innerText; if (decSep) e.oldV=e.oldV.replace( new RegExp('\\'+decSep), '.'); } let t=newR && newR.toFixed(1); if (o.no0) t=t.replace(/\.0$/,''); e.curV=t; e.innerText= t || '!'; e.classList.toggle('noMod',t == e.oldV); } if (e=tv) { if (!e.style.cssText) { e.style='--oldSc:"'+e.innerText+'"'; e.oldV=e.innerText; if (thSep) e.oldV=e.oldV.replace( new RegExp('\\'+thSep,'g'), ''); if (decSep) e.oldV=e.oldV.replace( new RegExp('\\'+decSep), '.'); } let t = (o.divide && tot)? round(tot) : tot; e.curV=t; e.innerText=t || '!'; e.classList.toggle('noMod', parseFloat(t) == parseFloat(e.oldV) ); } // upd cache date upd_dialog(); } // END upd_ratings() function round(n) { var U=''; for (let u of ['K','M']) { if (n>1000) { n=(n/1000).toFixed( n<10000? 1:0 ); U=u; } } return n.toString().replace(/\.0$/,'')+U; } function fill_vars(v) { ratings=v; ratings.data=JSON.parse(ratings.data); A0=ratings.data.A0; H=ratings.data.H; } function purge_cache() { purging=false; var all=GM_listValues(), purge=1000*60*60* (opts.purge||8), now=Date.now(); for (let i of all) { let d=GM_getValue(i); if (d && d.t && ( (d.t + purge < now ) || (d.maxAge && (d.maxAge < now)) ) ) { GM_deleteValue(i); } } } function getValues(k) { ratings=GM_getValue(k, false); let now=Date.now(); if (ratings && ( (ratings.t + (1000*60*60* (opts.purge||8)) < now) || (ratings.maxAge && (ratings.maxAge < now) ) ) ) { return 0; } return Boolean(ratings); } function loadRatings() { var unk=[]; if (!voters) { A8={}; ratings8={t:[], key:id+opts.voters, data:{}}; if (opts.voters=='usnus') { voters=['us','nus']; } else voters=[opts.voters]; votersL=voters.length; } for (let i=0,vt; i < voters.length; i++) { vt=voters[i]; if (!getValues(id+vt)) { unk.push(vt); if (ratings) { ratings=null; } if (voters.length == votersL) { getRatings(id, vt); if (!purging) setTimeout(purge_cache,3000); purging=true; } continue; } fill_vars(ratings); if (votersL > 1) { merge_A(); ratings8.t.push(ratings.t); } else unk=null; } voters=unk; if (votersL > 1) { if (!voters.length) { voters=null; ratings=ratings8; A0=ratings.data.A0=A8; fill_H(A0); ratings.data.H=H; } } if (!voters) { upd_ratings(); } } function merge_A() { for (let k in A0) { let a=A8[k], b=A0[k]; if (!a && !b) return; A8[k]={k, 'tot': (a?a.tot:0)+b.tot}; } } var ratings, ratings8, id, re= /^\/title\/([^\/]+)\/(rating)?/.exec(href); if (re && re[1]) { id=re[1]; loadRatings(); } // exit if dialog already created. if (dialog) return; dialog=document.createElement('div'); dialog.id='fix_rating_opt'; dialog.innerHTML=`<div id="close">❎</div> <!--h3>(Userscript) Fix rating - Settings</h3><!--> <b id="hdr">Fix rating - Settings</b><hr><br> <hr> Count votes from: <select name="voters"><option value="">all voters</option> <option disabled title="Currently disabled with new design" value="us">US voters</option> <option disabled title="Currently disabled with new design" value="nus">non-US voters</option> <option disabled title="Currently disabled with new design" value="top">Top 1000 voters</option> <option disabled title="Currently disabled with new design" value="usnus">US & non-US voters</option></select> <hr> <input name="k10" type="checkbox" data-group="10">Ignore "10"<br> <input name="k10_max" type="checkbox" data-group="10">Ignore "10" if is highest count<br> <input name="k10_maxmax" type="checkbox" data-group="10">... "10" highest and if "9" is < <input name="k9_pc_10" type="number" min="1" max="99">% of "10"<br> <input name="k1" type="checkbox">Ignore "1"<br> <hr> <b>If "9" is highest : </b><input name="k9_max_do" type="checkbox"> <div class="mrg"><input name="k9_max" type="checkbox">discard "9"<br> <input name="k9_max_10" type="checkbox" data-group="9_10">discard "10"<br> <input name="k10_9_pcOn" type="checkbox" data-group="9_10">discard "10" if >= <input name="k10_9_pc" type="number" min="1" max="99">% of "9"</div> <hr> Expire cached values after <input name="purge" type="number" data-norld min="1" max="99"> hours <hr> <nobr><input type="button" id="rldSettings" value="Reload settings"> (if modified in another window)</nobr><br> <input type="button" id="reset" value="Reset to default"><br> <hr> <span>Rating values cached on: <span id="cached"></span></span><br> <input type="button" id="clrCache" value="Refresh cache"><br class="show"><hr class="show"><br> <div class="show"> <input type="checkbox" name="search" data-norld>Enable on "search" (need page reload)<br> <input type="checkbox" name="chart" data-norld>Enable on "chart" (need page reload)<br> <input type="checkbox" name="list" data-norld>Enable on "list" (need page reload)</div> `; dialog.querySelector('#close').onclick=function(){dialog.remove();dialog.style='';}; dialog.querySelector('#rldSettings').onclick=function(){ getOpts(); upd_dialog(); upd_ratings(); getListRating(); }; dialog.querySelector('#clrCache').onclick=function(){ getRatings(id, opts.voters); }; dialog.querySelector('#reset').onclick=function(){ if (!confirm("Reset? You'll lose your changes.")) return; GM_deleteValue('opts'); getOpts(); upd_dialog(); upd_ratings(); getListRating(); }; var cached=dialog.querySelector('#cached'); function upd_opts(e) { let k=e.name; if (k in opts) { if (e.type=='checkbox') opts[k]=e.checked; else opts[k]=e.value; } } dialog.addEventListener('change', function(ev){ let t=ev.target, g; if (g=t.dataset.group) { let a=dialog.querySelectorAll('[data-group="'+g+'"]:checked'); a.forEach(function(e){ if (e!==t) { e.checked=false; upd_opts(e); } }); } upd_opts(t) GM_setValue('opts', opts); if ('norld' in t.dataset) return; upd_ratings(); getListRating(); }); var x=0, y=0, move=dialog.querySelector('#hdr'); function moving(ev) { var st=dialog.style; var Y= (E?ev.pageY:ev.clientY) -y, X= (E?ev.pageX:ev.clientX) -x; if ( (Y<0) || (X<0) ) return; st.top=Y+'px'; st.left=X+'px'; st.margin='0'; } move.onmousedown=function(ev){ // ignore if not left click if (ev.buttons != 1) return; ev.preventDefault(); var cCss=window.getComputedStyle(dialog); x=ev.offsetX+parseInt(cCss.borderLeftWidth); y=ev.offsetY+parseInt(cCss.borderTopWidth); document.body.addEventListener('mousemove', moving); dialog.onmouseup=mouseup; dialog.classList.add('grabbed'); } function mouseup(ev){ document.body.removeEventListener('mousemove', moving); dialog.onmouseup=null; dialog.classList.remove('grabbed'); } function fixed(s,n) { return ('000'+s).substr(- n); } function upd_dialog() { if (!dialog) return; for (let k in opts) { let e=dialog.querySelector('[name="'+k+'"]'); if (e) { if (e.type=='checkbox') e.checked=opts[k]; else e.value=opts[k]; } } if (cached && ratings) { let s='', a=ratings.t || []; if (!Array.isArray(a)) a=[a]; for (let t of a) { t=new Date(t); if (s) s+='<br>'; s+=t.getFullYear()+'/'+ fixed(t.getMonth()+1,2) +'/'+ fixed(t.getDate(),2) +' '+fixed(t.getHours(),2)+':'+fixed(t.getMinutes(),2); } cached.innerHTML=s; } } upd_dialog(); } // END display() })();