Samlib Reader

Делает самиздатовские текста более читабельными: смена фона на тёмный, смена шрифта на verdana, смена цвета текста на светлый, текст выровнен по ширине строки, добавлен автоматический перенос слов. Дополнительно добавлено окно настроек, позволяющее изменить ширину текста, тип и размер шрифта, цвет общего фона страницы, а также принудительно сменить цвет текста, в случае, когда автор вручную установил цвет части текста

Versión del día 16/1/2021. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name Samlib Reader
// @description Делает самиздатовские текста более читабельными: смена фона на тёмный, смена шрифта на verdana, смена цвета текста на светлый, текст выровнен по ширине строки, добавлен автоматический перенос слов. Дополнительно добавлено окно настроек, позволяющее изменить ширину текста, тип и размер шрифта, цвет общего фона страницы, а также принудительно сменить цвет текста, в случае, когда автор вручную установил цвет части текста
// @copyright 2019, Angens (https://openuserjs.org/users/angens)
// @license MIT
// @version 2.1.1
// @include /^http:\/\/(zhurnal\.lib\.ru|samlib\.ru|budclub\.ru)\/.\/\w+\/\w*\.shtml/
// @exclude /^http:\/\/(zhurnal\.lib\.ru|samlib\.ru|budclub\.ru)\/.\/\w+\/(index\w*|stat\w*)\.shtml/
// @grant none
// @namespace https://greasyfork.org/users/386214
// ==/UserScript==
//
// ==OpenUserJS==
// @author angens
// ==/OpenUserJS==



/*
 *  Функция для работы с форматом
 */
function changer(){
  
  // Прописываем в тело возможность переноса слов
  document.querySelector("body").setAttribute("lang", "ru");
  document.querySelector("body").setAttribute("style", "-moz-hyphens: auto; -webkit-hyphens: auto; -ms-hyphens: auto; white-space: unset;");
  
  /*
   * Блок работы с описанием
   */
  
  // Ищем комментарии на первом уровне тела
  let numOfComments = 0;
  let lastComment;
  let bodyChildren = document.body.childNodes;
  for (let i = 0; i < bodyChildren.length; i++){
    let node = bodyChildren[i];
    if (node.nodeType === 8){
      numOfComments++;
      lastComment = node;
    }
  }
  
  // Создаём блок описания
  let description = document.createElement('div');
  description.id = "SamLibReaderDescription"; 
  
  // Если комментарии начала и конца произведения дети body — сразу записываем всё под нижним комментарием в блок описания
  if(numOfComments === 2){
    while(lastComment.nextSibling){
      description.append(lastComment.nextSibling);
    }
  }
  
  // Ищем комментарий описания и находим главный блок. Все последующие отправляем в блок описания
  if(numOfComments === 1){
    let treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false);
    
    while (treeWalker.nextNode()){
      if (treeWalker.currentNode.nodeType === 8){
        if (treeWalker.currentNode.nodeValue == "-- Блок описания произведения (слева внизу) ---------------------"){
          let node = treeWalker.currentNode.parentElement.parentElement.parentElement;
          while(node.nextSibling){
            description.append(node.nextSibling);
          }
          description.insertBefore(node, description.firstChild);
        }
      }
    }
  }
    
  
  /*
   *  Блок работы с текстом
   */
  // Блок работы с произведением
  let nodes = document.querySelectorAll("dd, p");
 
  let new_element = document.createElement('div');
 
  new_element.id = "SamLibReader";
  new_element.style.color = "wheat";
  new_element.style.fontSize = "18px";
  new_element.style.fontFamily = "verdana";
  new_element.style.backgroundColor = "#212127";
  new_element.style.width = '40%';
  new_element.style.marginLeft = 'auto';
  new_element.style.marginRight = 'auto';  
  new_element.style.padding = "5%";
  new_element.style.textAlign = "justify";
  
  if(nodes[0])
    nodes[0].parentElement.insertBefore(new_element, nodes[0]);
 
  for (let i = 0; i < nodes.length; i++){
    new_element.append(nodes[i]);
  }
  
  document.body.append(description);
  
  /*
   *  Блок работы с тегом <pre>
   */
  let pre = document.querySelectorAll("pre");
  for (let i = 0; i < pre.length; i++){
    pre[i].style.marginLeft = 'auto';
    pre[i].style.marginRight = 'auto';
    pre[i].style.width = 'min-content';
    pre[i].style.color = "wheat";
    pre[i].style.fontSize = "18px";
    pre[i].style.fontFamily = "roboto condensed, verdana";
    pre[i].style.backgroundColor = "#212127";
    pre[i].style.padding = '5%';
  }
  
  addControls();
}

/*
 *  Функция работы с панелью управления
 */
function addControls(){
  
  /*
   *  Добавление блоков
   */
  // Добавление общего блока панели
  let showHide = document.createElement('div');
  showHide.style.position = 'fixed';
  //showHide.style.backgroundColor = 'rgba(0, 0, 0, 0.3)';
  showHide.style.width = 'min-content';
  showHide.style.height = 'min-content';
  showHide.style.right = '0px';
  showHide.style.top = '50%';  
  document.body.append(showHide);
  
  // Кнопка скрытия/раскрытия панели
  let showBtn = document.createElement('button');
  showBtn.style.width = '100px';
  showBtn.style.height = '40px';
  showBtn.textContent = 'Настройки';
  showBtn.addEventListener('mouseenter', (event) => event.target.style.borderColor = 'green');
  showBtn.addEventListener('mouseleave', (event) => event.target.style.borderColor = '#778beb');
  showBtn.style.fontWeight = 'bold';
  showHide.append(showBtn);
  
  // Внутренний блок, который скрывается/раскрывается
  let controlPanel = document.createElement('div');
  controlPanel.style.display = 'none';
  //controlPanel.style.height = '100px';
  
  // Кнопки ширины текста
  let sizeButtons = document.createElement('div');
  let buttons = [];
  for (let i = 0; i < 3; i++){
    let tmpBtn = document.createElement('button');
    tmpBtn.style.float = 'left';
    tmpBtn.style.width = 100/3 + "%";
    tmpBtn.textContent = i * 10 + 30 + "%";
    buttons.push(tmpBtn);
    sizeButtons.append(buttons[i]);
  }
  
  // Слайдер ширины текста
  let sliderBlock = document.createElement('div');
  let slider = document.createElement('input');
  slider.addEventListener('change', () => {
    document.getElementById('SamLibReader').style.width = slider.value + "%";
  });
  slider.type = 'range';
  slider.min = '1';
  slider.max = '100';
  slider.value = 40;
  slider.id = 'textWidth';
  slider.style.width = '350px';
  sliderBlock.append(slider);
  
  // Комбобокс с выбором шрифта
  let choiceBlock = document.createElement('div');
  choiceBlock.style.width = 'min-content';
  choiceBlock.style.margin = 'auto';
  let comboBox = document.createElement('select');
  let fontChoice = ['verdana', 'roboto', 'roboto condensed'];
  let options = [];
  for (let i = 0; i < fontChoice.length; i++){
    let opt = document.createElement('option');
    opt.text = fontChoice[i];
    options.push(opt);
    comboBox.add(options[i], comboBox[i]);
  }
  choiceBlock.append(comboBox);
  
  // Размер шрифта
  let fontSize = document.createElement('div');
  let btnMinus = document.createElement('button');
  let sizeBox = document.createElement('a');
  let btnPlus = document.createElement('button');
  fontSize.style.width = '86px';
  fontSize.style.margin = 'auto';
  
  btnMinus.style.float = 'left';
  btnMinus.textContent = "-";
  btnMinus.style.width = '30px';
  btnMinus.style.textAlign = 'center';
  
  btnPlus.style.flost = 'left';
  btnPlus.textContent = "+";
  btnPlus.style.width = '30px';
  btnPlus.style.textAlign = 'center';
  
  sizeBox.style.float = 'left';
  sizeBox.style.display = 'block';
  sizeBox.style.width = '24px';
  sizeBox.style.height = '22px';
  sizeBox.textContent = '18';
  sizeBox.style.textAlign = 'center';
  
  fontSize.append(btnMinus);
  fontSize.append(sizeBox);
  fontSize.append(btnPlus);
  
  // Сделать весь фон тёмным
  let bgBlock = document.createElement('div');
  let bgCheckBox = document.createElement('input');
  let bgLabel = document.createElement('label');
  bgCheckBox.type = 'checkbox';
  bgCheckBox.name = 'bgCheckbox';
  bgCheckBox.borderRadius = '5px';
  bgLabel.for = 'bgCheckbox';
  bgLabel.textContent = "Сделать весь фон тёмным";
  bgBlock.append(bgCheckBox);
  bgBlock.append(bgLabel);
  
  // Принудительная смена текста шрифта
  let fntBlock = document.createElement('div');
  fntBlock.style.width = '350px';
  let fntCheckBox = document.createElement('input');
  let fntLabel = document.createElement('label');
  fntCheckBox.type = 'checkbox';
  fntCheckBox.name = 'fntCheckbox';
  fntLabel.for = 'fntCheckbox';
  fntLabel.textContent = "Принудительно сменить цвет шрифта в тексте";
  fntBlock.append(fntCheckBox);
  fntBlock.append(fntLabel);
  
  // Добавление блоков опций в панель
  if (document.getElementById('SamLibReader')){
    controlPanel.append(sizeButtons);
    controlPanel.append(sliderBlock);
  }
  controlPanel.append(choiceBlock);
  controlPanel.append(fontSize);
  controlPanel.append(bgBlock);
  if (document.getElementById('SamLibReader'))
    controlPanel.append(fntBlock);
  showHide.append(controlPanel);
  
  /*
   *  Функционал
   */
  // Управление отображением панели
  function isElementHidden (element) {
    return window.getComputedStyle(element, null).getPropertyValue('display') === 'none';
  }  
  showBtn.addEventListener('click', () => {
    if (isElementHidden(controlPanel)){
      controlPanel.style.display = 'block';
      showHide.style.backgroundColor = 'rgba(0, 0, 0, 0.3)';
      showHide.style.borderRadius = "7px"
      showBtn.textContent = 'Скрыть';
    } else {
      controlPanel.style.display = 'none';
      showHide.style.backgroundColor = 'rgba(0, 0, 0, 0)';
      showBtn.textContent = 'Настройки';
    }
  });
  
  // Управление шириной текста
  for (let i = 0; i < 3; i++){
    buttons[i].addEventListener('click', () => {
      document.getElementById('SamLibReader').style.width = buttons[i].textContent;
      slider.value = 30 + i * 10;
    });    
  }
  
  // Смена шрифта
  comboBox.addEventListener('change', (event) => {
    if(document.getElementById('SamLibReader')){
      document.getElementById('SamLibReader').style.fontFamily = event.target.value;
    }
    if(document.querySelector('pre')){
      document.querySelector('pre').style.fontFamily = event.target.value;
    }
  });
  
  // Смена размера
  btnMinus.addEventListener('click', () => {
    if(sizeBox.textContent != 6){
      sizeBox.textContent = Number(sizeBox.textContent) - 2;
      if (document.getElementById('SamLibReader'))
        document.getElementById('SamLibReader').style.fontSize = sizeBox.textContent;
      if (document.querySelector('pre'))
        document.querySelector('pre').style.fontSize = sizeBox.textContent;
    }
  });
  btnPlus.addEventListener('click', () => {
    if(sizeBox.textContent != 32){
      sizeBox.textContent = Number(sizeBox.textContent) + 2;
      if (document.getElementById('SamLibReader'))
        document.getElementById('SamLibReader').style.fontSize = sizeBox.textContent;
      if (document.querySelector('pre'))
        document.querySelector('pre').style.fontSize = sizeBox.textContent;
    }
  });
  
  // Смена общего фона
  bgCheckBox.addEventListener('change', () => {
    if(bgCheckBox.checked){
      document.querySelector("body").style.backgroundColor = "#212127";
      document.querySelector("body").setAttribute("link", "gray");
      document.querySelector("body").setAttribute("vlink", "#C6B2D4");
      document.querySelector("body").style.color = 'white';
    }else{
      document.querySelector("body").style.backgroundColor = "#E9E9E9";
      document.querySelector("body").setAttribute("link", "0000EE");
      document.querySelector("body").setAttribute("vlink", "#551A7E");
      document.querySelector("body").style.color = 'black';     
    }
  });
  
  // Принудительная смена цвета шрифта
  let fonts = document.getElementById('SamLibReader').getElementsByTagName('font');
  let fontsColors = [];
  for (let i = 0; i < fonts.length; i++)
    fontsColors.push(fonts[i].getAttribute('color'));
  fntCheckBox.addEventListener('change', () => {
    if(fntCheckBox.checked){
      for (let i = 0; i < fonts.length; i++)
        fonts[i].setAttribute('color', 'wheat');
    }else{
      for (let i = 0; i < fonts.length; i++)
        fonts[i].setAttribute('color', fontsColors[i]);
    }
  });
}
 
 
document.addEventListener("DOMContentLoaded", changer());