diff --git a/4chan_x.user.js b/4chan_x.user.js
index 4aeca678d..e6a103130 100644
--- a/4chan_x.user.js
+++ b/4chan_x.user.js
@@ -1240,6 +1240,10 @@
},
main: function(section) {
var ID, arr, checked, description, hiddenNum, key, li, obj, post, thread, ul, _ref, _ref1, _ref2;
+ section.innerHTML = "
\n \n \n \n
\n";
+ $.on($('.export', section), 'click', Settings["export"]);
+ $.on($('.import', section), 'click', Settings["import"]);
+ $.on($('input', section), 'change', Settings.onImport);
_ref = Config.main;
for (key in _ref) {
obj = _ref[key];
@@ -1283,6 +1287,74 @@
});
return $.after($('input[name="Stubs"]', section).parentNode.parentNode, li);
},
+ "export": function() {
+ var a, data, now, output;
+ now = Date.now();
+ data = {
+ version: g.VERSION,
+ date: now,
+ Conf: Conf,
+ WatchedThreads: $.get('WatchedThreads', {})
+ };
+ a = $.el('a', {
+ className: 'warning',
+ textContent: 'Save me!',
+ download: "4chan X Beta-" + now + ".json",
+ href: "data:application/json;base64," + (btoa(unescape(encodeURIComponent(JSON.stringify(data))))),
+ target: '_blank'
+ });
+ if ($.engine !== 'gecko') {
+ a.click();
+ return;
+ }
+ output = this.parentNode.nextElementSibling;
+ output.innerHTML = null;
+ return $.add(output, a);
+ },
+ "import": function() {
+ return this.nextElementSibling.click();
+ },
+ onImport: function() {
+ var file, output, reader;
+ if (!(file = this.files[0])) {
+ return;
+ }
+ output = this.parentNode.nextElementSibling;
+ if (!confirm('Your current settings will be entirely overwritten, are you sure?')) {
+ output.textContent = 'Import aborted.';
+ return;
+ }
+ reader = new FileReader();
+ reader.onload = function(e) {
+ var data;
+ try {
+ data = JSON.parse(decodeURIComponent(escape(e.target.result)));
+ Settings.loadSettings(data);
+ if (confirm('Import successful. Refresh now?')) {
+ return window.location.reload();
+ }
+ } catch (err) {
+ output.textContent = 'Import failed due to an error.';
+ return $.log(err.stack);
+ }
+ };
+ return reader.readAsText(file);
+ },
+ loadSettings: function(data) {
+ var key, val, _ref;
+ if (data.version.split('.')[0] === '2') {
+ data = Settings.convertSettingsFromV2(data);
+ }
+ _ref = data.Conf;
+ for (key in _ref) {
+ val = _ref[key];
+ $.set(key, val);
+ }
+ return $.set('WatchedThreads', data.WatchedThreads);
+ },
+ convertSettingsFromV2: function(data) {
+ return data;
+ },
filter: function(section) {
var select;
section.innerHTML = "Filter is disabled.
\n\n";
diff --git a/src/features.coffee b/src/features.coffee
index 85c714c0d..6fa5e8488 100644
--- a/src/features.coffee
+++ b/src/features.coffee
@@ -226,6 +226,18 @@ Settings =
section.scrollTop = 0
main: (section) ->
+ section.innerHTML = """
+
+
+
+
+
+
+ """
+ $.on $('.export', section), 'click', Settings.export
+ $.on $('.import', section), 'click', Settings.import
+ $.on $('input', section), 'change', Settings.onImport
+
for key, obj of Config.main
ul = $.el 'ul',
textContent: key
@@ -252,6 +264,54 @@ Settings =
$.delete "hiddenThreads.#{g.BOARD}"
$.delete "hiddenPosts.#{g.BOARD}"
$.after $('input[name="Stubs"]', section).parentNode.parentNode, li
+ export: ->
+ now = Date.now()
+ data =
+ version: g.VERSION
+ date: now
+ Conf: Conf
+ WatchedThreads: $.get('WatchedThreads', {})
+ a = $.el 'a',
+ className: 'warning'
+ textContent: 'Save me!'
+ download: "<%= meta.name %>-#{now}.json"
+ href: "data:application/json;base64,#{btoa unescape encodeURIComponent JSON.stringify data}"
+ target: '_blank'
+ if $.engine isnt 'gecko'
+ a.click()
+ return
+ # XXX Firefox won't let us download automatically.
+ output = @parentNode.nextElementSibling
+ output.innerHTML = null
+ $.add output, a
+ import: ->
+ @nextElementSibling.click()
+ onImport: ->
+ return unless file = @files[0]
+ output = @parentNode.nextElementSibling
+ unless confirm 'Your current settings will be entirely overwritten, are you sure?'
+ output.textContent = 'Import aborted.'
+ return
+ reader = new FileReader()
+ reader.onload = (e) ->
+ try
+ data = JSON.parse decodeURIComponent escape e.target.result
+ Settings.loadSettings data
+ if confirm 'Import successful. Refresh now?'
+ window.location.reload()
+ catch err
+ output.textContent = 'Import failed due to an error.'
+ $.log err.stack
+ reader.readAsText file
+ loadSettings: (data) ->
+ if data.version.split('.')[0] is '2'
+ data = Settings.convertSettingsFromV2 data
+ for key, val of data.Conf
+ $.set key, val
+ $.set 'WatchedThreads', data.WatchedThreads
+ convertSettingsFromV2: (data) ->
+ # XXX TODO
+ data
filter: (section) ->
section.innerHTML = """