Merge pull request #1618 from AleziaKurdis/createApp_2025_06_Bundle
Some checks failed
Master API-docs CI Build and Deploy / Build and deploy API-docs (push) Has been cancelled
Master Doxygen CI Build and Deploy / Build and deploy Doxygen documentation (push) Has been cancelled

Create app: Properties Tab: Add "tags" properties and arrayOfStrings field type to support it.
This commit is contained in:
ksuprynowicz 2025-06-13 20:45:28 +02:00 committed by GitHub
commit 1238aa1297
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 221 additions and 4 deletions

View file

@ -698,6 +698,9 @@
"renderWithZones": {
"tooltip": "If set, this entity will only render when your avatar is inside of a zone in this list."
},
"tags": {
"tooltip": "A set of tags describing this entity that can be used with the API."
},
"groupCulled": {
"tooltip": "If false, individual pieces of the entity may be culled by the render engine. If true, either the entire entity will be culled, or it won't at all."
},

View file

@ -23,6 +23,8 @@ const ENTITY_HOST_TYPE_COLOR_LOCAL = "#f0d769";
const NO_SELECTION = ",";
const MAX_TAGS_PER_ROWS = 5;
const PROPERTY_SPACE_MODE = Object.freeze({
ALL: 0,
LOCAL: 1,
@ -154,7 +156,13 @@ const GROUPS = [
label: "Render With Zones",
type: "multipleZonesSelection",
propertyID: "renderWithZones",
}
},
{
label: "Tags",
type: "arrayOfStrings",
propertyID: "tags",
useStringColor: true,
},
]
},
{
@ -1126,7 +1134,7 @@ const GROUPS = [
vec2Type: "xyz",
min: 0,
max: 1,
step: 0.1,
step: 0.005,
decimals: 4,
subLabels: [ "x", "y" ],
propertyID: "materialMappingPos",
@ -1135,7 +1143,7 @@ const GROUPS = [
label: "Material Scale",
type: "vec2",
vec2Type: "xyz",
step: 0.1,
step: 0.005,
decimals: 4,
subLabels: [ "x", "y" ],
propertyID: "materialMappingScale",
@ -2297,6 +2305,8 @@ function getPropertyInputElement(propertyID) {
return property.elInput;
case 'multipleZonesSelection':
return property.elInput;
case 'arrayOfStrings':
return property.elInput;
case 'number-draggable':
return property.elNumber.elInput;
case 'rect':
@ -2464,6 +2474,12 @@ function resetProperties() {
setZonesSelectionData(property.elInput, false);
break;
}
case 'arrayOfStrings': {
property.elInput.classList.remove('multi-diff');
property.elInput.value = "[]";
setArrayOfStringsUi(property.elInput.id, false);
break;
}
case 'childList': {
setChildListData(property.elInput, undefined, "");
break;
@ -3716,6 +3732,10 @@ function createProperty(propertyData, propertyElementID, propertyName, propertyI
property.elInput = createZonesSelection(property, elProperty);
break;
}
case 'arrayOfStrings': {
property.elInput = createArrayOfStrings(property, elProperty);
break;
}
case 'childList': {
property.elInput = createChildList(property, elProperty);
break;
@ -4834,6 +4854,155 @@ function setZonesSelectionData(element, isEditable) {
displaySelectedZones(element.id, isEditable);
}
/**
* ARRAY-OF-STRINGS FUNCTIONS
*/
function createArrayOfStrings(property, elProperty) {
let propertyData = property.data;
let elementID = property.elementID;
elProperty.className = "arrayOfStrings";
let elInput = document.createElement('input');
elInput.setAttribute("id", elementID);
elInput.setAttribute("type", "hidden");
elInput.setAttribute("useStringColor", propertyData.useStringColor);
elInput.className = "hiddenArrayOfStrings";
let elArrayOfStringsSelector = document.createElement('div');
elArrayOfStringsSelector.setAttribute("id", "arrayOfStrings-selector-" + elementID);
let elMultiDiff = document.createElement('span');
elMultiDiff.className = "multi-diff";
elProperty.appendChild(elInput);
elProperty.appendChild(elArrayOfStringsSelector);
elProperty.appendChild(elMultiDiff);
return elInput;
}
function setArrayOfStringsUi(propertyId, isEditable) {
let i, listedStringsInner, hiddenData, isMultiple, useStringColor, tagStyle;
hiddenData = document.getElementById(propertyId).value;
useStringColor = document.getElementById(propertyId).getAttribute('useStringColor').toLowerCase() === "true";
if (JSON.stringify(hiddenData) === '"undefined"') {
isMultiple = true;
hiddenData = "[]";
} else {
isMultiple = false;
}
listedStringsInner = "<div class='arrayOfStringsContainer'>";
let selectedStrings = JSON.parse(hiddenData);
if (selectedStrings.length === 0) {
if (isMultiple) {
listedStringsInner += "<br>"; //or anything saying we dont suport multiple selection, but we might by the list with bulk actions.
}
} else {
selectedStrings.sort();
let counter = 0;
for (i = 0; i < selectedStrings.length; i++) {
tagStyle = "";
if (useStringColor) {
tagStyle = " style='color:#bbbbbb; background-color:" + getColorOfString(selectedStrings[i]) + ";'";
}
if (isEditable) {
listedStringsInner += "<div class='arrayOfStringsTags'" + tagStyle + ">" + selectedStrings[i] + "&nbsp;&nbsp;";
listedStringsInner += "<span class='arrayOfStringsTagsRemove' onClick='removeElementFromArrayOfStrings(" + '"' + propertyId + '"' + ", " + '"' + selectedStrings[i] + '"' + ");' >&#10006;</span>"
listedStringsInner += "</div>";
} else {
listedStringsInner += "<div class='arrayOfStringsTags'" + tagStyle + ">" + selectedStrings[i] + "</div>";
}
counter++;
if (counter === MAX_TAGS_PER_ROWS) {
listedStringsInner += "<br>";
counter = 0;
}
}
}
if (isEditable && !isMultiple) {
let addComponent = "<div class='arrayOfStringsAddComponentContainer'><input class='arrayOfStringsStringToAdd' type='text' id='arrayOfStringsStringToAdd-" + propertyId + "'>";
addComponent += " <input type='button' class='glyph' value = 'K' id='arrayOfStringsAddButton-" + propertyId + "' onClick='addElementToArrayOfStrings(" + '"' + propertyId + '", "';
addComponent += "arrayOfStringsStringToAdd-" + propertyId + '"' + ");'>";
addComponent += "</div>";
listedStringsInner += addComponent;
}
listedStringsInner += "</div>";
document.getElementById("arrayOfStrings-selector-" + propertyId).innerHTML = listedStringsInner;
}
function removeElementFromArrayOfStrings(propertyId, stringText) {
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let selectedStrings = JSON.parse(hiddenField.value);
let index = selectedStrings.indexOf(stringText);
if (index > -1) {
selectedStrings.splice(index, 1);
}
hiddenField.value = JSON.stringify(selectedStrings);
setArrayOfStringsUi(propertyId, true);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, selectedStrings, false);
}
function addElementToArrayOfStrings(propertyId, elementToGetText) {
let stringText = document.getElementById(elementToGetText).value;
if (stringText === "") {
return;
} else {
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let selectedStrings = JSON.parse(hiddenField.value);
if (!selectedStrings.includes(stringText)) {
selectedStrings.push(stringText);
}
hiddenField.value = JSON.stringify(selectedStrings);
setArrayOfStringsUi(propertyId, true);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, selectedStrings, false);
}
}
function getColorOfString(input) {
let sum = 0;
for (let i = 0; i < input.length; i++) {
sum += input.charCodeAt(i);
}
let hue = sum % 360;
return hslToHex(hue, 100, 20);
}
function hslToHex(h, s, l) {
s /= 100;
l /= 100;
const c = (1 - Math.abs(2 * l - 1)) * s;
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
const m = l - c / 2;
let r = 0, g = 0, b = 0;
if (0 <= h && h < 60) {
[r, g, b] = [c, x, 0];
} else if (60 <= h && h < 120) {
[r, g, b] = [x, c, 0];
} else if (120 <= h && h < 180) {
[r, g, b] = [0, c, x];
} else if (180 <= h && h < 240) {
[r, g, b] = [0, x, c];
} else if (240 <= h && h < 300) {
[r, g, b] = [x, 0, c];
} else if (300 <= h && h < 360) {
[r, g, b] = [c, 0, x];
}
const toHex = (n) => {
const hex = Math.round((n + m) * 255).toString(16);
return hex.padStart(2, '0');
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
/**
* CHILD ENTITIES FUNCTIONS
@ -5530,7 +5699,7 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
break;
}
case 'multipleZonesSelection': {
property.elInput.value = JSON.stringify(propertyValue);
property.elInput.value = JSON.stringify(propertyValue);
if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
setZonesSelectionData(property.elInput, false);
} else {
@ -5538,6 +5707,15 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
}
break;
}
case 'arrayOfStrings': {
property.elInput.value = JSON.stringify(propertyValue);
if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
setArrayOfStringsUi(property.elInput.id, false);
} else {
setArrayOfStringsUi(property.elInput.id, true);
}
break;
}
case 'childList': {
let parentID = selections[0].properties.parentID;
if (selections.length !== 1 || parentID === UUID_NONE) {

View file

@ -335,6 +335,10 @@ input[type="text"] {
width: 100%;
}
input.arrayOfStringsStringToAdd {
width: 70%;
}
input.multi-diff:not(:focus) + span.multi-diff,
textarea.multi-diff:not(:focus) + span.multi-diff,
.draggable-number.multi-diff>input:not(:focus)+span.multi-diff,
@ -2292,3 +2296,35 @@ font.viewParentIcon {
font-weight: bold;
}
div.arrayOfStringsContainer {
width: 100%;
overflow: hidden;
}
div.arrayOfStringsAddComponentContainer {
margin-top: 2px;
}
div.arrayOfStringsTags {
color: #000000;
font-family: FiraSans-SemiBold;
font-size: 12px;
border-radius: 10px;
padding: 5px 8px 5px 8px;
margin: 2px;
text-align: left;
background-color: #dddddd;
border: none;
display: inline-block;
width: auto;
max-width: none;
}
span.arrayOfStringsTagsRemove {
color: #777777;
}
span.arrayOfStringsTagsRemove:hover {
color: #000000;
}