您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
View html immediately
当前为
- // ==UserScript==
- // @name CF-Html-Viewer
- // @version 0.3.1
- // @description View html immediately
- // @author Iverycool
- // @namespace Cyberforum
- // @match https://www.cyberforum.ru/*
- // @grant none
- // ==/UserScript==
- (function() {
- const $ = (sec, node = document) => node.querySelector(sec);
- const $$ = (sec, node = document) => node.querySelectorAll(sec);
- const size = 1.4;
- // const isFF = ~navigator.userAgent.search(/firefox/i);
- const styles = {
- but: 'color: rgb(96, 96, 96); font-weight: normal; margin-left: 5px;',
- rightBut: 'color: rgb(96, 96, 96); font-weight: normal; float: right;',
- frame: 'display: block; width: 100%;',
- textarea: getStyleString({
- 'position': 'absolute',
- 'margin': 0,
- 'padding': 0,
- 'border': 'transparent',
- 'background': 'transparent',
- 'color': 'transparent',
- 'font-family': 'Consolas,Monaco,\'Andale Mono\',\'Ubuntu Mono\',monospace',
- 'font-size': '1em',
- 'line-height': size + ' !important',
- 'white-space': 'pre',
- 'caret-color': 'black',
- 'outline': 'none',
- 'resize': 'none'
- })
- }
- const sels = {
- codeFrame: 'div.codeframe',
- codePre: 'td.de1 > pre.de1',
- lnPre: 'td.ln > pre.de1'
- }
- document.addEventListener('DOMContentLoaded', () => {
- // debugger;
- init().then(() => $$('#posts div[id^="post_message_"]').forEach(register));
- });
- function init() {
- const prismStyle = createElem('link', document.head);
- prismStyle.rel = 'stylesheet';
- prismStyle.href = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism.min.css';
- const myStyle = createElem('style', document.head);
- myStyle.innerHTML = 'pre.de1, pre.de1 * { line-height: ' + size + ' !important }' +
- ['html5', 'phphtml', 'css', 'javascript'].map(name =>
- `table.${name} > tbody {background: #f5f2f0 !important}`
- ).join('');
- const prismScript = createElem('script', document.head);
- prismScript.type = 'text/javascript';
- prismScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/prism.min.js';
- return new Promise(res => prismScript.onload = res);
- }
- function register(post) {
- const viewer = new Viewer();
- const htmlNodes = $$('table.html5, table.phphtml', post);
- const cssNodes = $$('table.css', post);
- const jsNodes = $$('table.javascript', post);
- htmlNodes.forEach(htmlNode => {
- makeViewerLink(viewer, htmlNode);
- makeEditableLink(viewer, htmlNode, 'html');
- stylize(htmlNode, 'html');
- });
- cssNodes.forEach(cssNode => {
- makeUseLink(viewer, cssNode, 'style');
- makeEditableLink(viewer, cssNode, 'css');
- stylize(cssNode, 'css');
- });
- jsNodes.forEach(jsNode => {
- createLink({
- parentNode: $('.head', jsNode),
- style: styles.but,
- text: 'Выполнить',
- onClick: () => eval($(sels.codePre, jsNode).innerText)
- });
- makeUseLink(viewer, jsNode, 'script');
- makeEditableLink(jsNode, 'js');
- stylize(jsNode, 'js');
- });
- }
- class Viewer {
- style = [];
- script = [];
- mounted = false;
- create(parent, htmlCode, onClose = () => {}) {
- this.clean();
- this.mounted = true;
- this.html = htmlCode.replace(/ /g, '');
- this.container = createElem('tfoot', parent);
- createLink({
- parentNode: this.container,
- style: styles.but,
- text: 'Открыть в новом окне',
- onClick: () => this.openInNewWin()
- });
- createLink({
- parentNode: this.container,
- style: styles.but,
- text: 'Скачать страницу',
- onClick: () => this.download()
- })
- createLink({
- parentNode: this.container,
- style: styles.rightBut,
- text: 'Закрыть',
- onClick: () => (this.clean(), onClose())
- });
- this.iframe = createElem('iframe', this.container);
- this.iframe.style = styles.frame;
- this.update();
- }
- clean() {
- if (this.container) this.container.remove();
- this.iframe = null;
- this.doc = null;
- this.html = '';
- this.mounted = false;
- }
- add(id, code, type) {
- if (!this.mounted) return false;
- const ind = this[type].findIndex(el => el[0] == id);
- if (~ind) {
- this[type].splice(ind, 1, [id, code.replace(/ /g, '')])
- } else {
- this[type].push([id, code.replace(/ /g, '')]);
- }
- this.update();
- return true;
- }
- has(id, type) {
- return !!(~this[type].findIndex(el => el[0] == id));
- }
- remove(id, type) {
- const ind = this[type].findIndex(el => el[0] == id);
- const res = (~ind) ? !!this[type].splice(ind, 1) : false;
- this.update();
- return res;
- }
- update(code) {
- if (!this.mounted) return;
- if (code) this.html = code;
- const str = this._compile();
- this.iframe.src = 'about:blank';
- this.iframe.onload = () => {
- this.doc = this.iframe.contentWindow.document;
- this.doc.write(str);
- this.doc.close();
- this.updateFrameHeight();
- }
- }
- updateFrameHeight() {
- const coords = getCoords(this.doc.body.lastElementChild, this.iframe.contentWindow);
- const contentHeight = coords.top + coords.height;
- const frameHeight = (contentHeight > 500) ? '500px' : contentHeight + 16 + 'px';
- this.iframe.style.height = frameHeight;
- }
- openInNewWin() {
- const str = this._compile();
- const win = window.open('about:blank');
- win.onload = () => {
- win.document.write(str);
- win.document.close();
- }
- }
- download() {
- const str = this._compile();
- const id = this.container.parentElement.querySelector(sels.codeFrame).id;
- const a = createElem('a');
- a.download = `doc-${id}.html`;
- a.href = 'data:text/html;charset=UTF-8,' + str;
- a.click();
- a.remove();
- }
- _compile() {
- const wrap = (arr, type) =>
- arr.map(([,code]) => `<${type}>${code}</${type}>`).join('');
- return wrap(this.style, 'style') + wrap(this.script, 'script') + this.html;
- }
- }
- function stylize(node, type) {
- const pre = $(sels.codePre, node);
- const code = Prism.highlight(pre.innerText, Prism.languages[type]);
- pre.classList.add(`language-${type}`);
- pre.innerHTML = `<code class="language-${type}">${code}</code>`;
- updateCodeFrameHeight($(sels.codeFrame, node));
- }
- function updateCodeFrameHeight(div) {
- const conHeight = getCoords(div.firstChild).height;
- div.style.height = ((conHeight > 570) ? 590 : conHeight + 20) + 'px';
- }
- function makeViewerLink(viewer, htmlNode) {
- const makeObj = {
- text: 'Показать viewer',
- onClick: function() {
- viewer.create(htmlNode, $(sels.codePre, htmlNode).innerText, () => {
- this.update(makeObj);
- });
- this.update(unMakeObj);
- }
- }
- const unMakeObj = {
- text: 'Обновить viewer',
- onClick: () => viewer.update($(sels.codePre, htmlNode).innerText)
- }
- createLink({
- parentNode: $('.head', htmlNode),
- style: styles.but,
- ...makeObj
- });
- }
- function makeUseLink(viewer, codeNode, type) {
- const id = $(sels.codeFrame, codeNode).id;
- const useObj = {
- text: 'Использовать в viewer',
- onClick: function() {
- if (viewer.add(id, $(sels.codePre, codeNode).innerText, type)) {
- this.update(unUseObj);
- }
- }
- }
- const unUseObj = {
- text: 'Отвязать от viewer',
- onClick: function() {
- viewer.remove(id, type);
- this.update(useObj);
- }
- }
- createLink({
- parentNode: $('.head', codeNode),
- style: styles.but,
- ...useObj
- });
- }
- function makeEditableLink(viewer, node, type) {
- const id = $(sels.codeFrame, node).id;
- let textarea, autoReloadingLink;
- const makeObj = {
- text: 'Редактировать',
- onClick: function() {
- textarea = makeInput($(sels.codePre, node), type);
- this.update(unMakeObj);
- autoReloadingLink = makeAutoReloadingLink();
- }
- }
- const unMakeObj = {
- text: 'Отменить редактирование',
- onClick: function() {
- textarea.remove();
- autoReloadingLink.remove();
- this.update(makeObj);
- }
- }
- createLink({
- parentNode: $('.head', node),
- style: styles.but,
- ...makeObj
- });
- function makeAutoReloadingLink() {
- const makeObj = {
- style: styles.but + 'color: rgb(130, 130, 130);',
- text: 'AutoReloading - off',
- onClick: function() {
- textarea.onInput = function(text) {
- if (type === 'html') {
- viewer.update(text);
- } else {
- viewer.add(id, text, type === 'js' ? 'script' : 'style');
- }
- }
- this.update(unMakeObj);
- }
- };
- const unMakeObj = {
- style: styles.but + 'color: green',
- text: 'AutoReloading - on',
- onClick: function() {
- textarea.onInput = null;
- this.update(makeObj);
- }
- };
- return createLink({
- parentNode: $('.head', node),
- ...makeObj
- });
- }
- }
- function makeInput(pre, type, onInput = () => {}) {
- const div = pre.closest(sels.codeFrame);
- const lnPre = div.querySelector(sels.lnPre);
- const textarea = createElem('textarea', pre.parentElement);
- const divScroll = {
- left: div.scrollLeft,
- top: div.scrollTop
- }
- div.scrollTo(0, 0);
- const preCoords = getCoords(pre);
- const divCoords = getCoords(div);
- const paddingLeft = preCoords.left - divCoords.left;
- const paddingTop = preCoords.top - divCoords.top;
- textarea.style = styles.textarea + getStyleString({
- 'padding-left': paddingLeft + 'px',
- 'padding-top': paddingTop + 'px'
- });
- updateTextarea();
- textarea.spellcheck = false;
- textarea.value = pre.innerText;
- textarea.scrollTo(divScroll.left, divScroll.top);
- div.scrollTo(divScroll.left, divScroll.top);
- textarea.oninput = () => {
- const text = textarea.value;
- const textLen = text.split('\n').length;
- const code = Prism.highlight(text, Prism.languages[type]);
- pre.innerHTML = `<code class="language-${type}">${code}</code>`;
- lnPre.innerText = new Array(textLen).fill(1).map((_, i) => i + 1).join('\n');
- (textarea.onInput || onInput)(text);
- updateCodeFrameHeight(div);
- updateTextarea();
- }
- textarea.onscroll = () => div.scrollTo(textarea.scrollLeft, textarea.scrollTop);
- function updateTextarea() {
- const tStyle = textarea.style;
- const divCoords = getCoords(div);
- tStyle.width = divCoords.width - paddingLeft + 'px';
- tStyle.height = divCoords.height - paddingTop + 'px';
- tStyle.left = divCoords.left + 'px';
- tStyle.top = divCoords.top + 'px';
- }
- return textarea;
- }
- // Utils
- function createElem(name, parentNode = document.documentElement) {
- const elem = document.createElement(name);
- parentNode.appendChild(elem);
- return elem;
- }
- function createLink({parentNode = document.documentElement, style, text, onClick = () => {}}) {
- const a = createElem('a', parentNode);
- a.style = style;
- a.href = '#';
- a.innerText = text;
- a.onclick = function(ev) {
- ev.preventDefault();
- onClick.call(a, ev);
- }
- a.update = function({style: newStyle, text: newText, onClick: newOnClick}) {
- a.style = newStyle || style;
- a.innerText = newText || text;
- a.onclick = function(ev) {
- ev.preventDefault();
- (newOnClick || onClick).call(a, ev);
- }
- }
- return a;
- }
- function getStyleString(obj) {
- return Object.entries(obj).reduce((str, [key, value]) => str + `${key}:${value};`, '');
- }
- function getCoords(elem, win = window) {
- const box = elem.getBoundingClientRect();
- return {
- top: box.top + win.pageYOffset,
- left: box.left + win.pageXOffset,
- width: box.width,
- height: box.height
- }
- }
- })();