`;
// Add buttons
let addPositiveButton = document.createElement("button");
addPositiveButton.innerText = "Add Positive";
addPositiveButton.className = "gr-button";
addPositiveButton.onclick = Cleanreads.addSearchTerm.bind(null, true, null, null, null);
document.getElementById("crSettingsTermButtons").appendChild(addPositiveButton);
let addNegativeButton = document.createElement("button");
addNegativeButton.innerText = "Add Negative";
addNegativeButton.className = "gr-button";
addNegativeButton.onclick = Cleanreads.addSearchTerm.bind(null, false, null, null, null);
document.getElementById("crSettingsTermButtons").appendChild(addNegativeButton);
let resetButton = document.createElement("button");
resetButton.innerText = "Reset";
resetButton.className = "gr-button";
resetButton.onclick = function() {
if (confirm("Are you sure you want to remove? You will have to refresh the page to see default values loaded.")) {
localStorage.removeItem("Cleanreads.POSITIVE_SEARCH_TERMS");
localStorage.removeItem("Cleanreads.NEGATIVE_SEARCH_TERMS");
localStorage.removeItem("Cleanreads.SNIPPET_HALF_LENGTH");
localStorage.removeItem("Cleanreads.ATTEMPTS");
Cleanreads.loadSettings();
}
}
document.getElementById("crSettingsTermButtons").appendChild(resetButton);
// Add existing terms
Cleanreads.POSITIVE_SEARCH_TERMS.forEach((search) => Cleanreads.addSearchTerm(true, search.term, search.exclude.before, search.exclude.after));
Cleanreads.NEGATIVE_SEARCH_TERMS.forEach((search) => Cleanreads.addSearchTerm(false, search.term, search.exclude.before, search.exclude.after));
}
} catch (ex) {
console.error("Cleanreads: Failed to load settings!", ex);
}
};
/**
* Save the positive and negative search terms to local storage
*/
Cleanreads.saveSettings = function() {
let positiveTerms = document.querySelectorAll("#crPositiveSearchTerms > .crTermsContainer");
let negativeTerms = document.querySelectorAll("#crNegativeSearchTerms > .crTermsContainer");
Cleanreads.POSITIVE_SEARCH_TERMS = [...positiveTerms].map((search) => {
return {
term: search.querySelector("[name=term]").value,
exclude: {
before: search.querySelector("[name=excludeBefore]").value.split(",").map(x => x.trim()),
after: search.querySelector("[name=excludeAfter]").value.split(",").map(x => x.trim())
}
}
}).filter(x => x.term);
Cleanreads.NEGATIVE_SEARCH_TERMS = [...negativeTerms].map((search) => {
return {
term: search.querySelector("[name=term]").value,
exclude: {
before: search.querySelector("[name=excludeBefore]").value.split(",").map(x => x.trim()),
after: search.querySelector("[name=excludeAfter]").value.split(",").map(x => x.trim())
}
}
}).filter(x => x.term);
Cleanreads.SNIPPET_HALF_LENGTH = parseInt(document.getElementById("crSnippetHalfLength").value) || Cleanreads.SNIPPET_HALF_LENGTH;
Cleanreads.ATTEMPTS = parseInt(document.getElementById("crAttempts").value) || Cleanreads.ATTEMPTS;
localStorage.setItem("Cleanreads.POSITIVE_SEARCH_TERMS", JSON.stringify(Cleanreads.POSITIVE_SEARCH_TERMS));
localStorage.setItem("Cleanreads.NEGATIVE_SEARCH_TERMS", JSON.stringify(Cleanreads.NEGATIVE_SEARCH_TERMS));
localStorage.setItem("Cleanreads.SNIPPET_HALF_LENGTH", JSON.stringify(Cleanreads.SNIPPET_HALF_LENGTH));
localStorage.setItem("Cleanreads.ATTEMPTS", JSON.stringify(Cleanreads.ATTEMPTS));
Cleanreads.loadSettings();
}
/**
* Setup the settings modal for Cleanreads
*/
Cleanreads.setupSettings = function() {
// Add link to menu dropdown
let links = Array.from(document.getElementsByClassName('menuLink')).filter(x => x.innerText == 'Account settings');
if (links && links.length) {
let li = document.createElement('li');
li.className = 'menuLink';
li.onclick = Cleanreads.showSettings;
li.innerHTML = `Cleanreads settings`;
links[0].parentNode.insertBefore(li, links[0].nextSibling);
}
// Add dialog
document.body.innerHTML += `
Cleanreads Settings
`;
// Add link to profile page
let settingsLink = document.createElement('a');
settingsLink.href = '#';
settingsLink.innerText = 'Cleanreads settings';
settingsLink.onclick = Cleanreads.showSettings;
document.getElementsByClassName('userInfoBoxContent')[0].appendChild(settingsLink);
// Add close button to dialog
let closeButton = document.createElement('button');
closeButton.innerText = 'Close';
closeButton.className = 'gr-button';
closeButton.onclick = Cleanreads.hideSettings;
document.getElementById('crSettingsFooter').appendChild(closeButton);
// Add save button to dialog
let saveButton = document.createElement('button');
saveButton.innerText = 'Save';
saveButton.className = 'gr-button saveButton';
saveButton.onclick = Cleanreads.saveSettings;
document.getElementById('crSettingsFooter').appendChild(saveButton);
Cleanreads.loadSettings();
};
/**
* Add a search term to the settings UI
*/
Cleanreads.addSearchTerm = function(positive, term, before, after) {
document.getElementById(`cr${positive ? 'Positive' : 'Negative'}SearchTerms`).insertAdjacentHTML("beforeend",
`
`);
};
/**
* Setup the rating (verdict) container on a book page
*/
Cleanreads.setupRating = function() {
let match = window.location.pathname.match(/book\/show\/(\d+)/);
if (match && match.length > 1) {
Cleanreads.bookId = window.location.pathname.match(/show\/(\d*)/)[1];
Cleanreads.loadSettings();
Cleanreads.reviews = [];
Cleanreads.shelves = [];
Cleanreads.positives = 0;
Cleanreads.negatives = 0;
// Create container for rating
let container = document.getElementById('descriptionContainer');
let contentDescription = document.createElement('div');
contentDescription.id = 'contentDescription';
contentDescription.className = 'readable stacked u-bottomGrayBorder u-marginTopXSmall u-paddingBottomXSmall';
contentDescription.innerHTML = `
Cleanreads Rating
Verdict: Loading...
(0/0)
(Details)
`;
container.parentNode.insertBefore(contentDescription, container.nextSibling);
Cleanreads.crDetails = document.getElementById('crDetails');
document.getElementById('expandCrDetails').onclick = Cleanreads.expandDetails;
Cleanreads.getTopBookShelves(Cleanreads.bookId).then(shelves => {
Cleanreads.shelves = shelves;
Cleanreads.startReviews();
}).catch(err => Cleanreads.startReviews());
}
};
/**
* Start attempting to get the available reviews on the page and read their content
*/
Cleanreads.startReviews = function() {
Cleanreads.getReviews();
// Reviews are delayed content so keep looking for a bit if nothing
if (!Cleanreads.reviews.length && Cleanreads.ATTEMPTS--) {
setTimeout(Cleanreads.startReviews, 1000);
} else {
Cleanreads.calculateContent();
}
};
/**
* Get reviews from page (only gets the first page of reviews, not easy to access others without API)
*/
Cleanreads.getReviews = function() {
let reviewElements = document.querySelectorAll('#reviews .reviewText');
Cleanreads.reviews = Array.from(reviewElements).map(x => (x.querySelector('[style]') || x).innerText.trim());
};
/**
* Get title as text with series appended
*/
Cleanreads.getTitle = function() {
return document.getElementById('bookTitle').innerText.trim() + document.getElementById('bookSeries').innerText.trim();
};
/**
* Get book description text
*/
Cleanreads.getDescription = function() {
let description = document.getElementById('description');
return (description.querySelector('[style]') || description).innerText.trim();
};
/**
* Get group bookshelf titles
* @param {string} shelfId - The bookshelf id
* @param {number} maxCount - The maximum number of books in the bookshelf to return
* @returns {Promise} - A promise that resolves to array of book ids or rejects with error
*/
Cleanreads.getGroupBookshelfBooks = function(shelfId, maxCount) {
return new Promise(function(resolve, reject) {
jQuery.ajax(`${window.location.origin}/group/bookshelf/${shelfId}?utf8=✓&view=covers&per_page=${maxCount || 1000}`)
.done(result => {
resolve(jQuery(result).find(".rightContainer div > a").toArray().map(x => (x.href.match(/show\/(\d*)/)||[])[1]));
})
.fail(err => reject(err));
});
};
/**
* Get the top 100 shelf names for a given book
* @param {string} bookId - The book id
* @returns {Promise} - A promise that resolves to array of top 100 shelves for given book
*/
Cleanreads.getTopBookShelves = function(bookId) {
return new Promise(function(resolve, reject) {
jQuery.ajax(`${window.location.origin}/book/shelves/${bookId}`)
.done(result => {
resolve(jQuery(result).find('.shelfStat').toArray().map(x => `${jQuery(x).find('.actionLinkLite').text().replace(/-/gi, ' ')} (${jQuery(x).find('.smallText').text().trim()})`));
})
.fail(err => reject(err));
});
};
/**
* Get list titles
* TODO: currently only gets first page
* @param {string} listId - The list id
* @returns {Promise} - A promise that resolves to array of book ids or rejects with error
*/
Cleanreads.getListBooks = function(listId) {
return new Promise(function(resolve, reject) {
jQuery.ajax(`${window.location.origin}/list/show/${listId}`)
.done(result => {
resolve(jQuery(result).find(".tableList tr td:nth-child(2) div:nth-child(1)").toArray().map(x => x.id))
})
.fail(err => {
reject(err);
});
});
};
/**
* Calculate the cleanliness
*/
Cleanreads.calculateContent = function() {
let count = 0, containing = [];
// Insert containers for bases
Cleanreads.crDetails.innerHTML +=
`
`;
};
/**
* Search the loaded bookshelf book ids for current book and update verdict
*/
Cleanreads.searchBookshelf = function() {
let bookId = window.location.pathname.match(/show\/(\d*)/)[1];
let bookshelfBasis = document.getElementById('bookshelfBasis');
if (bookId && Cleanreads.CLEAN_READS_BOOKSHELF.books.indexOf(bookId) != -1) {
bookshelfBasis.innerHTML =
`