|
|
@@ -138,6 +138,54 @@ function remove_score(anime_id) { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function export_scores() { |
|
|
|
chrome.storage.sync.get(null, function(dat) { |
|
|
|
var blob = new Blob([JSON.stringify(dat)], {type: "application/json"}); |
|
|
|
$($("<a>") |
|
|
|
.attr("href", window.URL.createObjectURL(blob)) |
|
|
|
.attr("download", "animelist_decimal_scores.json") |
|
|
|
.hide() |
|
|
|
.appendTo($("body"))[0].click()).remove(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function validate_score_data(data) { |
|
|
|
if (!$.isPlainObject(data)) |
|
|
|
throw "invalid data type: " + data; |
|
|
|
if (JSON.stringify(data).length > chrome.storage.sync.QUOTA_BYTES) |
|
|
|
throw "file too large"; |
|
|
|
|
|
|
|
for (var bucket_id in data) { |
|
|
|
if (data.hasOwnProperty(bucket_id)) { |
|
|
|
if (isNaN(parseInt(bucket_id) || bucket_id >= MAX_BUCKETS)) |
|
|
|
throw "invalid bucket ID: " + bucket_id; |
|
|
|
var bucket = data[bucket_id]; |
|
|
|
if (!$.isPlainObject(bucket)) |
|
|
|
throw "invalid bucket type: " + bucket; |
|
|
|
for (var anime_id in bucket) { |
|
|
|
if (data.hasOwnProperty(anime_id)) { |
|
|
|
if (isNaN(parseInt(anime_id))) |
|
|
|
throw "invalid anime ID: " + anime_id; |
|
|
|
if (parseInt(anime_id) % MAX_BUCKETS != bucket_id) |
|
|
|
throw "anime is in the wrong bucket: " + anime_id; |
|
|
|
var score = parseFloat(bucket[anime_id]); |
|
|
|
if (isNaN(score)) |
|
|
|
throw "score is not a number: " + score; |
|
|
|
if ((score < 1 || score > 10) && score != 0) |
|
|
|
throw "score out of range: " + score; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
function import_scores(data, callback) { |
|
|
|
validate_score_data(data); |
|
|
|
chrome.storage.sync.clear(function() { |
|
|
|
chrome.storage.sync.set(data, callback); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/* ----------------------- Event patches/injections ------------------------ */ |
|
|
|
|
|
|
|
function update_list_score(anime_id) { |
|
|
@@ -307,15 +355,13 @@ function hook_list() { |
|
|
|
$("span[id^='scoreval']").each(function(i, elem) { |
|
|
|
var anime_id = elem.id.split("scoreval")[1]; |
|
|
|
|
|
|
|
$(elem).after($("<span>") |
|
|
|
.css("display", "none").text($(elem).text())); |
|
|
|
|
|
|
|
$(elem).after($("<span>").hide().text($(elem).text())); |
|
|
|
load_score_into_element(data, anime_id, $(elem)); |
|
|
|
|
|
|
|
$("#scorediv" + anime_id) |
|
|
|
.after($("<div>") |
|
|
|
.attr("id", "scorediv" + anime_id) |
|
|
|
.css("display", "none") |
|
|
|
.hide() |
|
|
|
.append($('<input>') |
|
|
|
.attr("type", "text") |
|
|
|
.attr("id", "scoretext" + anime_id) |
|
|
@@ -504,6 +550,80 @@ function hook_addtolist() { |
|
|
|
"page, and update the score.</p>").insertAfter($("#stype").parent()); |
|
|
|
} |
|
|
|
|
|
|
|
function hook_export() { |
|
|
|
chrome.storage.sync.getBytesInUse(null, function(usage) { |
|
|
|
usage = Math.round(usage / 1024 * 10) / 10; |
|
|
|
usage += " kB / " + chrome.storage.sync.QUOTA_BYTES / 1024 + " kB"; |
|
|
|
$("#dialog td") |
|
|
|
.append($("<hr>") |
|
|
|
.css("border", "none") |
|
|
|
.css("background-color", "#AAA") |
|
|
|
.css("height", "1px")) |
|
|
|
.append($("<p>") |
|
|
|
.html("The regular list export above will only include " + |
|
|
|
"rounded scores. You can export your decimal scores " + |
|
|
|
"separately and " + |
|
|
|
'<a href="http://myanimelist.net/import.php">import ' + |
|
|
|
"them</a> later.")) |
|
|
|
.append($("<div>") |
|
|
|
.attr("class", "spaceit") |
|
|
|
.html("Chrome Sync usage: " + usage)) |
|
|
|
.append($("<input>") |
|
|
|
.attr("type", "submit") |
|
|
|
.attr("value", "Export Decimal Scores") |
|
|
|
.attr("class", "inputButton") |
|
|
|
.click(export_scores)); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function hook_import() { |
|
|
|
$("#content").append($("<hr>") |
|
|
|
.css("border", "none") |
|
|
|
.css("background-color", "#AAA") |
|
|
|
.css("height", "1px")) |
|
|
|
.append($("<p>") |
|
|
|
.html("You can also import decimal scores here. Doing so will " + |
|
|
|
"erase any existing decimal scores.")) |
|
|
|
.append($("<div>") |
|
|
|
.attr("class", "spaceit") |
|
|
|
.append($("<input>") |
|
|
|
.attr("id", "decimal-file") |
|
|
|
.attr("size", "60") |
|
|
|
.attr("type", "file") |
|
|
|
.attr("class", "inputtext"))) |
|
|
|
.append($("<input>") |
|
|
|
.attr("id", "decimal-submit") |
|
|
|
.attr("type", "submit") |
|
|
|
.attr("value", "Import Decimal Scores") |
|
|
|
.attr("class", "inputButton") |
|
|
|
.click(function() { |
|
|
|
var filelist = $("#decimal-file")[0].files, file, reader; |
|
|
|
if (filelist.length != 1) |
|
|
|
return; |
|
|
|
file = filelist[0]; |
|
|
|
if (file.type != "application/json") { |
|
|
|
alert("Invalid file type: must be .json."); |
|
|
|
return; |
|
|
|
} |
|
|
|
reader = new FileReader(); |
|
|
|
reader.onload = function() { |
|
|
|
try { |
|
|
|
import_scores(JSON.parse(reader.result), function() { |
|
|
|
$("#decimal-file").after("<p>Success!</p>") |
|
|
|
.remove(); |
|
|
|
$("#decimal-submit").remove(); |
|
|
|
}); |
|
|
|
} catch (exc) { |
|
|
|
if (typeof exc === "object") |
|
|
|
alert("The file could not be parsed as JSON."); |
|
|
|
else |
|
|
|
alert("Error validating data: " + exc); |
|
|
|
} |
|
|
|
}; |
|
|
|
reader.readAsText(file); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
/* ------------------------------- Main hook ------------------------------- */ |
|
|
|
|
|
|
|
$(document).ready(function() { |
|
|
@@ -524,5 +644,9 @@ $(document).ready(function() { |
|
|
|
hook_shared(); |
|
|
|
else if (href.contains("/addtolist.php")) |
|
|
|
hook_addtolist(); |
|
|
|
else if (href.contains("/panel.php") && href.contains("go=export")) |
|
|
|
hook_export(); |
|
|
|
else if (href.contains("/import.php")) |
|
|
|
hook_import(); |
|
|
|
} |
|
|
|
}); |