NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name PonyTown Import/Export
// @namespace azedith
// @include https://pony.town/*
// @author Neeve
// @version 0.31.1pre2
// @copyright 2017, Neeve (https://openuserjs.org/users/Neeve)
// @license MIT
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM.getValue
// @grant GM.setValue
// @grant unsafeWindow
// @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
// @require https://raw.githubusercontent.com/Neeve01/PonyTown-Import-Export/master/ponytown_utils.js
// @require https://cdn.jsdelivr.net/npm/clipboard@1/dist/clipboard.min.js
// @updateURL https://openuserjs.org/meta/Neeve/PonyTown_ImportExport.meta.js
// ==/UserScript==
(function() {
'use strict';
var observer_target = document.querySelector("pony-town-app");
if (!observer_target) {
return;
}
var Resources = {
['css']: `
.nmw-overlay{background-color:rgba(51,51,51,0.7);position:fixed;width:100%;height:100%;left:0;top:0;z-index:99999;align-items:center}
.nmw-overlay:not(:empty){display:flex}
.nmw-overlay:empty{display:none}
.nmw-overlay .nmw-form{display:inline-block;position:absolute;transform:translate(-50%,0);width:45vw;min-width:32rem;left:50%;background:#212121;font-family:Helvetica Neue,Helvetica,Arial,sans-serif}
.nmw-overlay .nmw-form .nmw-contents{border:1px solid #9d603b;border-top:none;padding:.75% 1% .25%}
.nmw-overlay .nmw-textarea{font-size:.9em;resize:none;display:block;margin-left:auto;margin-right:auto;width:100%;height:50vh}
.nmw-overlay .nmw-form .nmw-text{display:block;text-align:center;font-size:1.25em;color:#CCC!important;font-weight:700}
.nmw-overlay .nmw-warning{display:block;text-align:center;font-size:1em;line-height:150%;color:#CA7E4E!important;font-weight:700}
.nmw-overlay hr{border:0;border-top:1px solid #555;margin-top:.5rem;margin-bottom:.5rem}
.nmw-overlay .nmw-form .nmw-line-center{display:flex;justify-content:center}
.nmw-overlay .nmw-input{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}
.nmw-overlay .nmw-link{text-decoration:none}
.nmw-overlay .nmw-link i{fill:#9d603b;font-size:.9em}
.nmw-overlay .nmw-form .nmw-btn-close{border:0 solid;background:#CA7E4E;width:2em;height:2em;padding:0;margin:0;color:#FFF;font-size:.75em;border-radius:0}
.nmw-overlay .nmw-form .nmw-btn-wide{width:100%}
.nmw-overlay .nmw-inpad{padding-left:1%;padding-right:1%}
.nmw-overlay .nmw-header{margin:0;padding:0;background:#9d603b;text-align:center;line-height:150%;font-size:1.1em;color:#fff;font-weight:400;padding-left:1%;margin:0}
.nmw-overlay .nmw-row{display:flex;justify-content:space-between}
.nmw-overlay .nmw-row .nmw-col{padding:0;margin:0}
.nmw-overlay .nmw-form .nmw-footer{position:absolute;bottom:0;right:0;transform:translate(0,100%);padding-top:0.15em;font-weight:700}
.nmw-overlay .nmw-form .nmw-footer .nmw-elements{display:flex;justify-content:flex-end;line-height:1;color:#CA7E4E!important;font-size:.75em}
#nmw-button-download{fill:#CCC}
.nmw-span-dimmable{transition:all 1.25s ease-in-out;opacity:1}
.nmw-span-dim{opacity:.65}
.nmw-char-preview-controls{transform:translate(0,-100%);padding:0.25rem;position:absolute;top:100%;right: 0;}
`,
['import-frame']: `
<div class="nmw-row nmw-header">
<label class="nmw-col">Import character</label>
<button id="nmw-button-close" class="nmw-btn-close btn btn-primary nmw-col">
<i class="fa fa-lg fa-times"></i>
</button>
</div>
<div class="nmw-contents">
<textarea autofocus class="nmw-textarea" cols="40" rows="5"></textarea>
<hr>
<div>
<label style="margin-bottom:0" class="nmw-text">Paste your character code inside and press Import.</label>
<label class="nmw-warning">Careful! This will erase current character settings.</label>
</div>
<input id="nmw-file" class="nmw-input" accept=".json,.txt" type="file">
<div class="nmw-line-center">
<label style="min-width: 12.5rem" id="nmw-button-import" class="btn btn-primary">
<i class="fas fa-align-center"></i>
<span class="nmw-span-dimmable">Import</span>
</label>
<label for="nmw-file" style="margin-left:1rem;min-width: 12.5rem" id="nmw-button-download" class="btn btn-primary">
<i class="fas fa-upload"></i>
<span>Import from file</span>
</label>
</div>
</div>
<div class="nmw-footer">
<div class="nmw-elements">
<span class="mr-1">Import/Export © NotMyWing</span>
<a target="_blank" href="https://twitter.com/NotMyWing" class="mr-1 nmw-link">
<i class="fab fa-twitter"></i>
</a>
<a target="_blank" href="https://github.com/Neeve01" class="nmw-link">
<i class="fab fa-github"></i>
</a>
</div>
</div>
`,
['export-frame']: `
<div class="nmw-row nmw-header">
<label class="nmw-col">Exported character</label>
<button id="nmw-button-close" class="nmw-btn-close btn btn-primary nmw-col">
<i class="fa fa-lg fa-times"></i>
</button>
</div>
<div class="nmw-contents">
<textarea autofocus readonly class="nmw-textarea" cols="40" rows="5"></textarea>
<hr>
<div style="margin-bottom:0.5rem" class="nmw-line-center">
<button style="min-width: 10.5rem" id="nmw-button-copy" class="btn btn-primary">
<i class="fas fa-clipboard"></i>
<span class="nmw-span-dimmable">Copy to clipboard</span>
</button>
<button style="margin-left:1rem;min-width: 10.5rem" id="nmw-button-download" class="btn btn-primary">
<i class="fas fa-download"></i>
<span>Download as file</span>
</button>
</div>
</div>
<div class="nmw-footer">
<div class="nmw-elements">
<span class="mr-1">Import/Export © NotMyWing</span>
<a target="_blank" href="https://twitter.com/NotMyWing" class="mr-1 nmw-link">
<i class="fab fa-twitter"></i>
</a>
<a target="_blank" href="https://github.com/Neeve01" class="nmw-link">
<i class="fab fa-github"></i>
</a>
</div>
</div>
`,
['eol-frame']: `
<div class="nmw-row nmw-header">
<label class="nmw-col">End of support</label>
<button id="nmw-button-close" class="nmw-btn-close btn btn-primary nmw-col">
<i class="fa fa-lg fa-times"></i>
</button>
</div>
<div class="nmw-contents">
<h3>Hey there!</h3>
The save/load project has been "officially" discontinued.<br>
If you want to continue using your exported horses, please consider importing them right now, as I give no guarantee of this script being compatible with the next version.<br><br>
Even if it stops working, you would still be able to get your characters' colour codes and patterns from JSON file, just open it with notepad and use the <a href="https://jsonformatter.curiousconcept.com/" target="_blank">JSON formatter</a> to make it readable.
<br><img src="https://github.com/Neeve01/PonyTown-Import-Export/raw/master/quills.gif" style="
width: 12em;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: -webkit-optimize-contrast;
image-rendering: -moz-crisp-edges;
image-rendering: -o-pixelated;
image-rendering: pixelated;
margin: 0 auto;
display: block;
">
<div style="display:block; text-align:center"><br>If you were using this script to bypass the character limit, consider
<br><a href="https://www.patreon.com/agamnentzar" target="_blank">dropping some bits on Aggie's Patreon page</a><br> to increase your character limit.
</div>
<br>- Neeve
</div>
<div class="nmw-footer">
<div class="nmw-elements">
<span class="mr-1">Import/Export © NotMyWing</span>
<a target="_blank" href="https://twitter.com/NotMyWing" class="mr-1 nmw-link">
<i class="fab fa-twitter"></i>
</a>
<a target="_blank" href="https://github.com/Neeve01" class="nmw-link">
<i class="fab fa-github"></i>
</a>
</div>
</div>
`
}
GM_addStyle(Resources["css"]);
var debugging = false;
var githubLink = "https://github.com/Neeve01";
var twitterLink = "https://twitter.com/NotMyWing";
var githubScriptLink = "https://github.com/Neeve01/PonyTown-Import-Export";
var debug = function(a) {
if (debugging) {
console.log(a);
}
}
var rgb2hex = function(rgb) {
if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
};
var TabFunctions = {
["Body"]: {
Tab: 0,
Import: async function(data, tabdata) {
tabdata.BodyColors = [data.Color, data.Outline];
// Horn.
PonyTownUtils.ImportSet(data.Horn, tabdata.Horn);
// Wings.
PonyTownUtils.ImportSet(data.Wings, tabdata.Wings);
// Ears.
PonyTownUtils.ImportSet(data.Ears, tabdata.Ears)
// Front hooves.
PonyTownUtils.ImportSet(data.FrontHooves, tabdata.FrontHooves);
// Back hooves.
PonyTownUtils.ImportSet(data.BackHooves, tabdata.BackHooves);
// Buttmark
tabdata.Buttmark = data.Buttmark;
tabdata.FlipButtmark = data.FlipButtmark || false;
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.CustomOutlines) {
exported.OutlinesEnabled = tabdata.CustomOutlines;
}
let [color, outline] = tabdata.BodyColors;
if (color && color.toLowerCase() !== "ffffff") {
exported.Color = color;
}
if (outline && outline !== "000000") {
exported.Outline = outline;
}
// Horn
if (tabdata.Horn.Type > 0) {
exported.Horn = PonyTownUtils.ExportSet(tabdata.Horn);
}
// Wings
if (tabdata.Wings.Type > 0) {
exported.Wings = PonyTownUtils.ExportSet(tabdata.Wings);
}
// Ears
if (tabdata.Ears.Type > 0) {
exported.Ears = PonyTownUtils.ExportSet(tabdata.Ears);
}
// Front hooves
if (tabdata.FrontHooves.Type > 0) {
exported.FrontHooves = PonyTownUtils.ExportSet(tabdata.FrontHooves);
}
// Back hooves
if (tabdata.BackHooves.Type > 0) {
exported.BackHooves = PonyTownUtils.ExportSet(tabdata.BackHooves);
}
// Buttmark
let mark = tabdata.Buttmark;
if (!mark.every((e) => e === "")) {
exported.Buttmark = mark;
}
if (tabdata.FlipButtmark) {
exported.FlipButtmark = true;
}
return exported;
},
GetButtmark: function(container) {
let element = container.querySelector("bitmap-box");
if (element.tagName == "BITMAP-BOX") {
element = element.children[0];
let pixels = [];
let rows = element.children;
let count = 0;
for (var i = 0; i < rows.length; i++) {
let bits = rows[i].children;
for (var j = 0; j < rows.length; j++) {
pixels[count++] = bits[j].style.backgroundColor ? rgb2hex(bits[j].style.backgroundColor) : "";
}
}
return pixels;
}
},
SetButtmark: function(container, pixels) {
let element = container.querySelector("bitmap-box");
if (element) {
element = element.children[0];
PonyTownUtils.EraseButtmark();
if (!pixels) {
return;
}
if (pixels.every((e) => e === "")) {
return;
}
PonyTownUtils.PickBrush();
let rows = element.children;
let count = 0;
for (var i = 0; i < rows.length; i++) {
let bits = rows[i].children;
for (var j = 0; j < rows.length; j++) {
if (pixels[count] !== "") {
PonyTownUtils.SetPixel(bits[j], pixels[count]);
}
count++;
}
}
return pixels;
}
},
SetupFunctions: async function(container) {
let setup = {};
let checkbox = document.evaluate('//div[text()=\'allow custom outlines\']')
.iterateNext()
.parentNode
.querySelector("CHECK-BOX");
PonyTownUtils.DefineCheckbox(setup, "CustomOutlines", checkbox);
PonyTownUtils.DefineFillOutline(setup, "BodyColors", container.querySelector('[label="Body color"]'));
setup.Horn = PonyTownUtils.DefineSet(container, "Horn");
setup.Wings = PonyTownUtils.DefineSet(container, "Wings");
setup.Ears = PonyTownUtils.DefineSet(container, "Ears");
setup.FrontHooves = PonyTownUtils.DefineSet(container, "Front hooves");
setup.BackHooves = PonyTownUtils.DefineSet(container, "Back hooves");
let io = this;
Object.defineProperty(setup, "Buttmark", {
get: function() {
return io.GetButtmark(container);
},
set: function(value) {
return io.SetButtmark(container, value);
}
});
let labels = container.querySelectorAll("label");
let flip_checkbox = [].filter.call(labels, function(element) {
return element.innerHTML.search("don't") != -1;
})[0].parentNode.querySelector("check-box");
PonyTownUtils.DefineCheckbox(setup, "FlipButtmark", flip_checkbox);
return setup;
}
},
["Mane"]: {
Tab: 1,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.Mane, tabdata.Mane);
PonyTownUtils.ImportSet(data.Backmane, tabdata.Backmane);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.Mane.Type > 0) {
exported.Mane = PonyTownUtils.ExportSet(tabdata.Mane);
}
if (tabdata.Backmane.Type > 0) {
exported.Backmane = PonyTownUtils.ExportSet(tabdata.Backmane);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.Mane = PonyTownUtils.DefineSet(container, "Mane");
setup.Backmane = PonyTownUtils.DefineSet(container, "Back mane");
return setup;
}
},
["Tail"]: {
Tab: 2,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.Tail, tabdata.Tail);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.Tail.Type > 0) {
exported.Tail = PonyTownUtils.ExportSet(tabdata.Tail);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.Tail = PonyTownUtils.DefineSet(container, "Tail");
return setup;
}
},
["Face"]: {
Tab: 3,
Container: null,
Import: async function(data, tabdata) {
tabdata.EyeColor.Value = data.EyeColor || "000000";
tabdata.EyeColorLeft.Value = data.EyeColorLeft || null;
tabdata.EyeWhitesColor.Value = data.EyeWhitesColor || "ffffff";
let right = data.Eyes || 0;
let left = typeof(data.LeftEye) == "number" ? data.LeftEye : null;
this.SetEyes([right, left]);
tabdata.Eyeshadow.Value = data.Eyeshadow || null;
tabdata.Eyelashes.Value = data.Eyelashes || 0;
tabdata.Expression.Value = data.Expression || 0;
tabdata.Fangs.Value = data.Fangs || 0;
if (data.Markings) {
tabdata.Markings.Value = data.Markings || 0;
tabdata.MarkingsColor.Value = data.MarkingsColor || "FFFFFF";
} else {
tabdata.Markings.Value = 0;
}
PonyTownUtils.ImportSet(data.FacialHair, tabdata.FacialHair);
PonyTownUtils.ImportSet(data.Muzzle, tabdata.Muzzle);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.EyeColor.Value !== "000000") {
exported.EyeColor = tabdata.EyeColor.Value;
}
if (tabdata.EyeColorLeft.Enabled) {
exported.EyeColorLeft = tabdata.EyeColorLeft.Value;
}
if (tabdata.EyeWhitesColor.Value !== "ffffff") {
exported.EyeWhitesColor = tabdata.EyeWhitesColor.Value;
}
let [right, left] = this.GetEyes();
if (right !== 0) {
exported.Eyes = right;
}
if (typeof(left) == "number") {
exported.LeftEye = left;
}
if (tabdata.Eyeshadow.Enabled) {
exported.Eyeshadow = tabdata.Eyeshadow.Value;
}
if (tabdata.Eyelashes.Value > 0) {
exported.Eyelashes = tabdata.Eyelashes.Value;
}
exported.Muzzle = PonyTownUtils.ExportSet(tabdata.Muzzle);
if (tabdata.Expression.Value > 0) {
exported.Expression = tabdata.Expression.Value;
}
if (tabdata.Fangs.Value > 0) {
exported.Fangs = tabdata.Fangs.Value;
}
if (tabdata.Markings.Value > 0) {
exported.Markings = tabdata.Markings.Value;
exported.MarkingsColor = tabdata.MarkingsColor.Value;
}
if (tabdata.FacialHair.Type > 0) {
exported.FacialHair = PonyTownUtils.ExportSet(tabdata.FacialHair);
}
return exported;
},
GetEyeSelectors: function() {
let right = PonyTownUtils.LookupFormGroupByName(this.Container, "Eyes");
if (right) {
return [PonyTownUtils.FormGroup_DefineSpriteSelection(right), null];
} else {
right = PonyTownUtils.LookupFormGroupByName(this.Container, "Right eye");
let left = PonyTownUtils.LookupFormGroupByName(this.Container, "Left eye");
right = right ? PonyTownUtils.FormGroup_DefineSpriteSelection(right) : null;
left = left ? PonyTownUtils.FormGroup_DefineSpriteSelection(left) : null;
return [right, left];
}
},
SetEyes: async function(values) {
let right = values[0] || 0;
let left = values[1] || null;
let [right_s, left_s] = this.GetEyeSelectors();
if (left !== null) {
right_s.Checked = false;
[right_s, left_s] = this.GetEyeSelectors();
left_s.Type = left;
} else {
right_s.Checked = true;
}
right_s.Type = right;
},
GetEyes: function() {
let [right_s, left_s] = this.GetEyeSelectors();
let right = right_s ? right_s.Value : 0;
let left = left_s ? left_s.Value : null;
return [right, left];
},
SetupFunctions: async function(container) {
let setup = {};
this.Container = container;
setup.EyeColor = PonyTownUtils.FormGroup_DefineColorPicker(PonyTownUtils.LookupFormGroupByName(container, "Eye color"));
setup.EyeColorLeft = PonyTownUtils.FormGroup_DefineColorPicker(PonyTownUtils.LookupFormGroupByName(container, "Eye color (left)"));
setup.EyeWhitesColor = PonyTownUtils.FormGroup_DefineColorPicker(PonyTownUtils.LookupFormGroupByName(container, "Eye whites color"));
setup.SetEyes = (values) => {
return this.SetEyes(values);
}
setup.GetEyes = () => {
return this.GetEyes;
}
setup.Eyeshadow = PonyTownUtils.FormGroup_DefineColorPicker(PonyTownUtils.LookupFormGroupByName(container, "Eyeshadow"));
setup.Eyelashes = PonyTownUtils.FormGroup_DefineSpriteSelection(PonyTownUtils.LookupFormGroupByName(container, "Eyelashes"));
setup.Expression = PonyTownUtils.FormGroup_DefineSpriteSelection(PonyTownUtils.LookupFormGroupByName(container, "Expression"));
setup.Fangs = PonyTownUtils.FormGroup_DefineSpriteSelection(PonyTownUtils.LookupFormGroupByName(container, "Fangs"));
setup.Markings = PonyTownUtils.FormGroup_DefineSpriteSelection(PonyTownUtils.LookupFormGroupByName(container, "Markings"));
setup.MarkingsColor = PonyTownUtils.FormGroup_DefineColorPicker(PonyTownUtils.LookupFormGroupByName(container, "Markings color"));
setup.Muzzle = PonyTownUtils.DefineSet(container, "Muzzle");
setup.FacialHair = PonyTownUtils.DefineSet(container, "Facial hair");
return setup;
}
},
["Other"]: {
Tab: 4,
TabFunctions: {
["Head"]: {
Tab: 0,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.HeadAccessories, tabdata.HeadAccessories);
PonyTownUtils.ImportSet(data.EarAccessories, tabdata.EarAccessories);
PonyTownUtils.ImportSet(data.FaceAccessories, tabdata.FaceAccessories);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.HeadAccessories.Type > 0) {
exported.HeadAccessories = PonyTownUtils.ExportSet(tabdata.HeadAccessories);
}
if (tabdata.EarAccessories.Type > 0) {
exported.EarAccessories = PonyTownUtils.ExportSet(tabdata.EarAccessories);
}
if (tabdata.FaceAccessories.Type > 0) {
exported.FaceAccessories = PonyTownUtils.ExportSet(tabdata.FaceAccessories);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.HeadAccessories = PonyTownUtils.DefineSet(container, "Head accessories");
setup.EarAccessories = PonyTownUtils.DefineSet(container, "Ear accessories");
setup.FaceAccessories = PonyTownUtils.DefineSet(container, "Face accessories");
return setup;
}
},
["Neck"]: {
Tab: 1,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.NeckAccessories, tabdata.NeckAccessories);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.NeckAccessories.Type > 0) {
exported.NeckAccessories = PonyTownUtils.ExportSet(tabdata.NeckAccessories);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.NeckAccessories = PonyTownUtils.DefineSet(container, "Neck accessories");
return setup;
}
},
["Legs"]: {
Tab: 2,
Import: async function(data, tabdata) {
let same_legs = (data.SameBackLegs == false) ? false : true;
await tabdata.SetSameBackLegs(same_legs);
PonyTownUtils.ImportSet(data.FrontLegAccessories, tabdata.FrontLegAccessories);
if (!same_legs) {
PonyTownUtils.ImportSet(data.BackLegAccessories, tabdata.BackLegAccessories);
}
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.FrontLegAccessories.Type > 0) {
exported.FrontLegAccessories = PonyTownUtils.ExportSet(tabdata.FrontLegAccessories);
}
if (!tabdata.GetSameBackLegs()) {
exported.SameBackLegs = false;
}
if (!tabdata.GetSameBackLegs()) {
if (tabdata.BackLegAccessories.Type > 0) {
exported.BackLegAccessories = PonyTownUtils.ExportSet(tabdata.BackLegAccessories);
}
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.FrontLegAccessories = PonyTownUtils.DefineSet(container, "Front leg accessories");
let same_back_legs = container.querySelector("div > div > div > check-box");
PonyTownUtils.DefineCheckbox(setup, "SameBackLegs", same_back_legs);
setup.SetSameBackLegs = (value) => {
PonyTownUtils.SetCheckbox(same_back_legs, value);
return new Promise(function(resolve) {
resolve();
}).then(() => {
if (!value) {
setup.BackLegAccessories = PonyTownUtils.DefineSet(container, "Back leg accessories");
} else {
setup.BackLegAccessories = null;
}
});
};
setup.GetSameBackLegs = () => {
return PonyTownUtils.IsCheckboxChecked(same_back_legs);
};
if (!PonyTownUtils.IsCheckboxChecked(same_back_legs)) {
setup.BackLegAccessories = PonyTownUtils.DefineSet(container, "Back leg accessories");
}
return setup;
}
},
["Chest"]: {
Container: null,
Tab: 3,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.ChestAccessories, tabdata.ChestAccessories);
// I know.
if (tabdata.ChestAccessories.Type > 1) {
let sleeves = PonyTownUtils.DefineSet(this.Container, "Sleeves");
PonyTownUtils.ImportSet(data.Sleeves, sleeves);
}
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.ChestAccessories.Type > 0) {
exported.ChestAccessories = PonyTownUtils.ExportSet(tabdata.ChestAccessories);
if (tabdata.ChestAccessories.Type > 1) {
exported.Sleeves = PonyTownUtils.ExportSet(tabdata.Sleeves);
}
}
return exported;
},
SetupFunctions: async function(container) {
this.Container = container;
let setup = {};
setup.ChestAccessories = PonyTownUtils.DefineSet(container, "Chest accessories");
setup.Sleeves = PonyTownUtils.DefineSet(container, "Sleeves");
return setup;
}
},
["Back"]: {
Tab: 4,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.BackAccessories, tabdata.BackAccessories);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.BackAccessories.Type > 0) {
exported.BackAccessories = PonyTownUtils.ExportSet(tabdata.BackAccessories);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.BackAccessories = PonyTownUtils.DefineSet(container, "Back accessories");
return setup;
}
},
["Waist"]: {
Tab: 5,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.WaistAccessories, tabdata.WaistAccessories);
},
Export: async function(tabdata) {
let exported = {};
if (tabdata.WaistAccessories.Type > 0) {
exported.WaistAccessories = PonyTownUtils.ExportSet(tabdata.WaistAccessories);
}
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.WaistAccessories = PonyTownUtils.DefineSet(container, "Waist accessories");
return setup;
}
},
["Other"]: {
Tab: 6,
Import: async function(data, tabdata) {
PonyTownUtils.ImportSet(data.ExtraAccessories, tabdata.ExtraAccessories);
},
Export: async function(tabdata) {
let exported = {};
exported.ExtraAccessories = PonyTownUtils.ExportSet(tabdata.ExtraAccessories);
return exported;
},
SetupFunctions: async function(container) {
let setup = {};
setup.ExtraAccessories = PonyTownUtils.DefineSet(container, "Extra accessories");
return setup;
}
}
},
Import: async function(data, tabdata) {
let exported = {};
for (let i in this.TabFunctions) {
let v = this.TabFunctions[i];
debug("> Importing tab #" + i + " (" + i + ")...");
let localdata = data[i] || {};
await PonyTownUtils.CharacterEditor.SetAccessoryTab(v.Tab);
let _tabdata = await Character.SetupFunctions();
await v.Import(localdata, _tabdata);
}
return exported;
},
Export: async function(tabdata) {
let data = {};
for (var i in this.TabFunctions) {
let v = this.TabFunctions[i];
debug("> Exporting tab #" + i + " (" + i + ")...");
await PonyTownUtils.CharacterEditor.SetAccessoryTab(v.Tab);
let _tabdata = await Character.SetupFunctions();
let exported = await v.Export(_tabdata);
Object.keys(exported).forEach((key) => (exported[key] == null || exported[key] == undefined) && delete exported[key]);
if (Object.keys(exported).length > 0) {
data[i] = exported;
}
}
return data;
},
SetupFunctions: async function(container) {
let current_tab = PonyTownUtils.CharacterEditor.GetAccessoryTab();
for (let i in this.TabFunctions) {
let v = this.TabFunctions[i];
if (v.Tab === current_tab) {
let _container = container.querySelector("div.active.tab-pane");
return await v.SetupFunctions(_container);
}
}
}
}
};
var Character = {
SetupFunctions: async function() {
let tab = PonyTownUtils.CharacterEditor.GetTab();
for (let i in TabFunctions) {
let v = TabFunctions[i];
if (v.Tab === tab) {
let container = document.querySelector("tabset > div > div.active.tab-pane");
return this.TabData = await v.SetupFunctions(container);
}
}
this.TabData = null;
},
Export: async function() {
let data = {};
data.Nickname = PonyTownUtils.CharacterEditor.GetCharacterName();
for (var i in TabFunctions) {
let v = TabFunctions[i];
debug("Exporting tab #" + i + " (" + i + ")...");
await PonyTownUtils.CharacterEditor.SetTab(v.Tab);
let exported = await v.Export(await this.SetupFunctions());
Object.keys(exported).forEach((key) => (exported[key] == null || exported[key] == undefined) && delete exported[key]);
if (Object.keys(exported).length > 0) {
data[i] = exported;
}
}
await PonyTownUtils.CharacterEditor.SetTab(0);
return data;
},
Import: async function(data) {
if (typeof(data) == "string") {
data = JSON.parse(data);
}
data.Body = data.Body || {};
await PonyTownUtils.CharacterEditor.SetTab(0);
(await this.SetupFunctions()).CustomOutlines = data.Body.OutlinesEnabled || false;
for (var i in TabFunctions) {
let v = TabFunctions[i];
debug("Importing tab #" + i + " (" + i + ")...");
let localdata = data[i] || {};
await PonyTownUtils.CharacterEditor.SetTab(v.Tab);
await v.Import(localdata, await this.SetupFunctions());
}
if (data.Nickname) {
PonyTownUtils.CharacterEditor.SetCharacterName(data.Nickname);
}
await PonyTownUtils.CharacterEditor.SetTab(0);
},
ExportAll: async function() {
var zip = new JSZip();
var used_filenames = [];
try {
let list = await PonyTownUtils.CharacterEditor.GetCharacterList();
if (list) {
let unknown_count = 0;
for (let i = 0; i < list.length; i++) {
await PonyTownUtils.CharacterEditor.SelectCharacter(i);
let data = JSON.stringify(await Character.Export());
let name,
used_count = 0;
do {
let used_suffix = "";
if (used_count > 0) {
used_suffix = "." + used_count;
}
name = (list[i] || "unknown-" + (++unknown_count)).replace(/[^a-z0-9]/gi, '_').toLowerCase() + used_suffix;
used_count++;
} while (used_filenames.includes(name));
used_filenames.push(name);
zip.file(name + ".pt.json", data);
}
zip.generateAsync({
type: "blob"
})
.then(function(content) {
saveAs(content, "characters.zip");
});
}
} catch (err) {
throw err;
}
}
};
var ProgressForm = (function() {
function form() {
this.style.display = 'table-cell';
this.innerHTML = `
`;
};
form.prototype.Close = function() {
};
})();
var ImportForm = (function() {
var html = Resources["import-frame"],
import_btn,
form;
function form(overlay) {
form = this;
this.container = document.createElement("div");
overlay.append(this.container);
this.container.innerHTML = html;
this.container.classList.add("nmw-form");
let textarea = this.container.querySelector("textarea");
textarea.onkeypress = function(ev) {
if (ev.keyCode == 10 || (ev.ctrlKey && ev.keyCode == 13)) {
form.Import(textarea.value);
}
};
let button = this.container.querySelector("[id='nmw-button-close']");
button.onclick = function() {
form.Close();
};
let import_button = this.container.querySelector("[id='nmw-button-import']");
import_button.onclick = function() {
if (textarea.value)
form.Import(textarea.value);
else {
form.ImportFail("Input is empty! •`c´•");
}
};
import_btn = import_button;
let fileinput = this.container.querySelector("input");
fileinput.onchange = function() {
let file = fileinput.files[0];
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function(evt) {
if (evt.target.result)
form.Import(evt.target.result, true);
}
}
}
textarea.select();
}
let timer_handle;
form.prototype.ImportFail = function(msg) {
msg = msg || "Couldn't import ´• c •`";
let span = import_btn.querySelector("span");
span.innerHTML = msg;
if (!span.classList.contains("nmw-span-dim"))
span.classList.add("nmw-span-dim");
clearTimeout(timer_handle);
timer_handle = setTimeout(function() {
if (span) {
import_btn.querySelector("span").innerHTML = "Import";
span.classList.remove("nmw-span-dim");
}
}, 3500);
}
form.prototype.Import = async function(data, force_close) {
try {
await Character.Import(data);
// Let it close if import was successful.
force_close = true;
} catch (err) {
form.ImportFail();
throw err;
} finally {
if (force_close)
this.Close();
}
}
form.prototype.Close = function() {
this.container.remove();
}
return form;
})();
var ExportForm = (function() {
var html = Resources["export-frame"];
function form(overlay, data) {
var form = this;
this.container = document.createElement("div");
overlay.append(this.container);
this.container.innerHTML = html;
this.container.classList.add("nmw-form");
let textarea = this.container.querySelector("textarea");
textarea.value = data;
let button = this.container.querySelector("[id='nmw-button-close']");
button.onclick = function() {
form.Close();
}
let copy_button = this.container.querySelector("[id='nmw-button-copy']");
let cpb = new Clipboard(copy_button, {
text: function(trigger) {
return textarea.value;
}
});
let timer_handle;
cpb.on("success", function(e) {
let span = copy_button.querySelector("span");
span.innerHTML = "Copied!";
if (!span.classList.contains("nmw-span-dim"))
span.classList.add("nmw-span-dim");
clearTimeout(timer_handle);
timer_handle = setTimeout(function() {
if (span) {
copy_button.querySelector("span").innerHTML = "Copy to clipboard";
span.classList.remove("nmw-span-dim");
}
}, 3500);
});
let dl = this.container.querySelector("[id='nmw-button-download']");
dl.onclick = function() {
let name = document.querySelector("character-select > div > input");
name = (name ? name.value : "character") + ".pt.json";
var blob = new Blob([textarea.value], {
type: "application/json"
});
saveAs(blob, name);
}
}
form.prototype.Close = function() {
this.container.remove();
}
return form;
})();
var EOLForm = (function() {
var html = Resources["eol-frame"];
function form(overlay, data) {
var form = this;
this.container = document.createElement("div");
overlay.append(this.container);
this.container.innerHTML = html;
this.container.classList.add("nmw-form");
let button = this.container.querySelector("[id='nmw-button-close']");
button.onclick = function() {
form.Close();
}
}
form.prototype.Close = function() {
this.container.remove();
let setvalue = GM && GM.setValue || GM_setValue;
setvalue("EOL-Shown", true);
}
return form;
})();
var UI = {
Overlay: null,
InjectHTML: function() {
if (!this.Overlay) {
let body = document.querySelector("body");
let e = this.Overlay = document.createElement("div");
e.classList.add("nmw-overlay");
body.appendChild(e);
}
},
ShowImport: function() {
this.InjectHTML();
let form = new ImportForm(this.Overlay);
},
ShowEOL: function() {
this.InjectHTML();
let form = new EOLForm(this.Overlay);
},
ShowExport: async function() {
this.InjectHTML();
try {
let data = JSON.stringify(await Character.Export());
let form = new ExportForm(this.Overlay, data);
} catch (err) {
throw err;
}
}
}
// --
//
// Injection.
//
// --
var InjectControls = function(el) {
let preview = el.querySelector(".character-preview-box > character-preview").parentNode;
let controls = document.createElement("div");
controls.classList.add("nmw-char-preview-controls");
controls.setAttribute("nmw", "");
preview.append(controls);
let import_btn = document.createElement("button");
import_btn.classList.add("btn");
import_btn.classList.add("btn-default");
import_btn.innerHTML = '<i class="fas mr-1 fa-cloud-upload"></i>Import';
controls.appendChild(import_btn);
let export_btn = document.createElement("button");
export_btn.classList.add("btn");
export_btn.classList.add("btn-default");
export_btn.classList.add("ml-1");
export_btn.innerHTML = '<i class="fas mr-1 fa-cloud-download"></i>Export';
controls.appendChild(export_btn);
import_btn.onclick = function() {
UI.ShowImport();
};
export_btn.onclick = function() {
UI.ShowExport();
};
};
// Set observer.
var observer = new MutationObserver(function(mutations) {
let controls_injected = false;
let overlay_changed = false;
for (var i = 0; i < mutations.length; i++) {
let element = mutations[i].target;
if (!overlay_changed && element.classList.contains("nmw-overlay")) {
overlay_changed = true;
let body = document.querySelector("body");
if (element.childNodes.length > 0) {
body.style.overflow = "hidden";
} else {
body.style.overflow = "";
}
}
if (!controls_injected && mutations[i].removedNodes.length === 0 && element.tagName == "CHARACTER") {
if (!element.querySelector('[nmw]')) {
InjectControls(element);
}
controls_injected = true;
let getvalue = GM && GM.getValue || GM_getValue;
(async() => {
if (!await getvalue("EOL-Shown", false)) {
UI.ShowEOL();
}
})();
}
}
});
observer.observe(observer_target.parentNode, {
childList: true,
subtree: true,
attributes: true
});
if (unsafeWindow) {
unsafeWindow.NMW = unsafeWindow.NMW || {};
unsafeWindow.NMW.PonyTownUtils = PonyTownUtils;
unsafeWindow.NMW.Character = Character;
}
})();