Samlib Reader

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

Pada tanggal 16 Januari 2021. Lihat %(latest_version_link).

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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());