// ==UserScript==
// @name MyAnimeList (MAL) Track Missing Relations
// @namespace https://greasyfork.org/users/7517
// @description Allows to find missing relations and entries with wrong chapter/episode count.
// @icon http://i.imgur.com/b7Fw8oH.png
// @version 5.1.1
// @author akarin
// @include /^http:\/\/myanimelist\.net\/panel\.php(\?go=editmanga)?$/
// @include /^http:\/\/myanimelist\.net\/editlist\.php\?type=anime$/
// @grant none
// @noframes
// ==/UserScript==
(function($) {
var mal = {};
mal.settings = {
// Script settings:
cache: '4.0',
ajax: { delay: 300, timeout: 10000 },
name: $('#header-menu span.profile-name').text().trim(),
type: document.URL.match(/\?type=anime$/) ? 'anime' : 'manga',
// Predefined data lists:
availableRelations: ['Alternative Setting', 'Alternative Version', 'Character', 'Full Story', 'Other', 'Parent Story', 'Prequel', 'Sequel', 'Side Story', 'Spin-off', 'Summary'],
availableStatus: {
anime: ['Watching', 'Completed', 'On-Hold', 'Dropped', 'Plan to Watch'],
manga: ['Reading', 'Completed', 'On-Hold', 'Dropped', 'Plan to Read']
},
// User settings:
excludedRelations: [],
excludedStatus: { anime: [], manga: [] },
load: function() {
mal.settings.excludedRelations = ['Adaptation'];
$.each(mal.settings.availableRelations, function(i, val) {
var id = 'mr_x' + mal.settings.type[0] + '_' + val.toHtmlId();
if (mal.loadValue(id, 'false') !== 'false') {
mal.settings.excludedRelations.push(val);
}
});
$.each(['anime', 'manga'], function(i, status) {
mal.settings.excludedStatus[status] = ['Empty Status'];
$.each(mal.settings.availableStatus[status], function(i, val) {
var id = 'mr_xs' + status[0] + '_' + val.toHtmlId(),
def = val.match(/^Plan to/) ? 'true' : 'false';
if (mal.loadValue(id, def) !== 'false') {
mal.settings.excludedStatus[status].push(val);
}
});
});
},
reset: function() {
$.each(mal.settings.availableRelations, function(i, val) {
mal.saveValue('mr_xa_' + val.toHtmlId(), 'false');
mal.saveValue('mr_xm_' + val.toHtmlId(), 'false');
});
$.each(['anime', 'manga'], function(i, status) {
$.each(mal.settings.availableStatus[status], function(i, val) {
mal.saveValue('mr_xs' + status[0] + '_' + val.toHtmlId(), val.match(/^Plan to/) ? 'true' : 'false');
});
});
mal.settings.load();
}
};
function main() {
if (mal.settings.name.length === 0) {
return;
}
var header = $('<h2 id="mr_body_title">Missing Relations <span><a id="mr_version" href="http://greasyfork.org/scripts/9261" target="_blank">v' + GM_info.script.version + '</a></span></h2>');
mal.content.body
.prepend(header.clone())
.append(mal.content.list);
mal.content.settings
.prepend(header.clone());
$('<div></div>').hide()
.append(mal.content.body)
.append(mal.content.settings)
.insertAfter('#contentWrapper');
if (document.URL.match(/^http:\/\/myanimelist\.net\/panel\.php$/)) {
pagePanel();
}
else {
pageList();
}
}
function pageList() {
$.ajaxSetup({ timeout: mal.settings.ajax.timeout });
if (!mal.entries.checkVersion()) {
mal.entries.clear();
mal.entries.save();
}
mal.entries.load();
mal.content.updateList(false);
$('<span id="mr_link"></span>')
.append('<span> | </span>')
.append($('<a href="#mr_body">Missing Relations</a>').fancybox({
'hideOnContentClick': false,
'hideOnOverlayClick': true,
'transitionIn': 'none',
'transitionOut': 'none',
'titleShow': false,
'scrolling': 'no'
}))
.append(' (')
.append($('<span></span>')
.append($('<a href="#mr_settings" title="Relations scan settings">settings</a>').fancybox({
'hideOnContentClick': false,
'hideOnOverlayClick': true,
'transitionIn': 'none',
'transitionOut': 'none',
'titleShow': false,
'scrolling': 'no',
'onStart': function() {
mal.content.updateSettings();
}
}))
.append(' | ')
.append($('<a href="javascript:void(0);" title="Scan only entries in your list">scan</a>').click(function() {
if (true === confirm('Recalculate all entries?')) {
mal.entries.update(false);
}
}))
.append(', ')
.append($('<a href="javascript:void(0);" title="Scan only new entries in your list">new</a>').click(function() {
if (true === confirm('Recalculate new entries?')) {
mal.entries.updateNew(false);
}
}))
.append(' | ')
.append($('<a href="javascript:void(0);" title="Scan entries in your list and their direct relations">full scan</a>').click(function() {
if (true === confirm('Recalculate all entries and their direct relations?')) {
mal.entries.update(true);
}
}))
.append(', ')
.append($('<a href="javascript:void(0);" title="Scan new entries in your list and their direct relations">new</a>').click(function() {
if (true === confirm('Recalculate new entries and their direct relations?')) {
mal.entries.updateNew(true);
}
}))
)
.append(')')
.append(mal.content.done)
.append(mal.content.fail)
.appendTo('#content > div:first');
}
function pagePanel() {
var animeLink = $('<a href="#mr_body" id="mr_link_anime" style="font-size: 11px; font-weight: normal;">Missing Anime Relations</a>'),
mangaLink = $('<a href="#mr_body" id="mr_link_manga" style="font-size: 11px; font-weight: normal;">Missing Manga Relations</a>'),
links = $('<div class="floatRightHeader"></div>').append(animeLink).append(' - ').append(mangaLink)
.appendTo('#panel_left > .container > div.bgColor1:first-of-type + .spaceit');
$('a[id^="mr_link_"]', links).each(function() {
var type = this.id.match(/^mr_link_(\w+)$/)[1];
$(this).fancybox({
'hideOnContentClick': false,
'hideOnOverlayClick': true,
'transitionIn': 'none',
'transitionOut': 'none',
'titleShow': false,
'scrolling': 'no',
'onStart': function() {
var listType = $('#mr_list_type', mal.content.body);
mal.settings.type = type;
if (listType.length === 0 || listType.val() !== mal.settings.type) {
if (mal.entries.checkVersion()) {
mal.entries.load();
}
else {
mal.entries.clear();
}
mal.content.updateList(false);
}
}
});
});
}
mal.entries = {
// Cache data:
left: {}, graph: {}, title: {}, wrong: {}, ignore: {},
total: 0, done: 0, fail: 0,
// For internal use only:
right: {},
load: function() {
mal.entries.clear();
mal.entries.left = mal.loadValue('mal.entries.left', mal.entries.left);
mal.entries.graph = mal.loadValue('mal.entries.graph', mal.entries.graph);
mal.entries.title = mal.loadValue('mal.entries.title', mal.entries.title);
mal.entries.wrong = mal.loadValue('mal.entries.wrong', mal.entries.wrong);
mal.entries.ignore = mal.loadValue('mal.entries.ignore', mal.entries.ignore);
},
save: function() {
mal.saveValue('mal.entries.version', mal.settings.cache);
mal.saveValue('mal.entries.left', mal.entries.left);
mal.saveValue('mal.entries.graph', mal.entries.graph);
mal.saveValue('mal.entries.title', mal.entries.title);
mal.saveValue('mal.entries.wrong', mal.entries.wrong);
mal.entries.saveIgnore();
},
saveIgnore: function() {
mal.saveValue('mal.entries.ignore', mal.entries.ignore);
},
clear: function() {
mal.entries.total = mal.entries.done = mal.entries.fail = 0;
mal.entries.left = {};
mal.entries.graph = {};
mal.entries.title = {};
mal.entries.wrong = {};
},
clearIgnore: function() {
mal.entries.ignore = {};
},
checkVersion: function() {
var v = mal.loadValue('mal.entries.version', '').trim();
return (v.length === 0 || v === mal.settings.cache);
},
isUpdating: function() {
return (mal.entries.done + mal.entries.fail) < mal.entries.total;
},
getTitle: function(id) {
var result = mal.entries.title.hasOwnProperty(id) ? mal.entries.title[id] : '';
return result.length === 0 ? '?' : result;
},
update: function(fullRefresh) {
if (!mal.entries.isUpdating()) {
mal.entries.clear();
mal.entries.updateNew(fullRefresh);
}
},
updateNew: function(fullRefresh) {
if (mal.entries.isUpdating()) {
return;
}
mal.settings.load();
var index = 0,
links = $('#content strong + a'),
statusCol = $('#content .normal_header > a:contains(Status)').parent().index(),
statusRe = new RegExp('(' + mal.settings.excludedStatus[mal.settings.type].join('|') + ')', 'i');
mal.entries.done = mal.entries.fail = 0;
mal.entries.total = links.length;
mal.entries.right = {};
mal.content.done.text('');
mal.content.fail.text('');
$('#content span[class^="mr_status_id_"]').empty();
if (links.length === 0) {
mal.content.updateList(true);
return;
}
links.each(function() {
var id = parseInt($(this).prop('href').match(/\d+$/)[0]),
span = $(this).parent().find('span[class="mr_status_id_' + id + '"]'),
status = $(this).closest('tr').children('td').eq(statusCol).text();
if (span.length === 0) {
span = $('<span class="mr_status_id_' + id + '"></span>').appendTo($(this).parent());
}
if (mal.entries.left.hasOwnProperty(id) || status.match(statusRe)) {
span.html('<small style="color: green;">done</small>');
mal.content.done.text(' done: ' + (++mal.entries.done) + '/' + mal.entries.total);
mal.content.updateList(true);
return;
}
mal.entries.title[id] = $(this).prev('strong').text().trim();
setTimeout(function() {
$.ajax('/' + mal.settings.type + '/' + id)
.done(function(data) {
mal.entries.left[id] = true;
var rels = mal.entries.findRelations(id, data);
if (!mal.entries.checkRelation(data)) {
mal.entries.wrong[id] = true;
}
if (fullRefresh) {
$.each(rels, function(i, id) {
mal.entries.right[id] = true;
});
}
span.html('<small style="color: green;">done</small>');
mal.content.done.text(' done: ' + (++mal.entries.done) + '/' + mal.entries.total);
if (fullRefresh) {
mal.entries.updateFull();
}
else {
mal.content.updateList(true);
}
})
.fail(function() {
span.html('<small style="color: red;">fail</small>');
mal.content.fail.text(' fail: ' + (++mal.entries.fail));
if (fullRefresh) {
mal.entries.updateFull();
}
else {
mal.content.updateList(true);
}
});
}, mal.settings.ajax.delay * (index++));
});
},
updateFull: function() {
if (mal.entries.isUpdating()) {
return;
}
$.each(mal.entries.right, function(id) {
if (mal.entries.left.hasOwnProperty(id)) {
delete mal.entries.right[id];
}
});
var index = 0,
doneStr = ' done: ' + mal.entries.done + '/' + mal.entries.total,
failStr = ' fail: ' + mal.entries.fail;
mal.entries.done = mal.entries.fail = 0;
mal.entries.total = Object.keys(mal.entries.right).length;
if (mal.entries.total === 0) {
mal.content.updateList(true);
return;
}
$.each(mal.entries.right, function(id) {
setTimeout(function() {
$.ajax('/' + mal.settings.type + '/' + id)
.done(function(data) {
mal.entries.findRelations(id, data);
mal.content.done.text(doneStr + '+' + (++mal.entries.done) + '/' + mal.entries.total);
mal.content.updateList(true);
})
.fail(function() {
mal.content.fail.text(failStr + '+' + (++mal.entries.fail));
mal.content.updateList(true);
});
}, mal.settings.ajax.delay * (index++));
});
},
comparator: function(a, b) {
var aTitle = mal.entries.getTitle(a).toLowerCase(),
bTitle = mal.entries.getTitle(b).toLowerCase();
return aTitle.localeCompare(bTitle);
},
findRelations: function(lId, data) {
var result = [],
relations = data.match(/>Related (Anime|Manga)<\/h2>([\s\S]*?)<h2>/);
if (relations === null) {
return result;
}
var re = '([^:]+):\\s*([\\s\\S]*?)<br>',
categories = relations[2].trim().match(new RegExp(re, 'g'));
if (categories === null) {
return result;
}
for (var i = 0; i < categories.length; ++i) {
var reData = categories[i].match(new RegExp(re)),
type = reData[1],
rels = reData[2];
if (type.match(new RegExp('(' + mal.settings.excludedRelations.join('|') + ')', 'i'))) {
continue;
}
$('a[href]', '<context>' + rels + '</context>').each(function() {
var idData = $(this).prop('href').match(/\d+/);
if (idData === null) {
console.log('Empty Relation: ' + lId);
return;
}
var rId = parseInt(idData[0]);
mal.entries.title[rId] = $(this).text().trim();
mal.entries.addRelation(lId, rId);
result.push(rId);
});
}
return result;
},
addRelation: function(lId, rId) {
if (!mal.entries.graph.hasOwnProperty(lId)) {
mal.entries.graph[lId] = [];
}
if (!mal.entries.graph.hasOwnProperty(rId)) {
mal.entries.graph[rId] = [];
}
if (mal.entries.graph[lId].indexOf(rId) < 0) {
mal.entries.graph[lId].push(rId);
mal.entries.graph[rId].push(lId);
}
},
checkRelation: function(data) {
var myStatusData = data.match(/selected>(.*?)<\/option/);
if (myStatusData === null) {
return false;
}
var status = data.match(/>Status:<\/span>([\s\S]*?)<\/div>/)[1].trim();
var myStatus = myStatusData[1].trim();
if ((status.match(/Not yet/) && !myStatus.match(/Plan to/)) ||
(status.match(/(Currently|Publishing)/) && myStatus === 'Completed')) {
return false;
}
if (myStatus !== 'Completed') {
return true;
}
function check(type, selector) {
var progRe = new RegExp('>' + type + ':</span>([\\s\\S]*?)</div>', 'i'),
myprRe = new RegExp(selector + '[\\s\\S]*?value="(\\d*)"'),
prog = data.match(progRe)[1].trim().replace('Unknown', '0'),
mypr = data.match(myprRe)[1].trim();
return parseInt(mypr) === parseInt(prog);
}
if (mal.settings.type === 'anime') {
if (!check('Episodes', 'name="myinfo_watchedeps"')) {
return false;
}
}
else {
if (!check('Volumes', 'id="myinfo_volumes"') ||
!check('Chapters', 'id="myinfo_chapters"')){
return false;
}
}
return true;
},
findComps: function() {
var result = {}, used = {}, comp = [];
function dfs(v) {
used[v] = true;
comp.push(v);
if (!mal.entries.graph.hasOwnProperty(v)) {
return;
}
$.each(mal.entries.graph[v], function(i, to) {
if (!used.hasOwnProperty(to)) {
dfs(to);
}
});
}
$.each(mal.entries.graph, function(v) {
if (!used.hasOwnProperty(v)) {
comp = [];
dfs(v);
if (comp.length > 1) {
result[v] = comp;
}
}
});
return result;
}
};
mal.content = {
body: $('<div id="mr_body" class="mr_body"></div>'),
list: $('<div class="mr_list"></div>'),
settings: $('<div id="mr_settings" class="mr_body"><div class="mr_list"></div></div>'),
done: $('<span id="mr_status_done" style="color: green;"></span>'),
fail: $('<span id="mr_status_fail" style="color: #c32;"></span>'),
updateList: function(save) {
if (mal.entries.isUpdating()) {
return;
}
if (save) {
mal.entries.save();
}
var title = $('#mr_body_title', mal.content.body),
listType = $('<input type="hidden" id="mr_list_type" value="' + mal.settings.type + '" />');
title.html(title.html().replace(/^[\s\S]*? </, 'Missing Relations – ' + (mal.settings.type === 'anime' ? 'Anime' : 'Manga') + ' <'));
var comps = mal.entries.findComps();
if (Object.keys(comps).length === 0) {
var p = $('<p>No missing relations found.</p>');
if (document.URL.match(/^http:\/\/myanimelist\.net\/panel\.php$/)) {
p.append(' ').append('<a href="' + (mal.settings.type === 'anime' ? '/editlist.php?type=anime' : '/panel.php?go=editmanga') + '">Refresh</a>');
}
mal.content.list.empty().append(p).append(listType);
return;
}
var table = $('<table class="relTable" border="0" cellpadding="0" cellspacing="0" width="100%"><thead><tr><th>You\'ve ' + (mal.settings.type === 'anime' ? 'watched' : 'read') + ' this…</th><th>…so you might want to check this:</th></tr></table>'),
undel = $('<div id="mr_undelete"><p id="mr_undelete_msg" style="display: none;">There are <span id="mr_undelete_num" style="font-weight: bold;"></span> hidden relations. <a href="javascript:void(0);" title="Show ignored relations" onclick="window.showIgnoredRelations();">Show them</a></p></div>'),
tfoot = $('<tfoot><tr><td class="mr_td_left"><div class="mr_count"><span></span></div></td><td class="mr_td_right"><div class="mr_count"><span></span></div></td></tr></tfoot>');
// red relations
var wrong = Object.keys(mal.entries.wrong);
if (wrong.length > 0) {
var ul = $('<ul></ul>'), size = 0;
$.each(wrong.sort(mal.entries.comparator), function(i, id) {
mal.content.getLiLeft(id).prop('id', 'mr_li_red_' + id).appendTo(ul);
++size;
});
var tbody = $('<tbody></tbody>'),
tr = $('<tr class="mr_tr_data"></tr>')
.append($('<td class="mr_td_left"></td>').append(ul))
.append($('<td class="mr_td_right"></td>').append(mal.content.getEntryWarning()))
.appendTo(tbody);
if (size > 5) {
tr.addClass('mr_tr_collapsed');
$('<tr class="mr_tr_more"></tr>').append(mal.content.getMoreLink()).insertAfter(tr);
}
tbody.appendTo(table);
}
// normal relations
$.each(Object.keys(comps).sort(mal.entries.comparator), function(i, key) {
var ulLeft = $('<ul></ul>'), ulRight = $('<ul></ul>'),
lSize = 0, rSize = 0;
$.each(comps[key].sort(mal.entries.comparator), function(i, id) {
if (mal.entries.left.hasOwnProperty(id)) {
mal.content.getLiLeft(id).prop('id', 'mr_li_' + id).appendTo(ulLeft);
++lSize;
}
else {
mal.content.getLiRight(id).prop('id', 'mr_li_' + id).appendTo(ulRight);
++rSize;
}
});
if (lSize > 0 && rSize > 0) {
var tbody = $('<tbody></tbody>'),
tr = $('<tr class="mr_tr_data"></tr>')
.append($('<td class="mr_td_left"></td>').append(ulLeft))
.append($('<td class="mr_td_right"></td>').append(ulRight))
.appendTo(tbody);
if (lSize > 5 || rSize > 5) {
tr.addClass('mr_tr_collapsed');
$('<tr class="mr_tr_more"></tr>').append(mal.content.getMoreLink()).insertAfter(tr);
}
tbody.appendTo(table);
}
});
mal.content.list.empty()
.append(undel)
.append(table.append(tfoot))
.append(listType);
mal.hideIgnoredRelations(true);
mal.content.updateLineCount();
},
updateSettings: function() {
var title = $('#mr_body_title', mal.content.settings);
title.html(title.html().replace(/^[\s\S]*? </, 'Missing Relations – Settings <'));
var list = $('.mr_list', mal.content.settings),
table = $('<table class="relTable" border="0" cellpadding="0" cellspacing="0" width="100%"><thead><tr><th>Exclude Anime Relations:</th><th>Exclude Manga Relations:</th></tr><tbody></tbody></table>'),
other = $('<table class="relTable" border="0" cellpadding="0" cellspacing="0" width="100%"><thead><tr><th>Ignore Anime Entries:</th><th>Ignore Manga Entries:</th></tr><tbody></tbody></table>');
var buttons = $('<div class="mr_buttons"></div>')
.append(mal.content.getBtnSave())
.append(mal.content.getBtnCancel())
.append(mal.content.getBtnReset());
// Add exclude relations
var tbody = $('tbody', table);
$.each(mal.settings.availableRelations, function(i, rel) {
$('<tr class="mr_tr_data"></tr>')
.append($('<td class="mr_td_left"></td>').append(mal.content.getCbSetting(rel, 'mr_xa_' + rel, false)))
.append($('<td class="mr_td_right"></td>').append(mal.content.getCbSetting(rel, 'mr_xm_' + rel, false)))
.appendTo(tbody);
});
// Add ignore status
tbody = $('tbody', other);
for (var i = 0; i < mal.settings.availableStatus['anime'].length; ++i) {
var statusA = mal.settings.availableStatus['anime'][i],
statusM = mal.settings.availableStatus['manga'][i];
$('<tr class="mr_tr_data"></tr>')
.append($('<td class="mr_td_left"></td>').append(mal.content.getCbSetting(statusA, 'mr_xsa_' + statusA, statusA.match(/^Plan to/) !== null)))
.append($('<td class="mr_td_right"></td>').append(mal.content.getCbSetting(statusM, 'mr_xsm_' + statusM, statusM.match(/^Plan to/) !== null)))
.appendTo(tbody);
}
list.empty()
.append(table)
.append(other);
if (!mal.entries.isUpdating()) {
list.append(buttons);
}
else {
list.append(buttons.empty().append('<p>The settings can\'t be changed during relations calculation.</p>'));
}
},
getLiLeft: function(id) {
return $('<li></li>')
.append(mal.content.getEntryLink(id, mal.entries.getTitle(id)));
},
getLiRight: function(id) {
return $('<li></li>')
.append(mal.content.getHideButton('window.ignoreRelation(' + id + ');', 'Hide this relation'))
.append(mal.content.getEntryLink(id, mal.entries.getTitle(id)));
},
getCbSetting: function(str, id, state) {
id = id.toHtmlId();
state = state.toString();
return $('<div class="mr_checkbox"></div>')
.append($('<input name="' + id + '" id="' + id + '" type="checkbox" />').prop('checked', mal.loadValue(id, state) !== 'false'))
.append('<label for="' + id + '">' + str + '</label>');
},
getBtnSave: function() {
return $('<input class="inputButton" value="Save" type="button" />').click(function() {
$('input[type="checkbox"]', mal.content.settings).each(function() {
mal.saveValue(this.id, $(this).prop('checked').toString());
});
parent.$.fancybox.close();
});
},
getBtnCancel: function() {
return $('<input class="inputButton" value="Cancel" type="button" />').click(function() {
parent.$.fancybox.close();
});
},
getBtnReset: function() {
return $('<input class="inputButton" value="Reset" type="button" />').click(function() {
if (true === confirm('Reset all settings?')) {
mal.settings.reset();
parent.$.fancybox.close();
}
});
},
getEntryLink: function(id, title) {
return $('<a title="' + title + '"href="' + '/' + mal.settings.type + '/' + id + '" target="_blank">' + title + '</a>');
},
getEntryWarning: function() {
return $('<div class="mr_warning"><span>Wrong status or ' + (mal.settings.type === 'anime' ? 'episode' : 'vol./chap.') + ' count</span></div>');
},
getHideButton: function(func, title) {
return $('<div class="mr_hide"><span><a href="javascript:void(0);" title="' + title + '" onclick="' + func + '">x</a></span></div>');
},
getMoreLink: function() {
var result = $('<td colspan="2"></td>');
$('<a class="mr_more" href="javascript:void(0);">show more</a>').click(function() {
var tr = $(this).closest('tr');
tr.prev('.mr_tr_data').removeClass('mr_tr_collapsed');
tr.remove();
}).appendTo(result);
return result;
},
updateLineCount: function() {
var count = $('.relTable td.mr_td_right li:not([style*="display: none"])', mal.content.list).length,
total = $('.relTable td.mr_td_right li', mal.content.list).length,
left = $('.relTable td.mr_td_left li', mal.content.list).length;
$('tfoot td.mr_td_left .mr_count span', mal.content.list).text('Total: ' + left);
$('tfoot td.mr_td_right .mr_count span', mal.content.list).text('Total: ' + total + ', Visible: ' + count);
}
};
mal.ignoreRelation = function(id, save) {
var li = $('td.mr_td_right li[id="mr_li_' + id + '"]', mal.content.list);
if (li.length === 0) {
if (mal.entries.ignore.hasOwnProperty(id)) {
delete mal.entries.ignore[id];
}
if (save) {
mal.entries.saveIgnore();
}
return;
}
var row = li.hide().closest('tbody'),
lSize = $('td.mr_td_left li', row).length,
rSize = $('td.mr_td_right li:not([style*="display: none;"])', row).length;
row.toggle(rSize > 0);
if (lSize <= 5 && rSize <= 5) {
$('a.mr_more', row).trigger('click');
}
mal.entries.ignore[id] = true;
if (save) {
mal.entries.saveIgnore();
var count = Object.keys(mal.entries.ignore).length;
$('#mr_undelete_num', mal.content.list).text(count);
$('#mr_undelete_msg', mal.content.list).toggle(count > 0);
}
};
mal.hideIgnoredRelations = function(save) {
mal.showIgnoredRelations(false);
$.each(mal.entries.ignore, function(id) {
mal.ignoreRelation(id, false);
});
var count = Object.keys(mal.entries.ignore).length;
$('#mr_undelete_num', mal.content.list).text(count);
$('#mr_undelete_msg', mal.content.list).toggle(count > 0);
if (save) {
mal.entries.saveIgnore();
}
};
mal.showIgnoredRelations = function(save) {
$('#mr_undelete_msg', mal.content.list).hide();
$('li[id^="mr_li_"]', mal.content.list).show();
$('tbody', mal.content.list).show();
if (save) {
mal.entries.clearIgnore();
mal.entries.saveIgnore();
}
};
mal.loadValue = function(key, value) {
try {
value = JSON.parse(localStorage.getItem(mal.settings.name + '#' + mal.settings.type + '#' + key)) || value;
} catch (e) {}
return value;
};
mal.saveValue = function(key, value) {
localStorage.setItem(mal.settings.name + '#' + mal.settings.type + '#' + key, JSON.stringify(value));
};
window.ignoreRelation = function(id) {
mal.ignoreRelation(id, true);
mal.content.updateLineCount();
};
window.showIgnoredRelations = function() {
mal.showIgnoredRelations(true);
mal.content.updateLineCount();
};
String.prototype.toHtmlId = function() {
return this.trim().toLowerCase().replace(/\s/g, '_').replace(/[^\w]/g, '_');
};
$('<style type="text/css"></style>').html(
'#content span[class^="mr_status_id_"] { float: right; padding: 0 7px; }' +
'div.mr_body { text-align: center; width: 670px; height: auto; }' +
'div.mr_body a, div.mr_body a:visited { color: #1969cb; text-decoration: none; }' +
'div.mr_body a:hover { color: #2d7de0; text-decoration: underline; }' +
'div.mr_body #mr_body_title { font-size: 16px; font-weight: normal; text-align: center; margin: 0 0 8px 0; position: relative; border: 0; }' +
'div.mr_body #mr_body_title span { font-size: 12px; font-weight: normal; }' +
'div.mr_body #mr_body_title:after { content: ""; position: absolute; bottom: -14px; left: 0; width: 100%; height: 8px; border-top: 1px solid #eee; background: center bottom no-repeat radial-gradient(#f6f6f6, #fff 70%); background-size: 100% 16px; }' +
'div.mr_body div#mr_undelete { background-color: #fff; padding: 0; margin: 0; }' +
'div.mr_body p#mr_undelete_msg { margin: 0 0 10px; font-weight: normal; text-align: center; line-height: 20px; font-size: 13px; }' +
'div.mr_body .mr_list { width: auto; height: 680px; overflow-x: hidden; overflow-y: auto; margin: 18px auto 0; }' +
'div.mr_body .relTable { border: 1px solid #f5f5f5; }' +
'div.mr_body .relTable thead { background-color: #f5f5f5; }' +
'div.mr_body .relTable th { background-color: transparent; width: 50%; padding: 5px 0 5px 6px; font-size: 12px; font-weight: bold; text-align: left; line-height: 20px !important; box-shadow: none; }' +
'div.mr_body .relTable tbody { background-color: #fff; }' +
'div#mr_body .relTable tbody:hover { background-color: #f5f5f5; }' +
'div#mr_body .relTable tbody tr:first-of-type td { box-shadow: 0px 1em 1em -1em #ddd inset; }' +
'div.mr_body .relTable td { background-color: transparent; width: 50%; padding: 5px 0 5px 6px; font-size: 13px; font-weight: normal; text-align: left; line-height: 20px !important; vertical-align: top; }' +
'div.mr_body .relTable td div span { line-height: 20px !important; }' +
'div.mr_body .relTable td ul { list-style-type: none; margin: 0; padding: 0; }' +
'div.mr_body .relTable tr.mr_tr_collapsed td ul { height: 100px; overflow-y: hidden; }' +
'div.mr_body .relTable td ul li { width: 100%; padding: 0; margin: 0; }' +
'div.mr_body .relTable td ul li > a { display: block; width: 295px !important; line-height: 20px !important; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }' +
'div.mr_body .relTable td.mr_td_left ul li > a { width: 310px !important; }' +
'div.mr_body .relTable tfoot td { border-top: 1px solid #f5f5f5; }' +
'div.mr_body .relTable td .mr_count { color: #666; font-size: 11px; font-weight: normal; text-align: left; }' +
'div.mr_body .relTable td .mr_warning { width: 260px; color: #e43; font-size: 12px; font-weight: bold; text-align: left; }' +
'div.mr_body .relTable td .mr_hide { display: inline-block !important; width: 15px; float: right; text-align: left; font-size: 11px; }' +
'div.mr_body .relTable td .mr_hide a { color: #888 !important; line-height: 20px !important; font-style: normal !important; text-decoration: none !important; }' +
'div.mr_body .relTable tr.mr_tr_more td { padding: 0 0 2px 0; }' +
'div.mr_body .relTable td .mr_more { display: block !important; text-align: center; color: #c0c0c0 !important; font-style: normal !important; font-size: 0.9em; text-decoration: none !important; }' +
'div.mr_body .relTable .mr_checkbox > * { vertical-align: middle; }' +
'div.mr_body .mr_buttons { position: absolute; bottom: 0; width: 100%; text-align: center; padding: 5px 10px; }' +
'div.mr_body .mr_buttons > input { margin: 2px 5px !important; }' +
'div#mr_settings .relTable { margin-bottom: 10px; }'
).appendTo('head');
main();
})(jQuery);