From a98115c647147098d06c9e2084e13cbfb23700a9 Mon Sep 17 00:00:00 2001 From: Daniel Asher Resnick Date: Sat, 4 Feb 2023 13:53:39 -0600 Subject: [PATCH 1/5] Use Fetch API and thenify BurningData --- src/public/js/burning-service.js | 116 +++++++++++++++---------------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/src/public/js/burning-service.js b/src/public/js/burning-service.js index 242aaab..fe7761b 100644 --- a/src/public/js/burning-service.js +++ b/src/public/js/burning-service.js @@ -1,4 +1,4 @@ - +var DEBUG = true; /**** Class Settings (Angular Service) ****/ function Settings() { this.enforceLifepathReqts = true; @@ -218,13 +218,14 @@ function CharacterStorageService($http) { /* Load character names from server */ this.loadCharacterNames = function(){ - $http.get("/list_chars/user1", {'timeout': 3000} ). - success(function(data,status,headers,config){ + fetch("/list_chars/user1") + .then((response) => response.json()) + .then((data) => { myself.characterIdAndNames = data; console.log("Loaded saved character names"); - }). - error(function(data,status,headers,config){ - console.log("Error: Loading saved character names from server failed: HTTP code " + status + ": " + data); + }) + .catch((error) => { + console.log("Error: Loading saved character names from server failed: "+error); }); } @@ -305,24 +306,25 @@ function BurningDataService($http) { // Log events this.registerEvent("stocksLoaded", function() { console.log("Stocks fetched from server: ", Object.keys(myself.stocks)) - // DEBUG: - // console.log("Stocks fetched from server: ", myself.stocks) + if(DEBUG) + console.log("Stocks fetched from server: ", myself.stocks) }); this.registerEvent("skillsLoaded", function() { console.log("Loaded " + Object.keys(myself.skills).length + " skills."); - // DEBUG: - // console.log("Loaded skills: ", myself.skills); + if(DEBUG) + console.log("Loaded skills: ", myself.skills); }); this.registerEvent("traitsLoaded", function() { console.log("Loaded " + Object.keys(myself.traits).length + " traits."); - // DEBUG: - // console.log("Loaded traits: ", myself.traits); + if(DEBUG) + console.log("Loaded traits: ", myself.traits); }); - $http.get("/stocks", {'timeout': 3000}). - success(function(data,status,headers,config){ - // DEBUG: - // console.log(data); + fetch("/stocks") + .then((response) => response.json()) + .then((data) => { + if(DEBUG) + console.log("Loaded stock data: "+data); myself.stocks = data; for (var stock of Object.keys(data)) { myself.startingStatPts[stock] = new StartingStatPoints(myself.stocks[stock].starting_stats); @@ -330,68 +332,60 @@ function BurningDataService($http) { myself.defineStockEvent(stock, "resourcesLoaded"); } myself.triggerEvent("stocksLoaded"); - }). - error(function(data,status,headers,config){ - console.log("Error: Getting stocks from server failed: HTTP code " + status + ": " + data); + }) + .catch((error) => { + console.log("Error: Getting stocks from server failed: "+error); + }); + + /* Load skills from server */ + fetch("/skills") + .then((response) => response.json()) + .then((data) => { + myself.skills = data; + myself.triggerEvent("skillsLoaded"); + }) + .catch((error) => { + console.log("Error: Getting skills from server failed: "+error); + }); + + /* Load traits from server */ + fetch("/traits") + .then((response) => response.json()) + .then((data) => { + myself.traits = data; + myself.triggerEvent("traitsLoaded"); + }) + .catch((error) => { + console.log("Error: Getting traits from server failed: "+error); }); /* Load lifepaths from server */ this.loadLifepathsForStock = function(stock){ - $http.get("/lifepaths/" + stock, {'timeout': 3000} ). - success(function(data,status,headers,config){ + fetch("/lifepaths/" + stock) + .then((response) => response.json()) + .then((data) => { myself.lifepaths[stock] = data; myself.triggerStockEvent(stock, "lifepathsLoaded"); console.log("Loaded "+stock+" lifepaths. " + Object.keys(myself.lifepaths[stock]).length + " settings"); - }). - error(function(data,status,headers,config){ - console.log("Error: Getting "+stock+" lifepaths from server failed: HTTP code " + status + ": " + data); + }) + .catch((error) => { + console.log("Error: Getting "+stock+" lifepaths from server failed: "+error); }); } /* Load resources from server */ this.loadResourcesForStock = function(stock){ - $http.get("/resources/" + stock, {'timeout': 3000} ). - success(function(data,status,headers,config){ + fetch("/resources/" + stock) + .then((response) => response.json()) + .then((data) => { myself.resources[stock] = data; myself.triggerStockEvent(stock, "resourcesLoaded"); console.log("Loaded "+stock+" resources. "); - }). - error(function(data,status,headers,config){ - console.log("Error: Getting "+stock+" stat points from server failed: HTTP code " + status + ": " + data); + }) + .catch((error) => { + console.log("Error: Getting "+stock+" stat points from server failed: "+error); }); } - - - /* Load skills from server */ - $http.get("/skills", {'timeout': 3000} ). - success(function(data,status,headers,config){ - myself.skills = data; - myself.triggerEvent("skillsLoaded"); - }). - error(function(data,status,headers,config){ - console.log("Error: Getting skills from server failed: HTTP code " + status + ": " + data); - }); - - /* Load traits from server */ - $http.get("/traits", {'timeout': 3000} ). - success(function(data,status,headers,config){ - myself.traits = data; - myself.triggerEvent("traitsLoaded"); - }). - error(function(data,status,headers,config){ - console.log("Error: Getting traits from server failed: HTTP code " + status + ": " + data); - }); - // DEBUG: - // setTimeout(() => testStockLoading(myself), (2 * 1000)); -} - -function testStockLoading(dataService) { - console.log(dataService); - for (var stock in dataService.stocks) { - console.log(stock); - dataService.loadLifepathsForStock(stock); - dataService.loadResourcesForStock(stock); - } } /**** End BurningDataService ****/ From 42ffa31a3f2cdf1db49865d03691c4218fcd0dca Mon Sep 17 00:00:00 2001 From: Daniel Asher Resnick Date: Sat, 4 Feb 2023 14:00:49 -0600 Subject: [PATCH 2/5] Remove debug logging It would need to be refactored anyway --- src/public/js/burning-service.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/public/js/burning-service.js b/src/public/js/burning-service.js index fe7761b..1b5d619 100644 --- a/src/public/js/burning-service.js +++ b/src/public/js/burning-service.js @@ -300,26 +300,6 @@ function BurningDataService($http) { } - - var myself = this; - - // Log events - this.registerEvent("stocksLoaded", function() { - console.log("Stocks fetched from server: ", Object.keys(myself.stocks)) - if(DEBUG) - console.log("Stocks fetched from server: ", myself.stocks) - }); - this.registerEvent("skillsLoaded", function() { - console.log("Loaded " + Object.keys(myself.skills).length + " skills."); - if(DEBUG) - console.log("Loaded skills: ", myself.skills); - }); - this.registerEvent("traitsLoaded", function() { - console.log("Loaded " + Object.keys(myself.traits).length + " traits."); - if(DEBUG) - console.log("Loaded traits: ", myself.traits); - }); - fetch("/stocks") .then((response) => response.json()) .then((data) => { From 0782b4465ea5c6de286fa73776cb3db4e8fbd2f3 Mon Sep 17 00:00:00 2001 From: Daniel Asher Resnick Date: Sat, 4 Feb 2023 14:32:48 -0600 Subject: [PATCH 3/5] Debug behaviour should default to false Ideally overrides to this don't get committed, should find a better way to toggle it. --- src/public/js/burning-service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/public/js/burning-service.js b/src/public/js/burning-service.js index 1b5d619..7498921 100644 --- a/src/public/js/burning-service.js +++ b/src/public/js/burning-service.js @@ -1,4 +1,4 @@ -var DEBUG = true; +var DEBUG = false; /**** Class Settings (Angular Service) ****/ function Settings() { this.enforceLifepathReqts = true; From 30f477a2e00077b7c4612edad1a5cf819fb19691 Mon Sep 17 00:00:00 2001 From: Daniel Asher Resnick Date: Sat, 4 Feb 2023 15:40:42 -0600 Subject: [PATCH 4/5] Replace BurningData events with Promise handlers --- src/public/js/burning-service.js | 76 +++++++++++--------------------- src/public/js/burning.js | 26 ++++++----- 2 files changed, 40 insertions(+), 62 deletions(-) diff --git a/src/public/js/burning-service.js b/src/public/js/burning-service.js index 7498921..4891833 100644 --- a/src/public/js/burning-service.js +++ b/src/public/js/burning-service.js @@ -237,6 +237,10 @@ function CharacterStorageService($http) { /**** Class BurningDataService (Angular Service) ****/ // This service is used to load the lifepaths, skills, traits, etc. from the server. function BurningDataService($http) { + + // Used to reference the object from within functions and callbacks + var myself = this; + /* JSON Data structure representing lifepaths. The structure is: stock: setting_name: @@ -264,43 +268,10 @@ function BurningDataService($http) { // A hash of StartingStatPoints objects keyed by stock. this.startingStatPts = {}; - this.events = { - stocksLoaded: { triggered : false, callbacks : [] }, - traitsLoaded: { triggered : false, callbacks : [] }, - skillsLoaded: { triggered : false, callbacks : [] }, - } - - this.registerEvent = function(eventName, callback){ - if(this.events[eventName].triggered) - callback(); - this.events[eventName].callbacks.push(callback); - } - this.triggerEvent = function(eventName) { - myself.events[eventName].triggered = true; - for(var callback of myself.events[eventName].callbacks) { - callback(); - } - } + /* Loading of stocks, skills, and traits begins on initializing the service - this.stockEvents = {}; - this.defineStockEvent = function(stockName, eventName) { - if(!(stockName in myself.stockEvents)) myself.stockEvents[stockName] = {}; - myself.stockEvents[stockName][eventName] = { triggered : false, callbacks : [] } ; - } - this.registerStockEvent = function(stockName, eventName, callback){ - if(myself.stockEvents[stockName][eventName].triggered) - callback(); - myself.stockEvents[stockName][eventName].callbacks.push(callback); - } - this.triggerStockEvent = function(stockName, eventName) { - myself.stockEvents[stockName][eventName].triggered = true; - for(var callback of myself.stockEvents[stockName][eventName].callbacks) { - callback(); - } - } - - - fetch("/stocks") + /* Load stocks from server */ + this.whenStocksLoaded = fetch("/stocks") .then((response) => response.json()) .then((data) => { if(DEBUG) @@ -308,64 +279,67 @@ function BurningDataService($http) { myself.stocks = data; for (var stock of Object.keys(data)) { myself.startingStatPts[stock] = new StartingStatPoints(myself.stocks[stock].starting_stats); - myself.defineStockEvent(stock, "lifepathsLoaded"); - myself.defineStockEvent(stock, "resourcesLoaded"); } - myself.triggerEvent("stocksLoaded"); }) .catch((error) => { console.log("Error: Getting stocks from server failed: "+error); }); /* Load skills from server */ - fetch("/skills") + this.whenSkillsLoaded = fetch("/skills") .then((response) => response.json()) .then((data) => { myself.skills = data; - myself.triggerEvent("skillsLoaded"); + if(DEBUG) + console.log("Loaded skill data: "+data); }) .catch((error) => { console.log("Error: Getting skills from server failed: "+error); }); /* Load traits from server */ - fetch("/traits") + this.whenTraitsLoaded = fetch("/traits") .then((response) => response.json()) .then((data) => { myself.traits = data; - myself.triggerEvent("traitsLoaded"); + if(DEBUG) + console.log("Loaded trait data: "+data); }) .catch((error) => { console.log("Error: Getting traits from server failed: "+error); }); + /* Lifepaths and resources defer until their stock is selected */ + + this.whenLifePathsLoadedForStock = {}; /* Load lifepaths from server */ this.loadLifepathsForStock = function(stock){ - fetch("/lifepaths/" + stock) + return myself.whenLifePathsLoadedForStock[stock] = fetch("/lifepaths/" + stock) .then((response) => response.json()) .then((data) => { myself.lifepaths[stock] = data; - myself.triggerStockEvent(stock, "lifepathsLoaded"); - console.log("Loaded "+stock+" lifepaths. " + Object.keys(myself.lifepaths[stock]).length + " settings"); + if(DEBUG) + console.log("Loaded "+stock+" lifepaths. " + Object.keys(myself.lifepaths[stock]).length + " settings"); }) .catch((error) => { console.log("Error: Getting "+stock+" lifepaths from server failed: "+error); }); - } + }; /* Load resources from server */ + this.whenResourcesLoadedForStock = {}; this.loadResourcesForStock = function(stock){ - fetch("/resources/" + stock) + return myself.whenResourcesLoadedForStock[stock] = fetch("/resources/" + stock) .then((response) => response.json()) .then((data) => { myself.resources[stock] = data; - myself.triggerStockEvent(stock, "resourcesLoaded"); - console.log("Loaded "+stock+" resources. "); + if(DEBUG) + console.log("Loaded "+stock+" resources. "); }) .catch((error) => { console.log("Error: Getting "+stock+" stat points from server failed: "+error); }); - } + }; } /**** End BurningDataService ****/ diff --git a/src/public/js/burning.js b/src/public/js/burning.js index d2515e4..e51b17a 100644 --- a/src/public/js/burning.js +++ b/src/public/js/burning.js @@ -349,7 +349,6 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo return result; } - $scope.onGenderChange = function(){ if ($scope.name.length == 0) { $scope.generateName(); @@ -359,19 +358,21 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo $scope.onStockChange = function(){ if(!$scope.stock) return; - if(!$scope.stockSelected) { + + if(!$scope.stockSelected) { // Removes 'select a stock' after the first selection $scope.stocks.shift(); $scope.stockSelected = true; } - var oldName = $scope.name; - if(!burningData.lifepaths[$scope.stock]) { - burningData.loadLifepathsForStock($scope.stock); - } + + let loadPromises = []; if(!burningData.resources[$scope.stock]) { - burningData.loadResourcesForStock($scope.stock); + loadPromises.push(burningData.loadResourcesForStock($scope.stock)); + } + if(!burningData.lifepaths[$scope.stock]) { + loadPromises.push(burningData.loadLifepathsForStock($scope.stock)); } - // TODO: technically a bug — only want this registered once per stock... - burningData.registerStockEvent($scope.stock, "lifepathsLoaded", function () { + Promise.all(loadPromises).then(() => { + var oldName = $scope.name; // Make a blank character sheet $scope.initialize($scope.stock); @@ -383,6 +384,8 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo calculateSettingNames($scope, burningData); calculateCurrentSettingLifepathNames($scope, burningData); calculateSpecialTraitsForDisplay($scope, burningData); + calculateGearSelectionLists($scope, burningData); + calculatePropertySelectionLists($scope, burningData); }); } @@ -409,10 +412,11 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo calculateUnspentSkillPoints($scope); } - burningData.registerEvent("stocksLoaded", function() { - $scope.stocks = [{ name: "Select a stock" }] + burningData.whenStocksLoaded.then(() => { + $scope.stocks = [{ name: "Select a stock" }]; $scope.stocks = $scope.stocks.concat(Object.values(burningData.stocks)); $scope.stockSelected = false; + $scope.$digest(); }); $scope.$on('$locationChangeStart', function(event, nextUrl, currentUrl) { From c8adc19846952ba6d534ab4ba4a0bb3b468fab4b Mon Sep 17 00:00:00 2001 From: Daniel Asher Resnick Date: Sat, 4 Feb 2023 16:21:21 -0600 Subject: [PATCH 5/5] Load stock data on stock change or char upload Extracts the loading logic to a common method returning a promise, both places 'then' the promise. --- src/public/js/burning-serialize.js | 47 +++++++++++++++--------------- src/public/js/burning.js | 24 ++++++++------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/public/js/burning-serialize.js b/src/public/js/burning-serialize.js index 484b1cb..684ef23 100644 --- a/src/public/js/burning-serialize.js +++ b/src/public/js/burning-serialize.js @@ -1,8 +1,8 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropriateWeapons){ - $scope.name = charStruct.name; - $scope.gender = charStruct.gender; - $scope.stock = charStruct.stock; - + $scope.name = charStruct.name; + $scope.gender = charStruct.gender; + $scope.stock = charStruct.stock; + $scope.ensureStockLoaded($scope.stock).then(() => { // Appropriate weapons must be loaded before calculateLifepathSkills is called. if(serverSettings.storageType != 'server'){ appropriateWeapons.appropriateWeapons = charStruct.approp_weapons; @@ -15,8 +15,8 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr var selectedLifepaths = []; for(var i = 0; i < charStruct.lifepaths.length; i++){ var lp = charStruct.lifepaths[i]; - // lp[0] is setting name, lp[1] is lifepath name. - // lp[2] is brutalLifeDOF, lp[3] is brutalLifeTraitName, + // lp[0] is setting name, lp[1] is lifepath name. + // lp[2] is brutalLifeDOF, lp[3] is brutalLifeTraitName, // lp[4] is lifepath time, if it's variable and the user selected a value // lp[5] is the replacement skill for 'Weapon Of Choice' if it's present. // lp[6] is the replacement stat array, if present. This is needed if the @@ -128,19 +128,19 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr // Load Resources $scope.gear = {}; - for(var i = 0; i < charStruct.gear.length; i++){ + for(var i = 0; i < charStruct.gear.length; i++){ var gear = charStruct.gear[i]; $scope.gear[gear.desc] = new DisplayGear(gear.desc, gear.cost); } $scope.property = {}; - for(var i = 0; i < charStruct.property.length; i++){ + for(var i = 0; i < charStruct.property.length; i++){ var property = charStruct.property[i]; $scope.property[property.desc] = new DisplayGear(property.desc, property.cost); } - + $scope.relationships = {}; - for(var i = 0; i < charStruct.relationships.length; i++){ + for(var i = 0; i < charStruct.relationships.length; i++){ var rel = charStruct.relationships[i]; $scope.relationships[rel.desc] = new DisplayRelationship( rel.desc, @@ -154,13 +154,13 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr } $scope.affiliations = {}; - for(var i = 0; i < charStruct.affiliations.length; i++){ + for(var i = 0; i < charStruct.affiliations.length; i++){ var affil = charStruct.affiliations[i]; $scope.affiliations[affil.desc] = new DisplayAffiliation(affil.desc, affil.importance); } $scope.reputations = {}; - for(var i = 0; i < charStruct.reputations.length; i++){ + for(var i = 0; i < charStruct.reputations.length; i++){ var rep = charStruct.reputations[i]; $scope.reputations[rep.desc] = new DisplayReputation(rep.desc, rep.importance); } @@ -173,14 +173,15 @@ function loadCurrentCharacterFromStruct($scope, charStruct, burningData, appropr $scope.attributeModifierQuestionResults = loadAttributeModifierQuestionResultsFromSave($scope, charStruct.attr_mod_questions); $scope.brutalLifeWithdrawn = charStruct.brutal_life_withdrawn; - + $scope.$digest(); + }); } function convertCurrentCharacterToStruct($scope, appropriateWeapons) { // To serialize: // - Serialized version // - Character name - // - Stock + // - Stock // - Gender // - A list Lifepath names, with setting: [setting, lifepath] // - How many points were spent on which stat @@ -225,10 +226,10 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { var displayStat = $scope.stats[i]; stats.push({ - "name" : displayStat.name, - "shade" : displayStat.shade, - "mentalPoints" : displayStat.mentalPointsSpent, - "physicalPoints" : displayStat.physicalPointsSpent, + "name" : displayStat.name, + "shade" : displayStat.shade, + "mentalPoints" : displayStat.mentalPointsSpent, + "physicalPoints" : displayStat.physicalPointsSpent, "eitherPoints" : displayStat.eitherPointsSpent }); } @@ -277,7 +278,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { } var res = serializeResource( $scope.gear, function(display){ - return { + return { "cost" : display.cost, "desc" : display.desc }; @@ -285,7 +286,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { chardata.gear = res; var res = serializeResource( $scope.property, function(display){ - return { + return { "cost" : display.cost, "desc" : display.desc }; @@ -293,7 +294,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { chardata.property = res; var res = serializeResource( $scope.relationships, function(display){ - return { + return { "desc" : display.desc, "importance" : display.importance, "isImmedFam" : display.isImmedFam, @@ -306,7 +307,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { chardata.relationships = res; var res = serializeResource( $scope.affiliations, function(display){ - return { + return { "desc" : display.desc, "importance" : display.importance }; @@ -314,7 +315,7 @@ function convertCurrentCharacterToStruct($scope, appropriateWeapons) { chardata.affiliations = res; var res = serializeResource( $scope.reputations, function(display){ - return { + return { "desc" : display.desc, "importance" : display.importance }; diff --git a/src/public/js/burning.js b/src/public/js/burning.js index e51b17a..573aaed 100644 --- a/src/public/js/burning.js +++ b/src/public/js/burning.js @@ -364,14 +364,7 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo $scope.stockSelected = true; } - let loadPromises = []; - if(!burningData.resources[$scope.stock]) { - loadPromises.push(burningData.loadResourcesForStock($scope.stock)); - } - if(!burningData.lifepaths[$scope.stock]) { - loadPromises.push(burningData.loadLifepathsForStock($scope.stock)); - } - Promise.all(loadPromises).then(() => { + $scope.ensureStockLoaded($scope.stock).then(() => { var oldName = $scope.name; // Make a blank character sheet $scope.initialize($scope.stock); @@ -386,9 +379,21 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo calculateSpecialTraitsForDisplay($scope, burningData); calculateGearSelectionLists($scope, burningData); calculatePropertySelectionLists($scope, burningData); + $scope.$digest(); }); } + $scope.ensureStockLoaded = function(stock) { + let loadPromises = []; + if(!burningData.lifepaths[stock]) { + loadPromises.push(burningData.loadLifepathsForStock(stock)); + } + if(!burningData.resources[stock]) { + loadPromises.push(burningData.loadResourcesForStock(stock)); + } + return Promise.all(loadPromises); + }; + $scope.onSettingChange = function(){ calculateCurrentSettingLifepathNames($scope, burningData); @@ -413,8 +418,7 @@ function BurningCtrl($scope, $http, $modal, $timeout, settings, appropriateWeapo } burningData.whenStocksLoaded.then(() => { - $scope.stocks = [{ name: "Select a stock" }]; - $scope.stocks = $scope.stocks.concat(Object.values(burningData.stocks)); + $scope.stocks = [{ name: "Select a stock" }, ...Object.values(burningData.stocks)]; $scope.stockSelected = false; $scope.$digest(); });