From 1ebb0d25275b8f37fc5648480cbf54b50d1410ff Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Mon, 11 Feb 2019 11:11:51 +0200 Subject: [PATCH] Got character copying working --- .../views/character/characterSheet.html | 10 +- app/client/views/character/characterSheet.js | 12 +++ app/lib/functions/backupRestoreCharacter.js | 61 +++++++----- app/lib/methods/characterCopyPaste.js | 4 + app/package-lock.json | 93 +++++++++++++++++-- app/package.json | 1 + 6 files changed, 148 insertions(+), 33 deletions(-) diff --git a/app/client/views/character/characterSheet.html b/app/client/views/character/characterSheet.html index 8785892b..efc54123 100644 --- a/app/client/views/character/characterSheet.html +++ b/app/client/views/character/characterSheet.html @@ -31,9 +31,17 @@ Settings - + Export to Improved Initiative + + + Make a copy + + + + Download a backup + {{else}} diff --git a/app/client/views/character/characterSheet.js b/app/client/views/character/characterSheet.js index a2a549f4..0c43d387 100644 --- a/app/client/views/character/characterSheet.js +++ b/app/client/views/character/characterSheet.js @@ -234,6 +234,18 @@ Template.characterSheet.events({ element: event.currentTarget.parentElement.parentElement, }); }, + "click #characterCopy": function(event, instance){ + Meteor.call("copyCharacter", this._id, (error, char) => { + if (error){ + console.error(error); + } else { + Router.go(`/character/${char._id}/${char.urlName || "-"}`); + } + }); + }, + "click #characterDump": function(event, instance){ + saveCharacterDump(this._id); + }, "click #unshareCharacter": function(event, instance){ pushDialogStack({ data: this, diff --git a/app/lib/functions/backupRestoreCharacter.js b/app/lib/functions/backupRestoreCharacter.js index d08ef919..9863d12f 100644 --- a/app/lib/functions/backupRestoreCharacter.js +++ b/app/lib/functions/backupRestoreCharacter.js @@ -1,24 +1,29 @@ -let characterCollections = [ - Actions, - Attacks, - Buffs, - Classes, - Conditions, - CustomBuffs, - Effects, - Experiences, - Features, - Notes, - Proficiencies, - SpellLists, - Spells, - TemporaryHitPoints, - Items, - Containers, -]; +import { saveAs } from 'file-saver'; -function dumpCharacter(charId){ - let characterDump = {}; +let characterCollections = []; +Meteor.startup(() => { + characterCollections = [ + Actions, + Attacks, + Buffs, + Classes, + Conditions, + CustomBuffs, + Effects, + Experiences, + Features, + Notes, + Proficiencies, + SpellLists, + Spells, + TemporaryHitPoints, + Items, + Containers, + ]; +}); + +dumpCharacter = function(charId){ + let characterDump = {collections: {}}; characterDump.character = Characters.findOne(charId); characterCollections.forEach(c => { characterDump.collections[c._name] = c.find({charId}).fetch(); @@ -26,13 +31,23 @@ function dumpCharacter(charId){ return characterDump; }; -function giveCharacterDumpNewIds(characterDump){ +saveCharacterDump = function(charId){ + let dump = dumpCharacter(charId); + let textDump = JSON.stringify(dump, null, 2); + let charName = dump.character.name; + let blob = new Blob([textDump], {type: "application/json;charset=utf-8"}); + saveAs(blob, `${charName}.JSON`); +}; + +giveCharacterDumpNewIds = function(characterDump){ // Give the character a new Id + const oldCharId = characterDump.character._id; const newCharId = Random.id(); characterDump.character._id = newCharId; + let idMap = {[oldCharId]: newCharId}; // {oldId: newId} + // Give all documents a new Id, and store the mapping from old to new - let idMap = {}; // {oldId: newId} for (let colName in characterDump.collections){ for (let doc of characterDump.collections[colName]){ let oldId = doc._id; @@ -57,7 +72,7 @@ function giveCharacterDumpNewIds(characterDump){ } } -function restoreCharacter(characterDump){ +restoreCharacter = function(characterDump){ Characters.insert(characterDump.character); for (collectionName in characterDump.collections){ let collection = Meteor.Collection.get(collectionName); diff --git a/app/lib/methods/characterCopyPaste.js b/app/lib/methods/characterCopyPaste.js index d078b45b..76173202 100644 --- a/app/lib/methods/characterCopyPaste.js +++ b/app/lib/methods/characterCopyPaste.js @@ -16,7 +16,11 @@ Meteor.methods({ characterDump.character.writers = []; characterDump.character.owner = userId; + // Rename the character so it's obviously a copy + characterDump.character.name += " - Copy"; + // Write the character back to the database restoreCharacter(characterDump); + return characterDump.character; }, }); diff --git a/app/package-lock.json b/app/package-lock.json index 12e5ed0b..3c606c15 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -45,7 +45,7 @@ }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { @@ -74,6 +74,7 @@ }, "block-stream": { "version": "0.0.9", + "resolved": false, "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "requires": { "inherits": "~2.0.0" @@ -131,7 +132,7 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "core-js": { @@ -139,6 +140,11 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -209,6 +215,11 @@ "resolved": "https://registry.npmjs.org/fibers/-/fibers-2.0.2.tgz", "integrity": "sha512-HfVRxhYG7C8Jl9FqtrlElMR2z/8YiLQVDKf67MLY25Ic+ILx3ecmklfT1v3u+7P5/4vEFjuxaAFXhr2/Afwk5g==" }, + "file-saver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.0.tgz", + "integrity": "sha512-cYM1ic5DAkg25pHKgi5f10ziAM7RJU37gaH1XQlyNDrtUnzhC/dfoV9zf2OmF0RMKi42jG5B0JWBnPQqyj/G6g==" + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -259,7 +270,7 @@ }, "graceful-fs": { "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "resolved": false, "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "har-schema": { @@ -361,6 +372,7 @@ }, "inherits": { "version": "2.0.3", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "invert-kv": { @@ -383,7 +395,7 @@ }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -1064,6 +1076,37 @@ "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "stream-http": { @@ -1076,6 +1119,37 @@ "readable-stream": "^2.3.3", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "string_decoder": { @@ -1434,7 +1508,7 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "os-homedir": { @@ -1578,6 +1652,7 @@ }, "minimist": { "version": "1.2.0", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "strip-json-comments": { @@ -1815,7 +1890,7 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "shebang-command": { @@ -1833,7 +1908,7 @@ }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "source-map": { @@ -1909,7 +1984,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -2159,7 +2234,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/app/package.json b/app/package.json index 13ecdf36..fbbadeae 100644 --- a/app/package.json +++ b/app/package.json @@ -17,6 +17,7 @@ "bower": "^1.7.9", "core-js": "^2.5.7", "fibers": "^2.0.2", + "file-saver": "^2.0.0", "meteor-node-stubs": "^0.3.3", "qrcode": "^1.3.0", "source-map-support": "^0.5.9",