From 8d4aa1ec44e067e5981fa9475b680bb52fae3fee Mon Sep 17 00:00:00 2001
From: Arkerthan <arkerthan@mailbox.org>
Date: Mon, 12 Sep 2022 21:37:06 +0200
Subject: [PATCH] Refactor slave description to use SpacedTextAccumulator

---
 css/interaction/slaveInteract.css |   5 +
 src/js/slaveCostJS.js             |   2 +-
 src/npc/descriptions/longSlave.js | 251 ++++++++++++------------------
 3 files changed, 109 insertions(+), 149 deletions(-)

diff --git a/css/interaction/slaveInteract.css b/css/interaction/slaveInteract.css
index 403f30d2892..dc9c7c2bbdf 100644
--- a/css/interaction/slaveInteract.css
+++ b/css/interaction/slaveInteract.css
@@ -10,6 +10,11 @@
 	font-size: 1.5em;
 }
 
+.si-slave-title {
+	color: coral;
+	font-weight: bold;
+}
+
 /* notification */
 a.with-note::after /*notification for links with notes in tooltips */
 {
diff --git a/src/js/slaveCostJS.js b/src/js/slaveCostJS.js
index 1089677ef83..41f0b0c3f6c 100644
--- a/src/js/slaveCostJS.js
+++ b/src/js/slaveCostJS.js
@@ -2208,7 +2208,7 @@ globalThis.FResult = function(s, forSale = 0) {
 /** Show an itemized breakdown of the sexual value (FResult) of the slave
  * @param {App.Entity.SlaveState} slave
  * @param {number} [forSale=0] set to 1 to ignore co-assignment and other temporary factors
- * @returns {Node}
+ * @returns {HTMLElement}
  */
 globalThis.FResultTooltip = function(slave, forSale = 0) {
 	// Make a link. Text should be slave's FResult. Clicking the link will display detailed info about that FResult over the top of the page (tooltip-style)
diff --git a/src/npc/descriptions/longSlave.js b/src/npc/descriptions/longSlave.js
index 6dcd140be03..f35c713da5b 100644
--- a/src/npc/descriptions/longSlave.js
+++ b/src/npc/descriptions/longSlave.js
@@ -9,9 +9,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	} = getPronouns(slave);
 	let el = new DocumentFragment();
 	let span;
-	let frag;
-	let p;
-	let r;
+	let r = new SpacedTextAccumulator();
 	SlaveStatClamp(slave);
 
 	descType = descType || (market ? DescType.MARKET : DescType.NORMAL);
@@ -22,127 +20,111 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	p = document.createElement("p");
 
 	// Name
-	App.UI.DOM.appendNewElement(
-		"span",	p,
-		`${SlaveFullName(slave)} `,
-		["slave", "name", "simple"]
-	);
+	r.push(App.UI.DOM.makeElement("span", `${SlaveFullName(slave)}`, ["slave", "name", "simple"]));
 
 	// Label
 	if (slave.custom.label) {
-		p.append("(", App.UI.DOM.makeElement('span', slave.custom.label, "custom-label"), ") ");
+		r.push(App.UI.DOM.combineNodes("(",
+			App.UI.DOM.makeElement('span', slave.custom.label, "custom-label"),
+			")"));
 	}
 
 	if (market && market !== "starting") {
 		if (applyLawCheck(market)) {
-			p.append(`has passed inspection to be sold in your arcology. `);
+			r.push(`has passed inspection to be sold in your arcology.`);
 		} else {
-			p.append(`is for sale and is available to inspect. `);
+			r.push(`is for sale and is available to inspect.`);
 		}
 		if (marketText) {
-			$(p).append(marketText, ` `);
+			r.push(marketText);
 		}
-		$(p).append(reportGingering(slave));
-		el.appendChild(p);
+		r.push(reportGingering(slave));
+		r.toParagraph();
 
-		p = document.createElement("p");
-		p.className = "indent";
-		p.appendChild(
-			App.UI.DOM.makeElement(
-				"span",
-				`${slave.slaveName} `,
-				"name"
-			)
-		);
+		r.push(App.UI.DOM.makeElement("span", `${slave.slaveName}`, "name"));
 	}
 
-	p.append(`is `);
+	r.push(`is`);
 	// Devotion
-	frag = new DocumentFragment();
 	span = document.createElement('span');
 
 	if (slave.devotion < -95) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion hateful";
-		span.textContent = "hate-filled, ";
+		span.textContent = "hate-filled,";
 	} else if (slave.devotion < -50) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion hateful";
-		span.textContent = "hateful, ";
+		span.textContent = "hateful,";
 	} else if (slave.devotion < -20) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion resistant";
-		span.textContent = "reluctant, ";
+		span.textContent = "reluctant,";
 	} else if (slave.devotion <= 20) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion ambivalent";
-		span.textContent = "hesitant, ";
+		span.textContent = "hesitant,";
 	} else if (slave.devotion <= 50) {
-		frag.append("an ");
+		r.push("an");
 		span.className = "devotion accept";
-		span.textContent = "accepting, ";
+		span.textContent = "accepting,";
 	} else if (slave.devotion <= 95) {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion devoted";
-		span.textContent = "devoted, ";
+		span.textContent = "devoted,";
 	} else {
-		frag.append("a ");
+		r.push("a");
 		span.className = "devotion worship";
-		span.textContent = "worshipful, ";
+		span.textContent = "worshipful,";
 	}
-
-	frag.appendChild(span);
-	p.appendChild(frag);
+	r.push(span);
 
 	// Trust
 	span = document.createElement('span');
 	if (slave.trust < -95) {
 		span.className = "trust terrified";
-		span.textContent = "abjectly terrified ";
+		span.textContent = "abjectly terrified";
 	} else if (slave.trust < -50) {
 		span.className = "trust terrified";
-		span.textContent = "terrified ";
+		span.textContent = "terrified";
 	} else if (slave.trust < -20) {
 		span.className = "trust frightened";
-		span.textContent = "frightened ";
+		span.textContent = "frightened";
 	} else if (slave.trust < 20) {
 		span.className = "trust fearful";
-		span.textContent = "fearful ";
+		span.textContent = "fearful";
 	} else if (slave.trust <= 50) {
 		if (slave.devotion < -20) {
 			span.className = "defiant careful";
-			span.textContent = "careful ";
+			span.textContent = "careful";
 		} else {
 			span.className = "trust careful";
-			span.textContent = "careful ";
+			span.textContent = "careful";
 		}
 	} else if (slave.trust < 95) {
 		if (slave.devotion < -20) {
 			span.className = "defiant bold";
-			span.textContent = "bold ";
+			span.textContent = "bold";
 		} else {
 			span.className = "trust trusting";
-			span.textContent = "trusting ";
+			span.textContent = "trusting";
 		}
 	} else {
 		if (slave.devotion < -20) {
 			span.className = "defiant full";
-			span.textContent = "defiant ";
+			span.textContent = "defiant";
 		} else {
 			span.className = "trust prof-trusting";
-			span.textContent = "profoundly trusting ";
+			span.textContent = "profoundly trusting";
 		}
 	}
-	p.appendChild(span);
+	r.push(span);
 
-	// Slave's Title, ex: "pregnant big bottomed busty milky hourglass broodmother"
-	span = App.UI.DOM.appendNewElement("span", p, `${SlaveTitle(slave)}. `, "coral");
-	span.style.fontWeight = "bold";
+	// Slave's Title, ex:"pregnant big bottomed busty milky hourglass broodmother"
+	r.push(App.UI.DOM.makeElement("span", `${SlaveTitle(slave)}.`, ["si-slave-title"]));
 
-	r = [];
 	// Indenture
 	if (slave.indenture > -1) {
 		r.push(`${His}`);
@@ -166,17 +148,15 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.sceneIntro(slave, descType));
 	r.push(App.Desc.name(slave));
 	r.push(App.Desc.ageAndHealth(slave));
-	$(p).append(r.join(" "));
 
-	r = [];
 	const clinicNameCaps = capFirstChar(V.clinicName);
 	if (descType !== DescType.MARKET) {
 		if (V.clinic !== 0 && V.clinicUpgradeScanner === 1) {
 			if (slave.chem > 15) {
-				p.append(`${clinicNameCaps}'s scanners score long term carcinogenic buildup in ${his} body at `,
-					App.UI.DOM.makeElement("span", `${Math.ceil(slave.chem / 10)}. `, "cyan"));
+				r.push(`${clinicNameCaps}'s scanners score long term carcinogenic buildup in ${his} body at`,
+					App.UI.DOM.makeElement("span", `${Math.ceil(slave.chem / 10)}.`, "cyan"));
 			} else {
-				p.append(`${clinicNameCaps}'s scanners confirm that ${he} has good prospects for long term health. `);
+				r.push(`${clinicNameCaps}'s scanners confirm that ${he} has good prospects for long term health.`);
 			}
 		}
 
@@ -216,12 +196,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 			}
 		}
 	}
-	$(p).append(r.join(` `));
-	el.appendChild(p);
 
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
+
 	if (descType !== DescType.MARKET || market === "starting") {
 		let origin = slave.origin;
 		if (origin === "$auto") {
@@ -290,9 +267,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	/* Needs contemplation. Slightly redundant with descriptionsWidgets.
 	if(slave.visualAge === V.idealAge) {
 		if(slave.actualAge === V.idealAge) {
-			r.push(`${He} is ${slave.actualAge}, `);
+			r.push(`${He} is ${slave.actualAge},`);
 		} else {
-			r.push(`${He} appears to be ${slave.visualAge}, `);
+			r.push(`${He} appears to be ${slave.visualAge},`);
 		}
 		if(V.idealAge === 18) {
 			r.push(`and many still find this age especially attractive due to old world tradition.`);
@@ -303,9 +280,9 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		r.push(`${He} appears to be ${slave.visualAge}, which is nearly the ideal, but as ${he} is actually ${slave.actualAge}, this can sometimes be cause for confusion regarding the appropriate level of enthusiasm society should have for ${him}.`);
 	} else if(slave.visualAge === V.idealAge - 1) {
 		if(slave.actualAge === V.idealAge - 1) {
-			r.push(`${He} is ${slave.actualAge}, `);
+			r.push(`${He} is ${slave.actualAge},`);
 		} else {
-			r.push(`${He} appears to be ${slave.visualAge}, `);
+			r.push(`${He} appears to be ${slave.visualAge},`);
 		}
 		if(V.idealAge === 18) {
 			r.push(`and many are already looking forward to ${his} birthday with great anticipation due to old world tradition.`);
@@ -313,34 +290,29 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 			r.push(`and many in the arcology are already looking forward to ${his} birthday with great anticipation.`);
 		}
 	} else if(slave.actualAge === V.idealAge && slave.visualAge !== V.idealAge) {
-		r.push(`${He} is ${slave.actualAge}, a fact that many in the arcology find appealing `);
+		r.push(`${He} is ${slave.actualAge}, a fact that many in the arcology find appealing`);
 		if(V.idealAge === 18) {
-			r.push(`because of old world tradition, `);
+			r.push(`because of old world tradition,`);
 		}
 		r.push(`but due to ${his} appearing to be ${slave.visualAge}, there is less enthusiasm for ${him} than there might otherwise be.`);
 	}
 	*/
 
-	$(p).append(r.join(" "));
-
 	if (V.showScores !== 0) {
-		p.append(` Currently, ${he} has an `);
+		r.push(`Currently, ${he} has an`);
 
 		// Beauty
-		App.UI.DOM.appendNewElement("span", p, `attractiveness score `, ["pink", "bold"]);
-		App.UI.DOM.appendNewElement("span", p, `of `, ["pink"]);
-		p.append(BeautyTooltip(slave), ` and a `);
+		r.push(App.UI.DOM.makeElement("span", `attractiveness score`, ["pink", "bold"]));
+		r.push(App.UI.DOM.makeElement("span", `of`, ["pink"]));
+		r.push(BeautyTooltip(slave), `and a`);
 
 		// Fresult
-		App.UI.DOM.appendNewElement("span", p, `sexual score `, ["lightcoral", "bold"]);
-		App.UI.DOM.appendNewElement("span", p, `of `, ["lightcoral"]);
-		p.append(FResultTooltip(slave), App.UI.DOM.makeElement("span", `.`, ["lightcoral"]));
+		r.push(App.UI.DOM.makeElement("span", `sexual score`, ["lightcoral", "bold"]));
+		r.push(App.UI.DOM.makeElement("span", `of`, ["lightcoral"]));
+		r.push(FResultTooltip(slave), App.UI.DOM.makeElement("span", `.`, ["lightcoral"]));
 	}
 
-	el.appendChild(p);
-	p = document.createElement('p');
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 
 	r.push(App.Desc.limbs(slave));
 
@@ -369,10 +341,10 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 			if (losses > 0) {
 				r.push(`with ${numberWithPluralOne(wins, "win")} and ${numberWithPluralOne(losses, "loss", "losses")}.`);
 			} else {
-				r.push(`${wins > 2 ? `all of ` : `both of `}which ${he} won.`);
+				r.push(`${wins > 2 ? `all of` : `both of`}which ${he} won.`);
 			}
 		} else {
-			r.push(`${losses > 2 ? `all of ` : `both of `}which ${he} lost.`);
+			r.push(`${losses > 2 ? `all of` : `both of`}which ${he} lost.`);
 		}
 	}
 
@@ -395,7 +367,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	}
 
 	let scarCounter = 0;
-	const scars = App.Medicine.Modification.scarRecord(slave)
+	const scars = App.Medicine.Modification.scarRecord(slave);
 	for (let scarName in scars) {
 		if (slave.ID === V.BodyguardID && scarCounter > 1) {
 			r.push(`${His} scars make ${him} look even more menacing than ${he} actually is.`);
@@ -523,27 +495,22 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 		}
 	}
 
-	$(p).append(r.join(` `));
-	p.append(` `);
-
 	if (slave.voice === 0) {
-		p.append(`${He} is `, App.UI.DOM.makeElement('span', "completely silent,", "pink"));
-		p.append(` which is understandable, since ${he}'s `, App.UI.DOM.makeElement("span", "mute. ", "red"));
+		r.push(`${He} is`, App.UI.DOM.makeElement('span', "completely silent,", "pink"));
+		r.push(`which is understandable, since ${he}'s`, App.UI.DOM.makeElement("span", "mute.", "red"));
 	} else if (slave.lips > 95) {
-		p.append(`${He} is `, App.UI.DOM.makeElement('span', "effectively mute,", "pink"));
-		p.append(` since ${his} lips are so large that ${he} can no longer speak intelligibly. ${He} can still `);
+		r.push(`${He} is`, App.UI.DOM.makeElement('span', "effectively mute,", "pink"));
+		r.push(`since ${his} lips are so large that ${he} can no longer speak intelligibly. ${He} can still`);
 		if (slave.devotion > 50) {
-			p.append(`moan `);
+			r.push(`moan`);
 		} else if (slave.devotion > 20) {
-			p.append(`whimper `);
+			r.push(`whimper`);
 		} else {
-			p.append(`scream `);
+			r.push(`scream`);
 		}
-		p.append(`through them, though. `);
+		r.push(`through them, though.`);
 	}
 
-	r = [];
-
 	if (V.showBodyMods === 1) {
 		if (slave.fuckdoll > 0) {
 			if (slave.piercing.ear.weight + slave.piercing.eyebrow.weight + slave.piercing.nose.weight > 0) {
@@ -608,67 +575,61 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "hand"));
 	r.push(App.Desc.mods(slave, "wrist"));
 
-	$(p).append(r.join(` `));
-	p.append(` `);
-
 	if (slave.fuckdoll === 0) {
 		if (slave.minorInjury !== 0) {
 			if (slave.minorInjury !== "sore ass") {
-				p.append(`${He} is sporting a `);
+				r.push(`${He} is sporting a`);
 				span = document.createElement('span');
 				span.className = "red";
-				span.textContent = `${slave.minorInjury}, `;
-				p.appendChild(span);
-				p.append(` covered by makeup. `);
+				span.textContent = `${slave.minorInjury},`;
+				r.push(span);
+				r.push(`covered by makeup.`);
 			}
 		}
 	}
 	if (slave.health.illness > 0) {
 		if (slave.fuckdoll === 0) {
-			p.append(`${He} `);
+			r.push(`${He}`);
 		} else {
-			p.append(`${His} suit reports that ${he} `);
+			r.push(`${His} suit reports that ${he}`);
 		}
 		span = document.createElement('span');
 		if (slave.health.illness === 1) {
 			if (slave.fuckdoll === 0) {
-				p.append(`is `);
+				r.push(`is`);
 				span.className = "red";
-				span.textContent = `feeling under the weather. `;
-				p.appendChild(span);
+				span.textContent = `feeling under the weather.`;
+				r.push(span);
 			} else {
-				p.append(`has `);
+				r.push(`has`);
 				span.className = "red";
-				span.textContent = `fallen ill. `;
-				p.appendChild(span);
+				span.textContent = `fallen ill.`;
+				r.push(span);
 			}
 		} else if (slave.health.illness === 2) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `somewhat ill. `;
-			p.appendChild(span);
+			span.textContent = `somewhat ill.`;
+			r.push(span);
 		} else if (slave.health.illness === 3) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `sick. `;
-			p.appendChild(span);
+			span.textContent = `sick.`;
+			r.push(span);
 		} else if (slave.health.illness === 4) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `very sick. `;
-			p.appendChild(span);
+			span.textContent = `very sick.`;
+			r.push(span);
 		} else if (slave.health.illness === 5) {
-			p.append(`is `);
+			r.push(`is`);
 			span.className = "red";
-			span.textContent = `terribly ill. `;
-			p.appendChild(span);
+			span.textContent = `terribly ill.`;
+			r.push(span);
 		}
 	}
 
-	el.appendChild(p);
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 	// Calling all boob widgets
 	r.push(App.Desc.boobs(slave, descType));
 	r.push(App.Desc.boobsShape(slave));
@@ -676,7 +637,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "chest"));
 	r.push(App.Desc.mods(slave, "breast"));
 	r.push(App.Desc.shoulders(slave));
-	if (slave.appendages !== "none" || slave.wingsShape !== "none"){
+	if (slave.appendages !== "none" || slave.wingsShape !== "none") {
 		r.push(App.Desc.upperBack(slave));
 	}
 	r.push(App.Desc.nipples(slave, descType));
@@ -687,28 +648,22 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 	r.push(App.Desc.mods(slave, "belly"));
 	r.push(App.Desc.butt(slave, descType));
 
-	$(p).append(r.join(` `));
-	el.appendChild(p);
-
-	p = document.createElement("p");
-	p.className = "indent";
-	r = [];
+	r.toParagraph();
 
 	r.push(App.Desc.crotch(slave, descType));
 	r.push(App.Desc.dick(slave, descType));
 	r.push(App.Desc.vagina(slave));
 	r.push(App.Desc.anus(slave, descType));
 
-	$(p).append(r.join(` `));
-	el.appendChild(p);
+	r.toParagraph();
 
 	if (slave.fuckdoll === 0) {
-		p = document.createElement("p");
-		p.className = "indent";
-		$(p).append(App.Desc.drugs(slave));
-		el.appendChild(p);
+		r.push(App.Desc.drugs(slave));
+		r.toParagraph();
 	}
 
+	el.append(r.container());
+
 	// clear sale and law flags, if set
 
 	return el;
@@ -742,7 +697,7 @@ App.Desc.longSlave = function(slave, {descType, market = 0, marketText, noArt} =
 					default:
 						t += `${He} is acting oddly, presenting ${his} ass in an awkward way and acting uncomfortable. ${He}'s obviously had an irritant shoved up ${his} butt to make ${him} act like an anal whore.`;
 				}
-				t += ` It's a trick you're very familiar with, given your <span class="skill player">training as a slaver.</span>`;
+				t += `It's a trick you're very familiar with, given your <span class="skill player">training as a slaver.</span>`;
 			} else if (slave.gingering.detected) {
 				switch (slave.gingering.type) {
 					case "antidepressant":
-- 
GitLab