diff --git a/.eslintrc.js b/.eslintrc.js
index 8f09ca77e..9b598971f 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -33,7 +33,8 @@ module.exports = {
"Popup": false, "ForfeitPopup": false, "BracketPopup": false, "LoginPasswordPopup": false, "UserPopup": false, "TeamPopup": false,
"AvatarsPopup": false, "BattleListPopup": false, "CreditsPopup": false, "FormatPopup": false, "FormattingPopup": false, "LoginPopup": false,
"MovePopup": false, "SoundsPopup": false, "OptionsPopup": false, "PromptPopup": false, "ProxyPopup": false, "ReconnectPopup": false,
- "RegisterPopup": false, "ReplayUploadedPopup": false, "RulesPopup": false, "TabListPopup": false, "TournamentBox": false
+ "RegisterPopup": false, "ReplayUploadedPopup": false, "RulesPopup": false, "TabListPopup": false, "TournamentBox": false,
+ "CustomBackgroundPopup": false
},
"rules": {
"comma-dangle": [2, "never"],
diff --git a/js/battledata.js b/js/battledata.js
index dc89aaccb..328269739 100644
--- a/js/battledata.js
+++ b/js/battledata.js
@@ -334,6 +334,10 @@ var Tools = {
tracker.callbacks[i][0].call(tracker.callbacks[i][1], value);
}
};
+ tracker.unload = function () {
+ if (!tracker.isLoaded) return;
+ tracker.isLoaded = false;
+ };
return tracker;
},
diff --git a/js/client-mainmenu.js b/js/client-mainmenu.js
index 326e0cdb6..d9dfe3989 100644
--- a/js/client-mainmenu.js
+++ b/js/client-mainmenu.js
@@ -42,11 +42,10 @@
}
buf += '
';
+ buf += '
';
- buf += '
' : '');
+ buf += '
' : '');
var folderTable = {};
var folders = [];
if (Storage.teams) for (var i = -2; i < Storage.teams.length; i++) {
+ if (i >= 0) {
+ var folder = Storage.teams[i].folder;
+ if (folder && !((folder + '/') in folderTable)) {
+ folders.push('Z' + folder);
+ folderTable[folder + '/'] = 1;
+ if (!('/' in folderTable)) {
+ folders.push('Z~');
+ folderTable['/'] = 1;
+ }
+ }
+ }
+
var format;
if (i === -2) {
- format = this.curFormatKeep;
+ format = this.curFolderKeep;
} else if (i === -1) {
- format = this.curFormat;
+ format = this.curFolder;
} else {
format = Storage.teams[i].format;
if (!format) format = 'gen6';
@@ -185,36 +206,66 @@
if (!format) continue;
if (format in folderTable) continue;
folderTable[format] = 1;
+ if (format.slice(-1) === '/') {
+ folders.push('Z' + (format.slice(0, -1) || '~'));
+ if (!('/' in folderTable)) {
+ folders.push('Z~');
+ folderTable['/'] = 1;
+ }
+ continue;
+ }
if (format === 'gen6') {
folders.push('A~');
continue;
}
switch (format.slice(0, 4)) {
- case 'gen1': format = 'Z' + format.slice(4); break;
- case 'gen2': format = 'X' + format.slice(4); break;
- case 'gen3': format = 'Y' + format.slice(4); break;
- case 'gen4': format = 'W' + format.slice(4); break;
- case 'gen5': format = 'V' + format.slice(4); break;
+ case 'gen1': format = 'F' + format.slice(4); break;
+ case 'gen2': format = 'E' + format.slice(4); break;
+ case 'gen3': format = 'D' + format.slice(4); break;
+ case 'gen4': format = 'C' + format.slice(4); break;
+ case 'gen5': format = 'B' + format.slice(4); break;
default: format = 'A' + format; break;
}
folders.push(format);
}
folders.sort();
var gen = '';
+ var formatFolderBuf = '
';
+ formatFolderBuf += '
';
for (var i = 0; i < folders.length; i++) {
var format = folders[i];
var newGen;
switch (format.charAt(0)) {
- case 'Z': newGen = '1'; break;
- case 'Y': newGen = '2'; break;
- case 'X': newGen = '3'; break;
- case 'W': newGen = '4'; break;
- case 'V': newGen = '5'; break;
+ case 'F': newGen = '1'; break;
+ case 'E': newGen = '2'; break;
+ case 'D': newGen = '3'; break;
+ case 'C': newGen = '4'; break;
+ case 'B': newGen = '5'; break;
case 'A': newGen = '6'; break;
+ case 'Z': newGen = '/'; break;
}
if (gen !== newGen) {
gen = newGen;
- buf += '
Gen ' + gen + ' ';
+ if (gen === '/') {
+ buf += formatFolderBuf;
+ formatFolderBuf = '';
+ buf += '
';
+ buf += '
Folders ';
+ } else {
+ buf += '
Gen ' + gen + ' ';
+ }
+ }
+ if (gen === '/') {
+ formatName = format.slice(1);
+ format = formatName + '/';
+ if (formatName === '~') {
+ formatName = '(uncategorized)';
+ format = '/';
+ } else {
+ formatName = Tools.escapeHTML(formatName);
+ }
+ buf += '
' : '');
+ continue;
}
var formatName = format.slice(1);
if (formatName === '~') formatName = '';
@@ -226,11 +277,11 @@
if (format === 'gen6') formatName = '(uncategorized)';
// folders are
s rather than
s because in theory it has
// less weird interactions with HTML5 drag-and-drop
- buf += '' : '');
+ buf += '' : '');
}
-
- buf += '
';
- buf += '';
+ buf += formatFolderBuf;
+ buf += '
';
+ buf += '';
buf += '
';
@@ -243,27 +294,50 @@
// teampane
buf += this.clipboardHTML();
- if (!this.curFormat) {
+ var filterFormat = '';
+ var filterFolder = undefined;
+
+ if (!this.curFolder) {
+ buf += '
Hi ';
+ buf += '
Did you have a good day?
';
+ buf += '
Yes, my day was pretty good No, it wasn\'t great
';
buf += '
All teams ';
} else {
- buf += '
' + this.curFormat + ' ';
+ if (this.curFolder.slice(-1) === '/') {
+ filterFolder = this.curFolder.slice(0, -1);
+ if (filterFolder) {
+ buf += '
' + filterFolder + ' Rename';
+ } else {
+ buf += '
Teams not in any folders';
+ }
+ } else {
+ filterFormat = this.curFolder;
+ buf += '
' + filterFormat + '';
+ }
}
+ var newButtonText = "New Team";
+ if (filterFolder) newButtonText = "New Team in folder";
+ if (filterFormat && filterFormat !== 'gen6') {
+ newButtonText = "New " + Tools.escapeFormat(filterFormat) + " Team";
+ }
+ buf += '
' + newButtonText + '
';
+
+ buf += '
';
+ var atLeastOne = false;
+
if (!window.localStorage && !window.nodewebkit) buf += '== CAN\'T SAVE ==Your browser doesn\'t support localStorage and can\'t save teams! Update to a newer browser. ';
if (Storage.cantSave) buf += '== CAN\'T SAVE ==You hit your browser\'s limit for team storage! Please backup them and delete some of them. Your teams won\'t be saved until you\'re under the limit again. ';
if (!teams.length) {
if (this.deletedTeamLoc >= 0) {
- buf += '';
+ buf += ' Undo Delete ';
}
- buf += 'you don\'t have any teams lol
';
+ buf += 'you don\'t have any teams lol
';
} else {
- var atLeastOne = false;
+
for (var i = 0; i < teams.length + 1; i++) {
if (i === this.deletedTeamLoc) {
- if (!atLeastOne) {
- buf += ' New' + (this.curFormat && this.curFormat !== 'gen6' ? ' ' + this.curFormat : '') + ' team
';
- atLeastOne = true;
- }
+ if (!atLeastOne) atLeastOne = true;
buf += ' Undo Delete ';
}
if (i >= teams.length) break;
@@ -281,16 +355,15 @@
continue;
}
- if (this.curFormat && this.curFormat !== (team.format || 'gen6')) continue;
+ if (filterFormat && filterFormat !== (team.format || 'gen6')) continue;
+ if (filterFolder !== undefined && filterFolder !== team.folder) continue;
- if (!atLeastOne) {
- buf += ' New' + (this.curFormat && this.curFormat !== 'gen6' ? ' ' + this.curFormat : '') + ' team
';
- atLeastOne = true;
- }
+ if (!atLeastOne) atLeastOne = true;
var formatText = '';
if (team.format) {
formatText = '[' + team.format + '] ';
}
+ if (team.folder) formatText += team.folder + '/';
// teams are s rather than s because Firefox doesn't
// support dragging and dropping buttons.
@@ -299,24 +372,66 @@
buf += '
Edit Delete ';
}
if (!atLeastOne) {
- buf += '';
}
- buf += ' New' + (this.curFormat && this.curFormat !== 'gen6' ? ' ' + this.curFormat : '') + ' team
';
+
+ buf += ' ';
+ if (atLeastOne) {
+ buf += ' ' + newButtonText + '
';
+ }
if (window.nodewebkit) {
buf += ' Reveal teams folder Reload teams files Backup/Restore all teams ';
- } else {
+ } else if (atLeastOne) {
buf += 'Clearing your cookies (specifically, localStorage) will delete your teams.
';
buf += ' Backup/Restore all teams ';
buf += 'If you want to clear your cookies or localStorage, you can use the Backup/Restore feature to save your teams as text first.
';
+ } else {
+ buf += ' Restore teams from backup ';
}
var $pane = this.$('.teampane');
$pane.html(buf);
if (resetScroll) $pane.scrollTop(0);
},
+ greeting: function (answer, button) {
+ var buf = '' + $(button).html() + '
';
+ if (answer === 'N') {
+ buf += 'Aww, that\'s too bad. :( I hope playing on Pokémon Showdown today can help cheer you up!
';
+ } else if (answer === 'Y') {
+ buf += 'Cool! I just added some pretty cool teambuilder features, so I\'m pretty happy, too. Did you know you can drag and drop teams to different format-folders? You can also drag and drop them to and from your computer (works best in Chrome).
';
+ buf += ' Wait, who are you? Talking to a teambuilder is weird.
';
+ } else if (answer === 'W') {
+ buf += 'Oh, I\'m Zarel! I made a Credits button for this...
';
+ buf += '';
+ buf += 'Isn\'t it pretty? Matches your background and everything. It used to be in the Main Menu but we had to get rid of it to save space.
';
+ buf += 'Speaking of, you should try changing your background .';
+ buf += '
You might be having too much fun with these buttons and icons
';
+ } else if (answer === 'B') {
+ buf += 'I paid good money for those icons! I need to get my money\'s worth!
';
+ buf += ' Wait, really?
';
+ } else if (answer === 'WR') {
+ buf += 'No, they were free. That just makes it easier to get my money\'s worth. Let\'s play rock paper scissors!
';
+ buf += ' Rock Paper Scissors Lizard Spock
';
+ } else if (answer[0] === 'R') {
+ buf += 'I play laser, I win.
';
+ buf += ' You can\'t do that!
';
+ } else if (answer === 'YC') {
+ buf += 'Okay, then I play peace sign , everyone signs a peace treaty, ending the war and ushering in a new era of prosperity.
';
+ }
+ $(button).parent().replaceWith(buf);
+ },
+ credits: function () {
+ app.addPopup(CreditsPopup);
+ },
+ background: function () {
+ app.addPopup(CustomBackgroundPopup);
+ },
selectFolder: function (format) {
if (format && format.currentTarget) {
var e = format;
@@ -330,13 +445,53 @@
}});
return;
}
+ if (format === '++') {
+ e.stopImmediatePropagation();
+ var self = this;
+ // app.addPopupPrompt("Folder name:", "Create folder", function (newFormat) {
+ // self.selectFolder(newFormat + '/');
+ // });
+ app.addPopup(PromptPopup, {message: "Folder name:", button: "Create folder", sourceEl: e.currentTarget, callback: function (name) {
+ name = $.trim(name);
+ if (name.indexOf('/') >= 0 || name.indexOf('\\') >= 0) {
+ app.addPopupMessage("Names can't contain slashes, since they're used as a folder separator.");
+ name = name.replace(/[\\\/]/g, '');
+ }
+ if (!name) return;
+ self.selectFolder(name + '/');
+ }});
+ return;
+ }
} else {
- this.curFormatKeep = format;
+ this.curFolderKeep = format;
}
- this.curFormat = (format === 'all' ? '' : format);
+ this.curFolder = (format === 'all' ? '' : format);
this.updateFolderList();
this.updateTeamList(true);
},
+ renameFolder: function () {
+ if (!this.curFolder) return;
+ if (this.curFolder.slice(-1) !== '/') return;
+ var oldFolder = this.curFolder.slice(0, -1);
+ var self = this;
+ app.addPopup(PromptPopup, {message: "Folder name:", button: "Rename folder", value: oldFolder, callback: function (name) {
+ name = $.trim(name);
+ if (name.indexOf('/') >= 0 || name.indexOf('\\') >= 0) {
+ app.addPopupMessage("Names can't contain slashes, since they're used as a folder separator.");
+ name = name.replace(/[\\\/]/g, '');
+ }
+ if (!name) return;
+ if (name === oldFolder) return;
+ for (var i = 0; i < Storage.teams.length; i++) {
+ var team = Storage.teams[i];
+ if (team.folder !== oldFolder) continue;
+ team.folder = name;
+ if (window.nodewebkit) Storage.saveTeam(team);
+ }
+ if (!window.nodewebkit) Storage.saveTeam(team);
+ self.selectFolder(name + '/');
+ }});
+ },
show: function () {
Room.prototype.show.apply(this, arguments);
var $teamwrapper = this.$('.teamwrapper');
@@ -410,6 +565,7 @@
}
},
saveBackup: function () {
+ Storage.deleteAllTeams();
Storage.importTeam(this.$('.teamedit textarea').val(), true);
teams = Storage.teams;
Storage.saveAllTeams();
@@ -422,20 +578,34 @@
this.back();
},
"new": function () {
+ var format = this.curFolder;
+ var folder = '';
+ if (format && format.charAt(format.length - 1) === '/') {
+ folder = format.slice(0, -1);
+ format = '';
+ }
var newTeam = {
name: 'Untitled ' + (teams.length + 1),
- format: (this.curFormat || ''),
+ format: format,
team: '',
+ folder: folder,
iconCache: ''
};
teams.push(newTeam);
this.edit(teams.length - 1);
},
newTop: function () {
+ var format = this.curFolder;
+ var folder = '';
+ if (format && format.charAt(format.length - 1) === '/') {
+ folder = format.slice(0, -1);
+ format = '';
+ }
var newTeam = {
name: 'Untitled ' + (teams.length + 1),
- format: (this.curFormat || ''),
+ format: format,
team: '',
+ folder: folder,
iconCache: ''
};
teams.unshift(newTeam);
@@ -546,7 +716,11 @@
if (app.draggingFolder) {
var format = app.draggingFolder.dataset.value;
app.draggingFolder = null;
- team.format = format;
+ if (format.slice(-1) === '/') {
+ team.folder = format.slice(0, -1);
+ } else {
+ team.format = format;
+ }
this.selectFolder(format);
edited = true;
} else {
@@ -554,7 +728,7 @@
}
if (edited) {
- Storage.saveTeams();
+ Storage.saveTeam(team);
app.user.trigger('saveteams');
}
@@ -621,7 +795,7 @@
return;
}
var format = e.currentTarget.dataset.value;
- if (format === '+' || format === 'all' || format === this.curFormat) {
+ if (format === '+' || format === '++' || format === 'all' || format === this.curFolder) {
return;
}
if (parseInt(app.dragging.dataset.value, 10) >= Storage.teams.length) {
@@ -691,6 +865,7 @@
name: name,
format: format,
team: team,
+ folder: '',
iconCache: ''
});
self.finishDrop();
@@ -890,8 +1065,13 @@
app.send('/vtm ' + format);
},
teamNameChange: function (e) {
- this.curTeam.name = ($.trim(e.currentTarget.value) || 'Untitled ' + (this.curTeamLoc + 1));
- e.currentTarget.value = this.curTeam.name;
+ var name = ($.trim(e.currentTarget.value) || 'Untitled ' + (this.curTeamLoc + 1));
+ if (name.indexOf('/') >= 0 || name.indexOf('\\') >= 0) {
+ app.addPopupMessage("Names can't contain slashes, since they're used as a folder separator.");
+ name = name.replace(/[\\\/]/g, '');
+ }
+ this.curTeam.name = name;
+ e.currentTarget.value = name;
this.save();
},
format: function (format, button) {
@@ -912,9 +1092,9 @@
},
nicknameChange: function (e) {
var i = +$(e.currentTarget).closest('li').attr('value');
- var team = this.curSetList[i];
- var name = $.trim(e.currentTarget.value) || team.species;
- e.currentTarget.value = team.name = name;
+ var set = this.curSetList[i];
+ var name = $.trim(e.currentTarget.value) || set.species;
+ e.currentTarget.value = set.name = name;
this.save();
},
diff --git a/js/client.js b/js/client.js
index dc76b200f..6b231dca4 100644
--- a/js/client.js
+++ b/js/client.js
@@ -2229,14 +2229,13 @@
});
var PromptPopup = this.PromptPopup = Popup.extend({
- type: 'semimodal',
initialize: function (data) {
if (!data || !data.message || typeof data.callback !== "function") return;
this.callback = data.callback;
var buf = ' ';
diff --git a/js/storage.js b/js/storage.js
index 9d45682f8..2ce1629fa 100644
--- a/js/storage.js
+++ b/js/storage.js
@@ -114,12 +114,12 @@ Storage.bg = {
loadHues: function (hues) {
$('#mainmenubuttoncolors').remove();
var cssBuf = '';
- for (var i = 0; i < 6; i++) {
+ for (var i = 0; i < 5; i++) {
var n = i + 1;
var hs = hues[i];
- cssBuf += '.mainmenuwrapper .button.mainmenu' + n + ' { background: linear-gradient(to bottom, hsl(' + hs + ',72%), hsl(' + hs + ',52%)); border-color: hsl(' + hs + ',40%); }\n';
- cssBuf += '.mainmenuwrapper .button.mainmenu' + n + ':hover { background: linear-gradient(to bottom, hsl(' + hs + ',62%), hsl(' + hs + ',42%)); border-color: hsl(' + hs + ',21%); }\n';
- cssBuf += '.mainmenuwrapper .button.mainmenu' + n + ':active { background: linear-gradient(to bottom, hsl(' + hs + ',42%), hsl(' + hs + ',58%)); border-color: hsl(' + hs + ',21%); }\n';
+ cssBuf += 'body .button.mainmenu' + n + ' { background: linear-gradient(to bottom, hsl(' + hs + ',72%), hsl(' + hs + ',52%)); border-color: hsl(' + hs + ',40%); }\n';
+ cssBuf += 'body .button.mainmenu' + n + ':hover { background: linear-gradient(to bottom, hsl(' + hs + ',62%), hsl(' + hs + ',42%)); border-color: hsl(' + hs + ',21%); }\n';
+ cssBuf += 'body .button.mainmenu' + n + ':active { background: linear-gradient(to bottom, hsl(' + hs + ',42%), hsl(' + hs + ',58%)); border-color: hsl(' + hs + ',21%); }\n';
}
$('head').append('');
},
@@ -132,13 +132,13 @@ Storage.bg = {
// or localStorage throws
try {
var colorThief = new ColorThief();
- var colors = colorThief.getPalette(img, 6);
+ var colors = colorThief.getPalette(img, 5);
var hues = [];
if (!colors) {
- hues = ['0, 0%', '0, 0%', '0, 0%', '0, 0%', '0, 0%', '0, 0%'];
+ hues = ['0, 0%', '0, 0%', '0, 0%', '0, 0%', '0, 0%'];
} else {
- for (var i = 0; i < 6; i++) {
+ for (var i = 0; i < 5; i++) {
var color = colors[i];
var hs = Storage.bg.getHueSat(color[0] / 255, color[1] / 255, color[2] / 255);
hues.unshift(hs);
@@ -179,7 +179,7 @@ try {
var bg = localStorage.getItem('showdown_bg').split('\n');
if (bg.length >= 2) {
Storage.bg.load(bg[0], bg[1]);
- if (bg.length === 8) Storage.bg.loadHues(bg.slice(2));
+ if (bg.length >= 7) Storage.bg.loadHues(bg.slice(2));
}
} catch (e) {}
@@ -473,6 +473,8 @@ Storage.saveAllTeams = function () {
this.saveTeams();
};
+Storage.deleteAllTeams = function () {};
+
/*********************************************************
* Team importing and exporting
*********************************************************/
@@ -487,6 +489,7 @@ Storage.unpackAllTeams = function (buffer) {
name: oldTeam.name || '',
format: oldTeam.format || '',
team: Storage.packTeam(oldTeam.team),
+ folder: '',
iconCache: ''
};
});
@@ -497,10 +500,13 @@ Storage.unpackAllTeams = function (buffer) {
if (pipeIndex < 0) return;
var bracketIndex = line.indexOf(']');
if (bracketIndex > pipeIndex) bracketIndex = -1;
+ var slashIndex = line.lastIndexOf('/', pipeIndex);
+ if (slashIndex < 0) slashIndex = bracketIndex; // line.slice(slashIndex + 1, pipeIndex) will be ''
return {
- name: line.slice(bracketIndex + 1, pipeIndex),
+ name: line.slice(slashIndex + 1, pipeIndex),
format: bracketIndex > 0 ? line.slice(0, bracketIndex) : '',
team: line.slice(pipeIndex + 1),
+ folder: line.slice(bracketIndex + 1, slashIndex > 0 ? slashIndex : bracketIndex + 1),
iconCache: ''
};
}).filter(function (v) { return v; });
@@ -508,7 +514,7 @@ Storage.unpackAllTeams = function (buffer) {
Storage.packAllTeams = function (teams) {
return teams.map(function (team) {
- return (team.format ? '' + team.format + ']' : '') + team.name + '|' + Storage.getPackedTeam(team);
+ return (team.format ? '' + team.format + ']' : '') + (team.folder ? '' + team.folder + '/' : '') + team.name + '|' + Storage.getPackedTeam(team);
}).join('\n');
};
@@ -917,10 +923,17 @@ Storage.importTeam = function (text, teams) {
if (teams.length) {
teams[teams.length - 1].team = Storage.packTeam(teams[teams.length - 1].team);
}
+ var slashIndex = line.lastIndexOf('/');
+ var folder = '';
+ if (slashIndex > 0) {
+ folder = line.slice(0, slashIndex);
+ line = line.slice(slashIndex + 1);
+ }
teams.push({
name: line,
format: format,
team: team,
+ folder: folder,
iconCache: ''
});
} else if (!curSet) {
@@ -1029,7 +1042,7 @@ Storage.exportAllTeams = function () {
var buf = '';
for (var i = 0, len = Storage.teams.length; i < len; i++) {
var team = Storage.teams[i];
- buf += '=== ' + (team.format ? '[' + team.format + '] ' : '') + team.name + ' ===\n\n';
+ buf += '=== ' + (team.format ? '[' + team.format + '] ' : '') + (team.folder ? '' + team.folder + '/' : '') + team.name + ' ===\n\n';
buf += Storage.exportTeam(team.team);
buf += '\n';
}
@@ -1243,6 +1256,7 @@ Storage.initDirectory2 = function () {
// load teams
self.nwLoadTeams();
self.saveAllTeams = self.nwSaveAllTeams;
+ self.deleteAllTeams = self.nwDeleteAllTeams;
self.saveTeam = self.nwSaveTeam;
self.deleteTeam = self.nwDeleteTeam;
@@ -1258,12 +1272,36 @@ Storage.revealFolder = function () {
gui.Shell.openItem(this.dir);
};
+Storage.nwFindTextFilesRecursive = function (dir, done) {
+ var results = [];
+ fs.readdir(dir, function (err, list) {
+ if (err) return done(err);
+ var pending = list.length;
+ if (!pending) return done(null, results);
+ list.forEach(function (file) {
+ file = dir + '/' + file;
+ fs.stat(file, function (err, stat) {
+ if (stat && stat.isDirectory()) {
+ Storage.nwFindTextFilesRecursive(file, function (err, res) {
+ results = results.concat(res);
+ if (!--pending) done(null, results);
+ });
+ } else {
+ if (file.slice(-4).toLowerCase() === '.txt') results.push(file);
+ if (!--pending) done(null, results);
+ }
+ });
+ });
+ });
+};
+
// teams
Storage.nwLoadTeams = function () {
var self = this;
var localApp = window.app;
- fs.readdir(this.dir + 'Teams', function (err, files) {
+ var dirOffset = this.dir.length + 6;
+ Storage.nwFindTextFilesRecursive(this.dir + 'Teams', function (err, files) {
if (err) return;
self.teams = [];
self.nwTeamsLeft = files.length;
@@ -1271,7 +1309,7 @@ Storage.nwLoadTeams = function () {
self.nwFinishedLoadingTeams(localApp);
}
for (var i = 0; i < files.length; i++) {
- self.nwLoadTeamFile(files[i], localApp);
+ self.nwLoadTeamFile(files[i].slice(dirOffset), localApp);
}
});
};
@@ -1279,12 +1317,11 @@ Storage.nwLoadTeams = function () {
Storage.nwLoadTeamFile = function (filename, localApp) {
var self = this;
var line = filename;
- if (line.substr(line.length - 4).toLowerCase() === '.txt') {
- line = line.substr(0, line.length - 4);
+ if (line.slice(-4).toLowerCase() === '.txt') {
+ line = line.slice(0, -4);
} else {
// not a team file
- self.nwTeamsLeft--;
- if (!self.nwTeamsLeft) {
+ if (!--self.nwTeamsLeft) {
self.nwFinishedLoadingTeams(localApp);
}
return;
@@ -1292,8 +1329,22 @@ Storage.nwLoadTeamFile = function (filename, localApp) {
var format = '';
var bracketIndex = line.indexOf(']');
if (bracketIndex >= 0) {
- format = line.substr(1, bracketIndex - 1);
- line = $.trim(line.substr(bracketIndex + 1));
+ format = line.slice(1, bracketIndex);
+ line = $.trim(line.slice(bracketIndex + 1));
+ }
+ var slashIndex = line.indexOf('/');
+ var folder = '';
+ if (slashIndex >= 0) {
+ folder = line.slice(0, slashIndex);
+ line = $.trim(line.slice(slashIndex + 1));
+ }
+ slashIndex = line.indexOf('/');
+ if (slashIndex >= 0) {
+ // very nested, not currently supported, skip
+ if (!--self.nwTeamsLeft) {
+ self.nwFinishedLoadingTeams(localApp);
+ }
+ return;
}
fs.readFile(this.dir + 'Teams/' + filename, function (err, data) {
if (!err) {
@@ -1301,11 +1352,11 @@ Storage.nwLoadTeamFile = function (filename, localApp) {
name: line,
format: format,
team: Storage.packTeam(Storage.importTeam('' + data)),
+ folder: folder,
iconCache: '',
filename: filename
});
- self.nwTeamsLeft--;
- if (!self.nwTeamsLeft) {
+ if (!--self.nwTeamsLeft) {
self.nwFinishedLoadingTeams(localApp);
}
}
@@ -1323,19 +1374,27 @@ Storage.teamCompare = function (a, b) {
return 0;
};
+Storage.fsReady = Tools.makeLoadTracker();
+Storage.fsReady.load();
+
Storage.nwDeleteAllTeams = function (callback) {
- var self = this;
- fs.readdir(this.dir + 'Teams', function (err, files) {
- if (err) return;
- self.nwTeamsLeft = files.length;
- if (!self.nwTeamsLeft) {
- callback();
- return;
+ // only delete teams we've opened
+ var deleteFilenames = [];
+ for (var i = 0; i < this.teams.length; i++) {
+ if (this.teams[i].filename) {
+ deleteFilenames.push(this.teams[i].filename);
+ delete this.teams[i].filename;
}
- for (var i = 0; i < files.length; i++) {
- self.nwDeleteTeamFile(files[i], callback);
- }
- });
+ }
+ if (!deleteFilenames.length) {
+ if (callback) callback();
+ return;
+ }
+ Storage.fsReady.unload();
+ this.nwTeamsLeft = deleteFilenames.length;
+ for (var i = 0; i < deleteFilenames.length; i++) {
+ this.nwDeleteTeamFile(deleteFilenames[i], callback);
+ }
};
Storage.nwDeleteTeamFile = function (filename, callback) {
@@ -1346,12 +1405,21 @@ Storage.nwDeleteTeamFile = function (filename, callback) {
} else {
// not a team file
self.nwTeamsLeft--;
- if (!self.nwTeamsLeft) callback();
+ if (!self.nwTeamsLeft) {
+ if (callback) callback();
+ Storage.fsReady.load();
+ }
return;
}
fs.unlink(this.dir + 'Teams/' + filename, function (err) {
+ var directory = filename.split('/').slice(0, -1).join('/');
+ fs.rmdir(directory, function () {});
+
self.nwTeamsLeft--;
- if (!self.nwTeamsLeft) callback();
+ if (!self.nwTeamsLeft) {
+ if (callback) callback();
+ Storage.fsReady.load();
+ }
});
};
@@ -1359,10 +1427,19 @@ Storage.nwSaveTeam = function (team) {
if (!team) return;
var filename = team.name + '.txt';
if (team.format) filename = '[' + team.format + '] ' + filename;
- filename = $.trim(filename).replace(/[\\\/]+/g, '');
+ filename = filename.trim().replace(/[\\\/]+/g, '');
+ if (team.folder) filename = '' + team.folder.replace(/[\\\/]+/g, '') + '/' + filename;
+
+ // not too hard to support saving to nested directories, but loading is a whole other issue
+ var splitFilename = filename.split('/');
+ var folder = splitFilename.slice(0, -1).join('');
+ var filename = folder + '/' + splitFilename[splitFilename.length - 1];
+ try {
+ fs.mkdirSync(this.dir + 'Teams/' + folder);
+ } catch (e) {}
if (team.filename && filename !== team.filename) {
- fs.unlink(this.dir + 'Teams/' + team.filename, function () {});
+ this.nwDeleteTeam();
}
team.filename = filename;
fs.writeFile(this.dir + 'Teams/' + filename, Storage.exportTeam(team.team).replace(/\n/g, '\r\n'));
@@ -1370,14 +1447,18 @@ Storage.nwSaveTeam = function (team) {
Storage.nwDeleteTeam = function (team) {
if (team.filename) {
- fs.unlink(this.dir + 'Teams/' + team.filename, function () {});
- delete team.filename;
+ var oldFilename = team.filename;
+ var oldDirectory = oldFilename.split('/').slice(0, -1).join('/');
+ if (oldDirectory) oldDirectory = this.dir + 'Teams/' + oldDirectory;
+ fs.unlink(this.dir + 'Teams/' + oldFilename, function () {
+ if (oldDirectory) fs.rmdir(oldDirectory, function () {});
+ });
}
};
Storage.nwSaveAllTeams = function () {
var self = this;
- this.nwDeleteAllTeams(function () {
+ Storage.fsReady(function () {
self.nwDoSaveAllTeams();
});
};
diff --git a/style/client.css b/style/client.css
index 2e00b7bd4..d5ead9ff9 100644
--- a/style/client.css
+++ b/style/client.css
@@ -837,7 +837,8 @@ p.or:after {
.menugroup p {
margin: 10px 0;
}
-.menugroup .button {
+.menugroup .button,
+.menugroup button.button {
box-sizing: border-box;
font-size: 12pt;
@@ -1999,13 +2000,24 @@ a.ilink.yours {
padding: 0;
border: 0;
}
-.folderlist .folder {
+.folderlist .folder,
+.folderlist .foldersep {
display: table-row;
margin: 0;
padding: 0;
border: 0;
height: 30px;
}
+.folderlist .foldersep {
+ height: 15px;
+}
+.folderlist .foldersep:before {
+ display: table-cell;
+ height: 15px;
+ background: #d7e3ec;
+ border-right: 1px solid #888888;
+ content: '';
+}
.folderlistafter {
display: table-row;
margin: 0;
@@ -2123,6 +2135,11 @@ a.ilink.yours {
font-size: 12pt;
padding: 5px 10px;
}
+.teampane .button.small,
+.teamwrapper .button.small {
+ font-size: 8pt;
+ padding: 2px 5px;
+}
.teamlist {
list-style: none;