Greasy Fork

ao3 savior

Hide specified works on AO3

目前为 2017-04-07 提交的版本。查看 最新版本

// ==UserScript==
// @name          ao3 savior
// @description   Hide specified works on AO3
// @namespace     ao3
// @include       http*://archiveofourown.org/*
// @grant         none
// @version       1.8
// ==/UserScript==


;(function() {
var STYLE = '\n  html body .ao3-savior-hidden {\n    display: none;\n  }\n  \n  .ao3-savior-cut {\n    display: none;\n  }\n  \n  .ao3-savior-cut::after {\n    clear: both;\n    content: \'\';\n    display: block;\n  }\n  \n  .ao3-savior-reason {\n    margin-left: 5px;\n  }\n  \n  .ao3-savior-hide-reasons .ao3-savior-reason {\n    display: none;\n  }\n  \n  .ao3-savior-unhide .ao3-savior-cut {\n    display: block;\n  }\n  \n  .ao3-savior-fold {\n    align-items: center;\n    display: flex;\n    justify-content: flex-start;\n  }\n  \n  .ao3-savior-unhide .ao3-savior-fold {\n    background: #ffc68e;\n  }\n  \n  button.ao3-savior-toggle {\n    margin-left: auto;\n  }\n';

function addStyle() {
  var style = document.createElement('style');
  style.innerHTML = STYLE;
  style.className = 'ao3-savior';

  document.head.appendChild(style);
}

var CSS_NAMESPACE = 'ao3-savior';

var getCut = function getCut(work) {
  var cut = document.createElement('div');

  cut.className = CSS_NAMESPACE + '-cut';
  cut.innerHTML = work.innerHTML;

  return cut;
};

var getFold = function getFold(reason) {
  var fold = document.createElement('div');
  var note = document.createElement('span');

  fold.className = CSS_NAMESPACE + '-fold';
  note.className = CSS_NAMESPACE + '-note';

  note.innerHTML = 'This work is hidden!';

  fold.appendChild(note);
  fold.append(' ');
  fold.appendChild(getReasonSpan(reason));
  fold.appendChild(getToggleButton());

  return fold;
};

var getToggleButton = function getToggleButton() {
  var button = document.createElement('button');
  var unhideClassFragment = ' ' + CSS_NAMESPACE + '-unhide';

  button.innerHTML = 'Unhide';
  button.className = CSS_NAMESPACE + '-toggle';

  button.addEventListener('click', function (event) {
    var work = event.target.closest('.' + CSS_NAMESPACE + '-work');

    if (work.className.indexOf(unhideClassFragment) !== -1) {
      work.className = work.className.replace(unhideClassFragment, '');
      work.querySelector('.' + CSS_NAMESPACE + '-note').innerHTML = 'This work is hidden.';
      event.target.innerHTML = 'Unhide';
    } else {
      work.className += unhideClassFragment;
      work.querySelector('.' + CSS_NAMESPACE + '-note').innerHTML = 'This work was hidden.';
      event.target.innerHTML = 'Hide';
    }
  });

  return button;
};

var getReasonSpan = function getReasonSpan(reason) {
  var span = document.createElement('span');
  var tag = reason.tag,
      author = reason.author,
      title = reason.title,
      summary = reason.summary;

  var text = void 0;

  if (tag) {
    text = 'tags include <strong>' + tag + '</strong>';
  } else if (author) {
    text = 'authors include <strong>' + author + '</strong>';
  } else if (title) {
    text = 'title is <strong>' + title + '</strong>';
  } else if (summary) {
    text = 'summary includes <strong>' + summary + '</strong>';
  }

  if (text) {
    span.innerHTML = '(Reason: ' + text + '.)';
  }

  span.className = CSS_NAMESPACE + '-reason';

  return span;
};

function blockWork(work, reason, config) {
  if (!reason) return;

  var showReasons = config.showReasons,
      showPlaceholders = config.showPlaceholders;


  if (showPlaceholders) {
    var fold = getFold(reason);
    var cut = getCut(work);

    work.className += ' ' + CSS_NAMESPACE + '-work';
    work.innerHTML = '';
    work.appendChild(fold);
    work.appendChild(cut);

    if (!showReasons) {
      work.className += ' ' + CSS_NAMESPACE + '-hide-reasons';
    }
  } else {
    work.className += ' ' + CSS_NAMESPACE + '-hidden';
  }
}

function matchTermsWithWildCard(term, pattern) {
  if (term.toLowerCase() === pattern.toLowerCase()) return true;
  if (pattern.indexOf('*') === -1) return false;

  var regexified = pattern.replace(/\*/g, '.*?');
  var regex = new RegExp('^' + regexified + '$', 'i');

  return regex.test(term);
}

var isTagWhitelisted = function isTagWhitelisted(tags, whitelist) {
  var whitelistLookup = whitelist.reduce(function (lookup, tag) {
    lookup[tag] = true;
    return lookup;
  }, {});

  return tags.some(function (tag) {
    return !!whitelistLookup[tag];
  });
};

var findBlacklistedItem = function findBlacklistedItem(list, blacklist, comparator) {
  var matchingEntry = void 0;

  list.some(function (item) {
    blacklist.some(function (entry) {
      var matched = comparator(item, entry);

      if (matched) matchingEntry = entry;

      return matched;
    });
  });

  return matchingEntry;
};

var equals = function equals(a, b) {
  return a === b;
};
var contains = function contains(a, b) {
  return a.indexOf(b) !== -1;
};

function getBlockReason(_ref, _ref2) {
  var _ref$authors = _ref.authors,
      authors = _ref$authors === undefined ? [] : _ref$authors,
      _ref$title = _ref.title,
      title = _ref$title === undefined ? '' : _ref$title,
      _ref$tags = _ref.tags,
      tags = _ref$tags === undefined ? [] : _ref$tags,
      _ref$summary = _ref.summary,
      summary = _ref$summary === undefined ? '' : _ref$summary;
  var _ref2$authorBlacklist = _ref2.authorBlacklist,
      authorBlacklist = _ref2$authorBlacklist === undefined ? [] : _ref2$authorBlacklist,
      _ref2$titleBlacklist = _ref2.titleBlacklist,
      titleBlacklist = _ref2$titleBlacklist === undefined ? [] : _ref2$titleBlacklist,
      _ref2$tagBlacklist = _ref2.tagBlacklist,
      tagBlacklist = _ref2$tagBlacklist === undefined ? [] : _ref2$tagBlacklist,
      _ref2$tagWhitelist = _ref2.tagWhitelist,
      tagWhitelist = _ref2$tagWhitelist === undefined ? [] : _ref2$tagWhitelist,
      _ref2$summaryBlacklis = _ref2.summaryBlacklist,
      summaryBlacklist = _ref2$summaryBlacklis === undefined ? [] : _ref2$summaryBlacklis;


  if (isTagWhitelisted(tags, tagWhitelist)) return null;

  var tag = findBlacklistedItem(tags, tagBlacklist, matchTermsWithWildCard);
  if (tag) return { tag: tag };

  var author = findBlacklistedItem(authors, authorBlacklist, equals);
  if (author) return { author: author };

  if (titleBlacklist.some(function (entry) {
    return title === entry;
  })) return { title: title };

  var summaryTerm = findBlacklistedItem([summary], summaryBlacklist, contains);
  if (summaryTerm) return { summary: summaryTerm };

  return null;
}

function isDebug(location) {
  return location.hostname === 'localhost' || /\ba3sv-debug\b/.test(location.search);
}

var getText = function getText(element) {
  return element.textContent.replace(/^\s*|\s*$/g, '');
};
var selectTextsIn = function selectTextsIn(root, selector) {
  return Array.from(root.querySelectorAll(selector)).map(getText);
};

function selectWorkBlockables(workContainerElement) {
  return {
    authors: selectTextsIn(workContainerElement, 'a[rel=author]'),
    tags: selectTextsIn(workContainerElement, 'a.tag'),
    title: selectTextsIn(workContainerElement, '.header .heading a:first-child')[0],
    summary: selectTextsIn(workContainerElement, 'blockquote.summary')[0]
  };
}

setTimeout(function () {
  var debugMode = isDebug(window.location);
  var config = window.ao3SaviorConfig;
  var blocked = 0;
  var total = 0;

  if (debugMode) {
    console.groupCollapsed('AO3 SAVIOR');

    if (!config) {
      console.warn('Exiting due to missing config.');
      return;
    }
  }

  addStyle();

  Array.from(document.querySelectorAll('li.blurb')).forEach(function (work) {
    var blockables = selectWorkBlockables(work);
    var reason = getBlockReason(blockables, config);

    total++;

    if (reason) {
      blockWork(work, reason, config);
      blocked++;

      if (debugMode) {
        console.groupCollapsed(work.id + ' blocked');
        console.log(work, reason);
        console.groupEnd();
      }
    } else if (debugMode) {
      console.groupCollapsed(work.id + ' skipped');
      console.log(work);
      console.groupEnd();
    }
  });

  if (debugMode) {
    console.log('Blocked ' + blocked + ' out of ' + total + ' works');
    console.groupEnd();
  }
}, 10);
}());

//# sourceMappingURL=ao3-savior.user.js.map