openvibers/openvibe.shared look-boot.js
look-boot.js
| 1 | ; |
| 2 | /** |
| 3 | * openvibe-shared/look-boot — the look before first paint, for a page whose theme-loader.js loads late (deferred, as on |
| 4 | * Live). A tiny inline script: it paints the look this browser last painted on this site (theme-loader.js keeps it in |
| 5 | * localStorage 'ov_paint'), or the one a link from another OpenVibe page just carried (?ov_look=, read only after an |
| 6 | * OpenVibe page; theme-loader.js then keeps it and cleans the address). Colours only pass (no url(), no expression); |
| 7 | * a season whose dates are over is left for the loader. Plan L42, 4.64.0. |
| 8 | * |
| 9 | * const { BOOT, tag } = require('openvibe-shared/look-boot'); |
| 10 | * `<head>${tag()}<link rel="stylesheet" …>` first in <head>, before any stylesheet |
| 11 | * |
| 12 | * The token order is theme-loader.js's own (THEME_KEYS), read from it here so the two cannot drift. |
| 13 | */ |
| 14 | const fs = require('fs'); |
| 15 | const path = require('path'); |
| 16 | |
| 17 | const LOADER = fs.readFileSync(path.join(__dirname, 'theme-loader.js'), 'utf8'); |
| 18 | const KEYS = JSON.parse(LOADER.match(/const THEME_KEYS = (\[[^\]]+\]);/)[1].replace(/'/g, '"')); |
| 19 | |
| 20 | const BOOT = `(function(){try{var d=document.documentElement,K=${JSON.stringify(KEYS)},P=null,ok=/^(#[0-9a-f]{3,8}|rgba?\\([0-9.,\\s%]+\\)|[0-9.,\\s]+|light|dark|(-?[0-9.]+(px)?\\s+){2,4}rgba?\\([0-9.,\\s%]+\\))$/i,m=/[?&]ov_look=([^&#]+)/.exec(location.search);` |
| 21 | + `if(m&&document.referrer&&/(^|\\.)(openvibe\\.[a-z]{2,12}|openre\\.stream)$/i.test(new URL(document.referrer).hostname)&&m[1].length<4000){var L=JSON.parse(atob(decodeURIComponent(m[1]).replace(/-/g,'+').replace(/_/g,'/')));if(L&&L.v===1)P=L.p}` |
| 22 | + `if(!P)P=JSON.parse(localStorage.getItem('ov_paint')||'null');if(!P||!P.k)return;var A=P.a||{};if(A['data-ov-season']&&P.u&&Date.now()>P.u)return;` |
| 23 | + `for(var i=0;i<K.length;i++){var v=String(P.k[i]||'');if(v&&ok.test(v))d.style.setProperty(K[i],v)}` |
| 24 | + `for(var n in A)if(/^data-(theme|theme-mode|ov-[a-z-]+)$/.test(n)&&/^[a-z0-9-]{1,40}$/.test(A[n]))d.setAttribute(n,A[n]);` |
| 25 | + `if(/^[0-9.]{1,5}$/.test(P.ts||''))d.style.setProperty('--ov-text-scale',P.ts);if(P.k[0]&&ok.test(P.k[0]))d.style.background=P.k[0];if(P.k[6]&&ok.test(P.k[6]))d.style.color=P.k[6];` |
| 26 | + `if(A['data-theme-mode']==='light'||A['data-theme-mode']==='dark')d.style.colorScheme=A['data-theme-mode']}catch(e){}})();`; |
| 27 | |
| 28 | /** The inline <script> for the top of <head> (a nonce when the page's CSP uses one). */ |
| 29 | function tag({ nonce = '' } = {}) { |
| 30 | return `<script${nonce ? ` nonce="${String(nonce).replace(/[^A-Za-z0-9+/=_-]/g, '')}"` : ''}>${BOOT}</script>`; |
| 31 | } |
| 32 | |
| 33 | module.exports = { BOOT, tag, KEYS }; |
| 34 |