JSON.stringify((() => { // Снимок страницы «как на сайте»: UTF-8, , таблицы стилей вынесены в css[] const root = document.documentElement.cloneNode(true); const css = []; const orig = [...document.querySelectorAll('link[rel~="stylesheet"]')]; const copy = [...root.querySelectorAll('link[rel~="stylesheet"]')]; orig.forEach((l, i) => { try { const rules = l.sheet && l.sheet.cssRules; if (!rules) return; let text = ''; for (const r of rules) text += r.cssText + '\n'; text = text.replace(/url\((['"]?)(?!data:|https?:|\/\/)([^)'"]+)\1\)/g, (m, q, u) => { try { return 'url(' + q + new URL(u, l.sheet.href) + q + ')'; } catch (e) { return m; } }); css.push(text); copy[i].setAttribute('href', '@@CSS' + (css.length - 1) + '@@'); } catch (e) { /* таблица чужого домена: оставляем исходную ссылку */ } }); root.querySelectorAll('script').forEach(x => x.remove()); // страница из файла не должна уходить на сайт const head = root.querySelector('head'); root.querySelectorAll('meta[charset], meta[http-equiv="Content-Type" i]').forEach(m => m.remove()); if (head) { const meta = document.createElement('meta'); meta.setAttribute('charset', 'utf-8'); head.insertBefore(meta, head.firstChild); const old = root.querySelector('base'); if (old) { // «//host/path» в файле стал бы file://host/… old.setAttribute('href', document.baseURI); } else { const base = document.createElement('base'); base.href = document.baseURI; head.insertBefore(base, meta.nextSibling); } } return { html: '' + root.outerHTML, css }; })())