// ==UserScript==
// @name AO3: Tracking
// @description Track any filterable listing.
// @namespace https://greasyfork.org/en/scripts/8382-ao3-tracking
// @author Min
// @version 1.0.1
// @grant none
// @include http://archiveofourown.org/*
// @include https://archiveofourown.org/*
// ==/UserScript==
(function($) {
if (typeof(Storage) !== 'undefined') {
// load the saved list
var tracked_list = localStorage.getItem('ao3tracking_list');
if (!tracked_list) { var tracked_list = ''; }
// make an array of the list
var tracked_array = [];
if (tracked_list.length) {
tracked_array = tracked_list.split(',,,');
}
addCss();
addTrackedMenu();
var main = $('#main');
// if it's a listing of works or bookmarks
if (main.hasClass('works-index') || main.hasClass('bookmarks-index')) {
var is_tracked = false;
var is_first_page = true;
// get page url
var location_url = location.href;
// check if page is already tracked
var array_index = tracked_array.indexOf(location_url);
if (array_index > -1) {
is_tracked = true;
checkOpen();
}
// make sure it's the first page of the listing
var current_page = main.find('ol.pagination:first span.current');
if (current_page.length && current_page.text() !== '1') {
is_first_page = false;
}
addTrackButton();
}
// add "Mark all as vieved" button when all listing get checked
$(document).ajaxStop(function() {
if ($('#tracked-box').length && !$('#button-check').length) {
var box_button_mark = $('<input type="button" id="button-mark" value="Mark all as viewed"></input>');
$('#tracked-box p.actions').prepend(box_button_mark);
box_button_mark.click(function() { markAllViewed(); });
}
});
}
// add current page to tracked listings
function addToTracked() {
var added = false;
// if there's less than 25 tracked
if (tracked_array.length < 75) {
// ask for name
var heading = main.find('h2.heading:first');
var heading_link = heading.find('a');
if (heading_link.length) {
var suggest = heading_link.text();
}
else {
var suggest = heading.text().replace(/\n/g, '').replace(/^\s+/, '').replace(/(.+of )?\d+ /, '');
}
var listing_name = prompt('Name for the tracked listing:', suggest);
if (listing_name !== '' && listing_name !== null) {
// remove characters we don't want in the names
listing_name = listing_name.replace(/,,,/g, ' ');
var listing_count = heading.text().replace(/\n/g, '').replace(/^\s+/, '').replace(/.*\d+ - \d+ of /, '').replace(/(\d+)(.+)/, '$1');
// add name, url, count
tracked_array.push(listing_name, location_url, listing_count);
tracked_list = tracked_array.join(',,,');
// save the updated list
localStorage.setItem('ao3tracking_list', tracked_list);
added = true;
}
}
else {
alert("You're already tracking 25 listings. Remove some first.");
}
return added;
}
// remove a given url from tracked listings
function removeFromTracked(url) {
var removed = false;
var index = tracked_array.indexOf(url);
// if the url is on the saved list
if (index > -1) {
// ask for confirmation
var confirmed = confirm('Sure you want to remove "' + tracked_array[index-1] + '"?');
if (confirmed) {
// remove name, url, count
tracked_array.splice(index-1, 3);
tracked_list = tracked_array.join(',,,');
// save the updated list
localStorage.setItem('ao3tracking_list', tracked_list);
removed = true;
}
}
return removed;
}
// check open page for new works
function checkOpen() {
var heading = main.find('h2.heading:first');
// get a count of new works
var current_count = parseInt(heading.text().replace(/\n/g, '').replace(/^\s+/, '').replace(/.*\d+ - \d+ of /, '').replace(/(\d+)(.+)/, '$1'));
var saved_count = parseInt(tracked_array[array_index+1]);
var new_count = current_count - saved_count;
if (new_count !== 0) {
heading.append(' <span id="new-works">(' + new_count + ' new)</span> <span id="mark-viewed">[mark viewed]</span>');
$('#mark-viewed').click(function() {
// update the count
tracked_array[array_index+1] = current_count;
tracked_list = tracked_array.join(',,,');
// save the updated list
localStorage.setItem('ao3tracking_list', tracked_list);
$('#new-works').detach();
$(this).detach();
});
}
}
// check the tracked listings for new works
function checkForNew() {
// for each tracked listing
$('#tracked-box li.tracked-listing').each(function() {
var tracked_url = $(this).find('a').attr('href');
var listing_id = $(this).attr('id');
tracked_url += ' #main h2.heading:first';
// load heading of the tracked page
$(this).find('span.tracked-current').load(tracked_url, function() {
var listing = $('#' + listing_id);
// get a count of new works
var current_count = parseInt(listing.find('span.tracked-current').text().replace(/\n/g, '').replace(/^\s+/, '').replace(/.*\d+ - \d+ of /, '').replace(/(\d+)(.+)/, '$1'));
listing.find('span.tracked-current').html(current_count);
var saved_count = parseInt(listing.find('span.tracked-saved').text());
var new_count = current_count - saved_count;
listing.find('span.tracked-new').text('(' + new_count + ' new)');
if (new_count !== 0) {
listing.find('span.tracked-new').addClass('new-stuff');
listing.parent().prepend(listing);
}
else {
listing.find('span.tracked-new').addClass('no-new-stuff');
}
});
});
}
// add the 'Track This' button
function addTrackButton() {
var work_filters = $('#work_filters dd.submit.actions:first');
var track_this_button = $('<input type="button" value="Track This" class="track-this"></input>');
track_this_button.click(function() {
var added = addToTracked();
if (added) {
track_this_button.detach();
work_filters.prepend(untrack_this_button);
}
});
var untrack_this_button = $('<input type="button" value="Untrack This" class="track-this"></input>');
untrack_this_button.click(function() {
var removed = removeFromTracked(location_url);
if (removed) {
untrack_this_button.detach();
work_filters.prepend(track_this_button);
}
});
// if the page is already tracked
if (is_tracked) {
work_filters.prepend(untrack_this_button);
}
// if it's not tracked and is the first page of the listing
else if (is_first_page) {
work_filters.prepend(track_this_button);
}
}
// rearrange things on the list
function editList() {
var box_list = $('#box-list');
box_list.find('li.tracked-listing').each(function() {
$(this).prepend('<span class="up-arrow">↑</span> <span class="down-arrow">↓</span> <span class="cross">✗</span> ');
});
box_list.on('click', 'span.up-arrow', function() {
$(this).parent().prev().before($(this).parent());
});
box_list.on('click', 'span.down-arrow', function() {
$(this).parent().next().after($(this).parent());
});
box_list.on('click', 'span.cross', function() {
$(this).parent().detach();
});
}
// save list after edits
function saveList() {
tracked_array = [];
// get name, url, count for all listings
$('#tracked-box li.tracked-listing').each(function() {
var name = $(this).find('a').text();
var url = $(this).find('a').attr('href');
var count = $(this).find('span.tracked-saved').text();
tracked_array.push(name, url, count);
});
// update and save the new list
tracked_list = tracked_array.join(',,,');
localStorage.setItem('ao3tracking_list', tracked_list);
// reload the box
$('#tracked-box').detach();
showBox();
}
// update the listings counts
function markAllViewed() {
// get the current count for all listings
$('#tracked-box li.tracked-listing').each(function() {
var url = $(this).find('a').attr('href');
var current_count = $(this).find('span.tracked-current').text();
var index = tracked_array.indexOf(url);
tracked_array[index+1] = current_count;
});
// update and save the new list
tracked_list = tracked_array.join(',,,');
localStorage.setItem('ao3tracking_list', tracked_list);
// reload the box
$('#tracked-box').detach();
showBox();
}
// show the box with tracked listings
function showBox() {
var tracked_box = $('<div id="tracked-box"></div>');
var box_buttons = $('<p class="actions"></p>');
var box_button_check = $('<input type="button" id="button-check" value="Check for new"></input>');
box_button_check.click(function() {
checkForNew();
box_button_edit.detach();
box_button_check.detach();
});
var box_button_edit = $('<input type="button" id="button-edit" value="Edit list"></input>');
box_button_edit.click(function() {
editList();
box_button_edit.after(box_button_save, box_button_cancel);
box_button_check.detach();
box_button_edit.detach();
});
var box_button_save = $('<input type="button" id="button-save" value="Save list"></input>');
box_button_save.click(function() { saveList(); });
var box_button_cancel = $('<input type="button" id="button-cancel" value="Cancel edits"></input>');
box_button_cancel.click(function() {
$('#tracked-box').detach();
showBox();
});
var box_button_close = $('<input type="button" id="button-close" value="Close"></input>');
box_button_close.click(function() { tracked_box.detach(); });
var box_header = $('<h3></h3>').text('Tracked listings [' + tracked_array.length/3 + '/25]:');
var box_list = $('<ul id="box-list"></ul>');
tracked_box.append(box_buttons, box_header, box_list);
// if there are saved listings
if (tracked_array.length > 2) {
for (var i = 0; i < tracked_array.length; i += 3) {
var listing = $('<li id="tracked-listing-' + i/3 + '" class="tracked-listing"></li>').html('<a href="' + tracked_array[i+1] + '">' + tracked_array[i] + '</a> <span class="tracked-new"></span> <span class="tracked-saved">' + tracked_array[i+2] + '</span> <span class="tracked-current"></span>');
box_list.append(listing);
}
box_buttons.append(box_button_check, box_button_edit, box_button_close);
}
else {
var no_listings = $('<li style="opacity: 0.5; font-style: oblique;"></li>').html("you're not tracking anything yet!");
box_list.append(no_listings);
box_buttons.append(box_button_close);
}
$('body').append(tracked_box);
}
// attach the menu
function addTrackedMenu() {
// get the header menu
var header_menu = $('ul.primary.navigation.actions');
// create and insert menu button
var tracked_button = $('<input class="button" type="button" value="Tracked"></input>');
header_menu.find('#search').prepend(tracked_button);
tracked_button.click(function() {
if ($('#tracked-box').length == 0) {
showBox();
}
});
}
// add css rules to page head
function addCss() {
var style = $('style');
var css = '#tracked-box {position: fixed; top: 10%; left: 20%; width: 60%; height: 80%; overflow-y: auto; border: 2px solid #888; box-shadow: 1px 1px 3px #CCC inset; border-radius: 0.35em; padding: 0 20px; background-color: #ffffff; z-index: 999999999;}\
input[type="button"] {height: 1.929em;}\
input.track-this {margin-bottom: 10px;}\
#tracked-box p.actions {float: none; min-height: 1.929em;}\
#button-check, #button-edit, #button-save, #button-cancel, #button-mark {float: left;}\
#button-save {font-weight: bold;}\
#button-close {float: right;}\
#tracked-box li span.tracked-new.new-stuff {font-weight: bold;}\
#tracked-box li span.tracked-new.no-new-stuff {opacity: 0.5;}\
#tracked-box li span.tracked-current, #tracked-box li span.tracked-saved {display: none;}\
#new-works {font-weight: bold;}';
if (!style.length) {
style = $('<style type="text/css"></style>').appendTo($('head'));
}
style.append(css);
}
})(jQuery);