diff --git a/devTools/FC.d.ts b/devTools/FC.d.ts index 2530ad10fbdbc6647f3d9de67e1b3a5568dcbda1..abc179ce417d94675542045bb8b6d52c0cc05446 100644 --- a/devTools/FC.d.ts +++ b/devTools/FC.d.ts @@ -249,8 +249,14 @@ declare namespace App { namespace SF {} namespace UI { - namespace DOM {} - namespace View {} + namespace DOM { + namespace Widgets { } + } + namespace View { } + namespace SlaveSummary { + type StringRenderer = (slave: App.Entity.SlaveState) => String; + type AppendRenderer = (slave: App.Entity.SlaveState, parentNode: Node) => void; + } } namespace Update {} diff --git a/js/002-config/fc-js-init.js b/js/002-config/fc-js-init.js index 784f7a7410c8b61af9d6dccb3fa5b0405b6ab4c8..6ee8fcd98120639ab35fa353a5727ed02858bd4e 100644 --- a/js/002-config/fc-js-init.js +++ b/js/002-config/fc-js-init.js @@ -4,59 +4,60 @@ var App = { }; -App.Arcology = { - Cell: {}, -}; +// When adding namespace declarations, please consider needs of those using VSCode: +// when you declare App.A{ A1:{}, A2:{} }, VSCode considers A, A1, and A2 to be +// sealed namespaces and no new members are added to them with nested declaration later on. +// This breaks code completion completely. Please instead declare them as: +// App.A = {}; App.A.A1 = {}; App.A.A2 = {}. Thank you. + +// Also, such declaration basically required only for namespaces that span more than a single file. + +App.Arcology = {}; +App.Arcology.Cell = {}, App.Art = {}; App.Corporate = {}; -App.Data = { - Weather: {}, - HeroSlaves: {}, -}; +App.Data = {}; +App.Data.HeroSlaves = { }; +App.Data.Weather = {}; App.Debug = {}; App.Desc = {}; -App.Encyclopedia = { - Entries: {} -}; -App.Entity = { - Utils: {} -}; +App.Encyclopedia = {}; +App.Encyclopedia.Entries = {}; +App.Entity = {}; +App.Entity.Utils = {}; App.Events = {}; -App.Facilities = { - Arcade: {}, - Brothel: {}, - Cellblock: {}, - Clinic: {}, - Club: {}, - Dairy: {}, - Farmyard: {}, - HGSuite: {}, - MasterSuite: {}, - Nursery: {}, - Schoolroom: {}, - ServantsQuarters: {}, - Spa: {} -}; +App.Facilities = {}; +App.Facilities.Arcade = {}; +App.Facilities.Brothel = {}; +App.Facilities.Cellblock = {}; +App.Facilities.Clinic = {}; +App.Facilities.Club = {} +App.Facilities.Dairy = {}; +App.Facilities.Farmyard = {}; +App.Facilities.HGSuite = {}; +App.Facilities.MasterSuite = {}; +App.Facilities.Nursery = {}; +App.Facilities.Schoolroom = {}; +App.Facilities.ServantsQuarters = {}; +App.Facilities.Spa = {} App.Interact = {}; App.Intro = {}; App.MainView = {}; -App.Medicine = { - Modification: {}, - OrganFarm: { - Organs: {} - }, - Surgery: {} -}; +App.Medicine = {}; +App.Medicine.Modification = {}; +App.Medicine.OrganFarm = {}; +App.Medicine.OrganFarm.Organs = {}; +App.Medicine.Surgery = {}; App.RA = {}; App.Reminders = {}; App.SF = {}; App.SecExp = {}; -App.UI = { - Budget: {}, - DOM: {}, - SlaveInteract: {}, - View: {} -}; +App.UI = {}; +App.UI.Budget = {}; +App.UI.DOM = {}; +App.UI.DOM.Widgets = {}; +App.UI.SlaveInteract = {}; +App.UI.View = {}; App.Update = {}; App.Utils = {}; diff --git a/src/004-base/arcologyBuilding.js b/src/004-base/arcologyBuilding.js index 2900eae721efd40dec801fdf3c3ea1ee66fa7ef0..9e33f19ae7f51c11ad9e5ce3f2fd61e0c259b51b 100644 --- a/src/004-base/arcologyBuilding.js +++ b/src/004-base/arcologyBuilding.js @@ -217,7 +217,7 @@ App.Arcology.Cell.BaseCell = class extends App.Entity.Serializable { if (cost > 0 || note === undefined) { note = ` Costs ${cashFormat(cost)}${note !== undefined ? ` ${note}` : ""}.`; } - App.UI.DOM.appendNewElement("span", note, div, "detail"); + App.UI.DOM.appendNewElement("span", div, note, "detail"); if (domNote !== undefined) { div.append(domNote); // this only exists for the farmyard, remove once that is out of alpha diff --git a/src/arcologyBuilding/shops.js b/src/arcologyBuilding/shops.js index 136879908be7af2d46dbb98d90998651cacef771..96d6b106b784a637a681ac02408e27022e0345b1 100644 --- a/src/arcologyBuilding/shops.js +++ b/src/arcologyBuilding/shops.js @@ -301,7 +301,7 @@ App.Arcology.Cell.Shop = class extends App.Arcology.Cell.BaseCell { } break; default: - App.UI.DOM.appendNewElement("span", `ERROR: bad shop type: ${this.type}`, fragment, "error"); + App.UI.DOM.appendNewElement("span", fragment, `ERROR: bad shop type: ${this.type}`, "error"); } if (this.owner === 1 && this.type === "Shops") { diff --git a/src/gui/multipleInspect.js b/src/gui/multipleInspect.js index 1abd7a86b0d7691d773d153d345dc44ba7226ddd..c46c8d3b712da7fb6619caf355ec8825db6e4e73 100644 --- a/src/gui/multipleInspect.js +++ b/src/gui/multipleInspect.js @@ -24,7 +24,7 @@ App.UI.MultipleInspect = (function() { */ function MultipleInspectDOM(slaves, showFamilyTree, saleDescription, applyLaw) { const frag = document.createDocumentFragment(); - const tabbar = App.UI.DOM.appendNewElement("div", "", frag, "tabbar"); + const tabbar = App.UI.DOM.appendNewElement("div", frag, "", "tabbar"); for (const slave of slaves) { tabbar.append(App.UI.tabbar.tabButtonDOM(`slave${slave.ID}`, slave.slaveName)); diff --git a/src/js/main.js b/src/js/main.js index 144c26aebeed49b819f0629b41bb758ac0a82988..983005dedc82567bb276bc5cd30e95c7f331f43e 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -170,7 +170,7 @@ App.MainView.useGuard = function() { return outerDiv; } - App.UI.DOM.appendNewElement("span", App.Interact.guardPose(guard), outerDiv, "scene-intro"); + App.UI.DOM.appendNewElement("span", outerDiv, App.Interact.guardPose(guard), "scene-intro"); function setEnvironment() { V.activeSlave = guard; diff --git a/src/js/utilsDOM.js b/src/js/utilsDOM.js index 80194e7e9d9b3bfb3b3d04e024472b679c914646..a88f6d5fe8445184237239d908fe9c0b954cf954 100644 --- a/src/js/utilsDOM.js +++ b/src/js/utilsDOM.js @@ -121,7 +121,7 @@ App.UI.DOM.disabledLink = function(link, reasons) { /** * @param {string} tag - valid HTML tag - * @param {string|Node} content + * @param {string|Node} [content] * @param {string|Array<string>} [classNames] * @returns {HTMLElement} */ @@ -134,18 +134,20 @@ App.UI.DOM.makeElement = function(tag, content, classNames) { element.classList.add(classNames); } } - element.append(content); + if (content) { + element.append(content); + } return element; }; /** * @param {string} tag - valid HTML tag - * @param {string|Node} content * @param {ParentNode} parent + * @param {string|Node} [content] * @param {string|Array<string>} [classNames] * @returns {HTMLElement} */ -App.UI.DOM.appendNewElement = function(tag, content, parent, classNames) { +App.UI.DOM.appendNewElement = function(tag, parent, content, classNames) { const element = App.UI.DOM.makeElement(tag, content, classNames); parent.append(element); return element; @@ -287,6 +289,34 @@ App.UI.DOM.arrayToList = function(content, delimiter = ", ", lastDelimiter = " a return fragment; }; +/** + * @param {function (*):void} callback + * @param {Object.<string, *>} options + * @param {*|function (): *} currentValue + * @param {string} [description] + * @returns {HTMLSpanElement} + */ +App.UI.DOM.Widgets.optionSelector = function(callback, options, currentValue, description) { + const res = document.createElement("span"); + res.classList.add("optionMacro"); + if (description) { + App.UI.DOM.appendNewElement("span", res, description, "optionDescription"); + } + const curVal = (currentValue instanceof Function) ? currentValue() : currentValue; + const valueNode = App.UI.DOM.appendNewElement("span", res, null, "optionValue"); + for (const s in options) { + const v = options[s]; + const choice = App.UI.DOM.appendNewElement("span", valueNode, null, "optionMacroOption"); + if (v === curVal) { + choice.classList.add("optionMacroSelected"); + choice.innerText = s; + } else { + choice.append(App.UI.DOM.link(s, () => { callback(v); })); + } + } + return res; +}; + /** * @param {string} text * @returns {HTMLElement}