diff --git a/main.js b/main.js index fb635a6..952c24d 100644 --- a/main.js +++ b/main.js @@ -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"}); + $($("") + .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($("") - .css("display", "none").text($(elem).text())); - + $(elem).after($("").hide().text($(elem).text())); load_score_into_element(data, anime_id, $(elem)); $("#scorediv" + anime_id) .after($("
") .attr("id", "scorediv" + anime_id) - .css("display", "none") + .hide() .append($('') .attr("type", "text") .attr("id", "scoretext" + anime_id) @@ -504,6 +550,80 @@ function hook_addtolist() { "page, and update the score.

").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($("
") + .css("border", "none") + .css("background-color", "#AAA") + .css("height", "1px")) + .append($("

") + .html("The regular list export above will only include " + + "rounded scores. You can export your decimal scores " + + "separately and " + + 'import ' + + "them later.")) + .append($("

") + .attr("class", "spaceit") + .html("Chrome Sync usage: " + usage)) + .append($("") + .attr("type", "submit") + .attr("value", "Export Decimal Scores") + .attr("class", "inputButton") + .click(export_scores)); + }); +} + +function hook_import() { + $("#content").append($("
") + .css("border", "none") + .css("background-color", "#AAA") + .css("height", "1px")) + .append($("

") + .html("You can also import decimal scores here. Doing so will " + + "erase any existing decimal scores.")) + .append($("

") + .attr("class", "spaceit") + .append($("") + .attr("id", "decimal-file") + .attr("size", "60") + .attr("type", "file") + .attr("class", "inputtext"))) + .append($("") + .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("

Success!

") + .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(); } });