img2tab / img2tab

// ==UserScript==
// @name img2tab
// @version         0.60
// @license         MIT
// @description     Lightbox gallery for 4chan and image lists
// @namespace       https://openuserjs.org/scripts/img2tab/img2tab
// @homepageURL     https://openuserjs.org/scripts/img2tab/img2tab
// @downloadURL     https://openuserjs.org/install/img2tab/img2tab.user.js
// @icon            https://i.imgur.com/BSBMFSp.png
// @compatible      firefox
// @match *://boards.4chan.org/*/thread/*
// @match *://boards.4channel.org/*/thread/*
// @match *://boards.420chan.org/*/res/*
// @match *://8ch.net/*/res/*
// @match file:///*/*
// @grant none
// ==/UserScript==

var multiLineCSS = `
#lightboxGallery          {
                            display: block;
                            position: absolute;
                            left: 0;
                            top: 0;
                            z-index: 999;
                            width: 100%;
                            text-align: center;
                            background-color: black;
                            overflow: auto;
                          }

#lightboxGallery *        {
                            max-width: 100%; 
                            -moz-user-select: none;
                          }

.pcontainer               {
                            display: flex;
                            flex-direction: column;
                            justify-content: space-between;
                            align-items: center;
                          }

.pcontainer:nth-child(odd)  { background-color: #181818; }

.pcontainer:nth-child(even) { background-color: #202020; }

.pcontainer p             {
                            display: flex;
                            align-items: center;
                            justify-content: center;
                            color: #666;
                            margin: 0;
                            padding: 1em 0;
                            width: 100%;
                            min-height: 2em;
                            flex-direction: row;
                            flex-flow: row wrap;
                            flex-grow: 1;
                          }

.imageP img               { max-height: 100vh;  }

#lightboxBackground       {
                            display: flex;
                            position: fixed;
                            left: 0;
                            top: 0;
                            width: 100%;
                            height: 100%;
                            background-color: black;
                            color: white;
                            text-align: center;
                            align-items: flex-end;
                            justify-content: center;
                          }

#pgupButton,
#stretchButton,
#removeButton             {
                            color: #fff;
                            font-family: arial;
                            position: fixed;
                            opacity: 0.5;
                            font-size: 2.5em;
                            width: 1.2em;
                            height: 1.2em;
                            vertical-align: middle;
                            text-align: center;
                            border-radius: 0.6em;
                            line-height: 1.2em;
                            overflow: visible;
                            top: 1em;
                            -moz-user-select: none;
                            cursor: pointer;
                            background-color: #000;
                          }

#pgupButton:hover,
#stretchButton:hover,
#removeButton:hover       { opacity: 0.9; }

#removeButton             { right: 1em; }

#stretchButton            { right: 2.5em; }

#pgupButton               { right: 4em; display: none; }

html                      { 
                            width: 100%;
                            overflow-x: hidden;
                          }
`;

arrowPosition = 0

function addGlobalStyle(css) {
  var head = document.getElementsByTagName('head')[0];
  if (!head) {
    head = document.createElement('head');
    document.getElementsByTagName('html')[0].appendChild(head);
  }
  var style = document.createElement('style');
  style.type = 'text/css';
  style.innerHTML = css;
  head.appendChild(style);
  var stretch = document.createElement('style');
  stretch.type = 'text/css';
  stretch.id = 'stretchCSS';
  head.appendChild(stretch);
}

function embedGalleryButton() {
  var galleryButton = document.createElement('a');
  galleryButton.href = '#';
  galleryButton.id = 'galleryButton';
  galleryButton.style = 'margin-left: 0.5em;';
  galleryButton.innerHTML = '[img2tab gallery]';
  if (document.getElementsByClassName('navLinks desktop').length > 0) {
    document.getElementsByClassName('navLinks desktop')[0].appendChild(galleryButton);
  }
  else if (document.getElementById('expand-all-images')) {
    document.getElementById('expand-all-images').appendChild(galleryButton);
  }
  else {
    galleryButton.style = 'position: fixed; top: 4em; right: 12em;';
    document.getElementsByTagName('body')[0].appendChild(galleryButton);
  }
  document.getElementById('galleryButton').addEventListener(
    'click', embedGallery, false);
}

function inArray(elem, array) {
  if (array.indexOf) {
    return array.indexOf(elem);
  }

  for (var i = 0, length = array.length; i < length; i++) {
    if (array[i] === elem) {
      return i;
    }
  }
  return -1;
}

function collectLinks() {
  var links = content.document.getElementsByTagName('a');
  var imageUrls = [];
  var count = 0;
  for (var i = 0; i < links.length; i++) {
    var url = links[i].href;
    if (url.match(/.+\.(jpg|gif|png|webm|mp4)$/i) &&
      !url.match(/%3A%2F%2F/) &&
      !url.match(/.+\.(jpg|gif|png|webm|mp4)\//i) &&
      !url.match(/file_dl/i) &&
      inArray(url, imageUrls) == -1) {
      imageUrls[count] = url;
      count++;
    }
  }
  return imageUrls;
}

function populateGallery(imageUrls) {
  var gallery = document.createElement('div');
  gallery.id = 'lightboxGallery';
  var removeButton = '<span id="removeButton">🞭</span>';
  var stretchButton = '<span id="stretchButton">🞑</span>';
  var pgupButton = '<span id="pgupButton">â–´</span>';
  gallery.innerHTML = stretchButton +
    removeButton +
    pgupButton +
    imageUrls.reduce(function (s, url, i) {
      var line = '';
      if (url.match(/\.(webm|mp4)/im)) {
        line = '<video src="' + url + '" controls></video>';
      }
      else {
        line = '<img src="' + url + '" />';
      }
      var anchori = 'anchor' + i.toString();
      line = s + '<div class="pcontainer" id="' + anchori + '">' +
        '<p class="imageP countP ' + anchori + '">' +
        line + '</p></div>';
      return line;
    }, '');
  return gallery;
}

function embedBackground() {
  var lightboxBackground = document.createElement('div');
  lightboxBackground.id = 'lightboxBackground';
  lightboxBackground.innerHTML = '<span>END</span>';
  document.getElementsByTagName('body')[0].appendChild(lightboxBackground);
}

function removeGallery() {
  document.getElementById('stretchCSS').innerHTML = '';
  document.getElementById('lightboxGallery').outerHTML = '';
  document.getElementById('lightboxBackground').outerHTML = '';
  scroll(0, 0);
}

function stretchGallery() {
  var i;
  var stretch = document.getElementById('stretchCSS');
  var anchors = document.getElementsByClassName('imageP');
  if (stretch.innerHTML === '') {
    var multiLineCSS = `
                        html {overflow: -moz-scrollbars-none;}
                        .pcontainer { min-height: 100vh; }
                        .pcontainer p { padding: 0 !important; cursor: pointer; }
                        #pgupButton { display: inherit !important; }
                       `;
    stretch.innerHTML = multiLineCSS;
    for (i = 0; i < anchors.length - 1; i++) {
      anchors[i].addEventListener(
        'click', scrolltoP, false);
    }
  }
  else {
    stretch.innerHTML = '';
    for (i = 0; i < anchors.length - 1; i++) {
      anchors[i].removeEventListener(
        'click', scrolltoP, false);
    }
  }
  scrollarrow(arrowPosition)
}

function scrolltoP() {
  var i = this.className;
  i = i.match(/[0-9][0-9]*/)[0];
  i = parseInt(i, 10);
  i += 1;
  arrowPosition = i;
  i = 'anchor' + i.toString();
  document.getElementById(i).scrollIntoView(true);
}

function scrollarrow(i) {
  i = 'anchor' + i.toString();
  document.getElementById(i).scrollIntoView(true);
}

function scrollBack() {
  arrowPosition--;
  if (arrowPosition < 0) {
    arrowPosition = document.getElementsByClassName('imageP').length - 1
  }
  scrollarrow(arrowPosition);
}

function scrollForward() {
  arrowPosition++;
  if (arrowPosition > document.getElementsByClassName('imageP').length - 1) {
    arrowPosition = 0
  }
  scrollarrow(arrowPosition);
}

function listentoButtons() {
  document.getElementById('removeButton').addEventListener(
    'click', removeGallery, false);
  document.getElementById('stretchButton').addEventListener(
    'click', stretchGallery, false);
  document.getElementById('pgupButton').addEventListener(
    'click', scrollBack, false);
}

function embedGallery() {
  imageUrls = collectLinks();
  gallery = populateGallery(imageUrls);
  document.getElementById('galleryButton').parentElement.appendChild(gallery);
  embedBackground();
  scroll(0, 0);
  listentoButtons();
}

addGlobalStyle(multiLineCSS);
embedGalleryButton();

document.onkeydown = function (e) {
  switch (e.keyCode) {
    case 37:
      scrollBack();
      break;
    case 39:
      scrollForward();
      break;
  }
};