";
document.getElementById("selected-zones-" + propertyId).innerHTML = listedZoneInner;
if (isEditable) {
document.getElementById("multiZoneSelTools-" + propertyId).style.display = "block";
} else {
document.getElementById("multiZoneSelTools-" + propertyId).style.display = "none";
}
}
function createZonesSelection(property, elProperty) {
let propertyData = property.data;
let elementID = property.elementID;
requestZoneList();
elProperty.className = "multipleZonesSelection";
let elInput = document.createElement('input');
elInput.setAttribute("id", elementID);
elInput.setAttribute("type", "hidden");
elInput.setAttribute("zonesCoefficientID", propertyData.zonesCoefficientID ?? "");
elInput.className = "hiddenMultiZonesSelection";
let elZonesSelector = document.createElement('div');
elZonesSelector.setAttribute("id", "zones-selector-" + elementID);
let elMultiDiff = document.createElement('span');
elMultiDiff.className = "multi-diff";
elProperty.appendChild(elInput);
elProperty.appendChild(elZonesSelector);
elProperty.appendChild(elMultiDiff);
return elInput;
}
function setZonesSelectionData(element, isEditable) {
let zoneSelectorContainer = document.getElementById("zones-selector-" + element.id);
let zoneSelector = "
";
zoneSelector += "";
zoneSelector += "
";
zoneSelector += "
Select the Zone to add:";
zoneSelector += "";
zoneSelector += "
";
zoneSelector += "
";
let i, name;
for (i = 0; i < zonesList.length; i++) {
if (zonesList[i].name === "") {
name = zonesList[i].id;
} else {
name = zonesList[i].name;
}
zoneSelector += " ";
}
zoneSelector += "
";
zoneSelector += "
";
zoneSelector += "";
zoneSelector += "
";
zoneSelector += "";
zoneSelectorContainer.innerHTML = zoneSelector;
displaySelectedZones(element.id, isEditable);
}
function getZoneName(zoneID) {
let name = "{ERROR: NOT FOUND}";
let j;
for (j = 0; j < zonesList.length; j++) {
if (zoneID === zonesList[j].id) {
if (zonesList[j].name !== "") {
name = zonesList[j].name;
} else {
name = zonesList[j].id;
}
break;
}
}
return name;
}
/**
* ZONES COEFFICIENT
*/
function createZonesCoefficient(property, elProperty) {
let propertyData = property.data;
let elementID = property.elementID;
elProperty.className = "zonesCoefficient";
let elInput = document.createElement('input');
elInput.setAttribute("id", elementID);
elInput.setAttribute("type", "hidden");
elInput.setAttribute("multipleZonesSelectionID", propertyData.multipleZonesSelectionID);
elInput.className = "hiddenZonesCoefficient";
let elZonesCoefficientSelector = document.createElement('div');
elZonesCoefficientSelector.setAttribute("id", "zonesCoefficient-selector-" + elementID);
let elMultiDiff = document.createElement('span');
elMultiDiff.className = "multi-diff";
elProperty.appendChild(elInput);
elProperty.appendChild(elZonesCoefficientSelector);
elProperty.appendChild(elMultiDiff);
return elInput;
}
function setZonesCoefficientUi(propertyId, isEditable) {
let i, listedCoefficientsInner, hiddenData, isMultiple, multipleZonesSelectionID, zoneListData;
hiddenData = document.getElementById(propertyId).value;
multipleZonesSelectionID = document.getElementById(propertyId).getAttribute('multipleZonesSelectionID');
zoneListData = JSON.parse(document.getElementById("property-" + multipleZonesSelectionID.replace(".", "-")).value);
if (JSON.stringify(hiddenData) === '"undefined"') {
isMultiple = true;
hiddenData = "[]";
} else {
isMultiple = false;
}
listedCoefficientsInner = "
";
let coefficients = JSON.parse(hiddenData);
if (coefficients.length !== zoneListData.length) {
listedCoefficientsInner += "
";
listedCoefficientsInner += "WARNING: Zones and coefficients are desynchronized. ";
listedCoefficientsInner += "";
listedCoefficientsInner += "
";
} else {
if (coefficients.length === 0) {
if (isMultiple) {
listedCoefficientsInner += "Not available.";
}
listedCoefficientsInner += " ";
} else {
let zoneName, lineColor;
for (i = 0; i < coefficients.length; i++) {
zoneName = getZoneName(zoneListData[i]);
lineColor = "";
if (i % 2 !== 0) {
lineColor = " zonesCoefficientDarkLine";
}
if (isEditable) {
listedCoefficientsInner += "
";
document.getElementById("zonesCoefficient-selector-" + propertyId).innerHTML = listedCoefficientsInner;
}
function fixUnsynchZonesCoefficients(propertyId, expectedLength) {
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let originalCoefficients = JSON.parse(hiddenField.value);
let coefficients = [];
let i;
for (i = 0; i < expectedLength; i++) {
if ( i < originalCoefficients.length) {
coefficients[i] = originalCoefficients[i];
} else {
coefficients[i] = AUDIO_ATTENUATION_COEFFICIENT_DEFAULT_VALUE;
}
}
hiddenField.value = JSON.stringify(coefficients);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, coefficients, false);
}
function setZonesCoefficientValue(propertyId, index, coef) {
function cleanFloat(val) {
let num = parseFloat(val);
if (Number.isNaN(num)) {
return 0;
}
return num;
}
let newCoefValue = cleanFloat(coef);
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let coefficients = JSON.parse(hiddenField.value);
coefficients[index] = newCoefValue;
hiddenField.value = JSON.stringify(coefficients);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, coefficients, false);
}
function removeElementFromZonesCoefficient(propertyId, index) {
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let coefficients = JSON.parse(hiddenField.value);
coefficients.splice(index, 1);
hiddenField.value = JSON.stringify(coefficients);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, coefficients, false);
}
function addElementToZonesCoefficient(propertyId) {
let hiddenField = document.getElementById(propertyId);
if (JSON.stringify(hiddenField.value) === '"undefined"') {
hiddenField.value = "[]";
}
let coefficients = JSON.parse(hiddenField.value);
coefficients.push(AUDIO_ATTENUATION_COEFFICIENT_DEFAULT_VALUE);
hiddenField.value = JSON.stringify(coefficients);
let propertyName = propertyId.replace("property-", "");
propertyName = propertyName.replace("-", ".");
updateProperty(propertyName, coefficients, false);
}
/**
* 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 = "
";
let selectedStrings = JSON.parse(hiddenData);
if (selectedStrings.length === 0) {
if (isMultiple) {
listedStringsInner += " "; //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 += "
";
document.getElementById("uiCreateChildEntityAssistant-form").innerHTML = renderer;
}
function selectTypeInChildEntityAssistant(type, entityHostType) {
if (type === "Model" || type === "Sound") { //Only if the url is cruxial. We want the less entry as possible for the user.
document.getElementById("nameCreateChildEntityAssistant").innerHTML = "
Create a child '" + type + "' entity ";
document.getElementById("typeSelectorCreateChildEntityAssistant").style.display = "none";
document.getElementById("paramaterCreateChildEntityAssistant").style.display = "block";
document.getElementById("createBtnCreateChildEntityAssistant").setAttribute("onclick","createChildEntity('" + type + "', '" + entityHostType + "')");
document.getElementById("cancelBtnCreateChildEntityAssistant").setAttribute("onclick","closeCreateChildEntityAssistant()");
} else {
createChildEntity(type, entityHostType);
}
}
function createChildEntity(type, entityHostType) {
let url = document.getElementById("urlCreateChildEntityAssistant").value;
let parentID = getPropertyInputElement("id").value;
let properties;
switch(type) {
case "Model":
properties = {
"type": type,
"modelURL": url,
"parentID": parentID,
"shapeType": "static-mesh",
"dynamic": false,
"grab": {"grabbable": false},
"useOriginalPivot": true
};
break;
case "Shape":
properties = {
"type": type,
"parentID": parentID,
"shape": "Cube"
};
break;
case "Text":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Image":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Web":
properties = {
"type": type,
"parentID": parentID
};
break;
case "ParticleEffect":
properties = {
"type": type,
"parentID": parentID
};
break;
case "ProceduralParticleEffect":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Light":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Zone":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Material":
properties = {
"type": type,
"materialURL": "materialData",
"materialData": JSON.stringify({ "materials": {} }),
"parentID": parentID,
"priority": 1
};
break;
case "Sound":
properties = {
"type": type,
"soundURL": url,
"parentID": parentID
};
break;
case "Script":
properties = {
"type": type,
"parentID": parentID
};
break;
case "PolyVox":
properties = {
"type": type,
"parentID": parentID
};
break;
case "Empty":
properties = {
"type": type,
"parentID": parentID
};
break;
}
EventBridge.emitWebEvent(JSON.stringify({
"type": "createChildEntity",
"properties": properties,
"entityHostType": entityHostType
}));
closeCreateChildEntityAssistant();
}
function closeCreateChildEntityAssistant() {
$('#uiCreateChildEntityAssistant').hide();
$('#properties-list').show();
}
/**
* MATERIAL TARGET FUNCTIONS
*/
function requestMaterialTarget() {
EventBridge.emitWebEvent(JSON.stringify({
type: 'materialTargetRequest',
entityID: getFirstSelectedID(),
}));
}
function setMaterialTargetData(materialTargetData) {
let elDivOptions = getPropertyInputElement("parentMaterialName");
resetDynamicMultiselectProperty(elDivOptions);
if (materialTargetData === undefined) {
return;
}
elDivOptions.firstChild.style.display = "none"; // hide "No Options" text
elDivOptions.parentNode.lastChild.style.display = null; // show Select/Clear all buttons
let numMeshes = materialTargetData.numMeshes;
for (let i = 0; i < numMeshes; ++i) {
addMaterialTarget(elDivOptions, i, false);
}
let materialNames = materialTargetData.materialNames;
let materialNamesAdded = [];
for (let i = 0; i < materialNames.length; ++i) {
let materialName = materialNames[i];
if (materialNamesAdded.indexOf(materialName) === -1) {
addMaterialTarget(elDivOptions, materialName, true);
materialNamesAdded.push(materialName);
}
}
materialTargetPropertyUpdate(elDivOptions.propertyValue);
}
function addMaterialTarget(elDivOptions, targetID, isMaterialName) {
let elementID = elDivOptions.getAttribute("id");
elementID += isMaterialName ? "-material-" : "-mesh-";
elementID += targetID;
let elDiv = document.createElement('div');
elDiv.className = "materialTargetDiv";
elDiv.onclick = onToggleMaterialTarget;
elDivOptions.appendChild(elDiv);
let elInput = document.createElement('input');
elInput.className = "materialTargetInput";
elInput.setAttribute("type", "checkbox");
elInput.setAttribute("id", elementID);
elInput.setAttribute("targetID", targetID);
elInput.setAttribute("isMaterialName", isMaterialName);
elDiv.appendChild(elInput);
let elLabel = document.createElement('label');
elLabel.setAttribute("for", elementID);
elLabel.innerText = isMaterialName ? "Material " + targetID : "Mesh Index " + targetID;
elDiv.appendChild(elLabel);
return elDiv;
}
function onToggleMaterialTarget(event) {
let elTarget = event.target;
if (elTarget instanceof HTMLInputElement) {
sendMaterialTargetProperty();
}
event.stopPropagation();
}
function setAllMaterialTargetInputs(checked) {
let elDivOptions = getPropertyInputElement("parentMaterialName");
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
for (let i = 0; i < elInputs.length; ++i) {
elInputs[i].checked = checked;
}
}
function selectAllMaterialTarget() {
setAllMaterialTargetInputs(true);
sendMaterialTargetProperty();
}
function clearAllMaterialTarget() {
setAllMaterialTargetInputs(false);
sendMaterialTargetProperty();
}
function sendMaterialTargetProperty() {
let elDivOptions = getPropertyInputElement("parentMaterialName");
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
let materialTargetList = [];
for (let i = 0; i < elInputs.length; ++i) {
let elInput = elInputs[i];
if (elInput.checked) {
let targetID = elInput.getAttribute("targetID");
if (elInput.getAttribute("isMaterialName") === "true") {
materialTargetList.push(MATERIAL_PREFIX_STRING + targetID);
} else {
materialTargetList.push(targetID);
}
}
}
let propertyValue = materialTargetList.join(",");
if (propertyValue.length > 1) {
propertyValue = "[" + propertyValue + "]";
}
updateProperty("parentMaterialName", propertyValue, false);
}
function materialTargetPropertyUpdate(propertyValue) {
let elDivOptions = getPropertyInputElement("parentMaterialName");
let elInputs = elDivOptions.getElementsByClassName("materialTargetInput");
if (propertyValue.startsWith('[')) {
propertyValue = propertyValue.substring(1, propertyValue.length);
}
if (propertyValue.endsWith(']')) {
propertyValue = propertyValue.substring(0, propertyValue.length - 1);
}
let materialTargets = propertyValue.split(",");
for (let i = 0; i < elInputs.length; ++i) {
let elInput = elInputs[i];
let targetID = elInput.getAttribute("targetID");
let materialTargetName = targetID;
if (elInput.getAttribute("isMaterialName") === "true") {
materialTargetName = MATERIAL_PREFIX_STRING + targetID;
}
elInput.checked = materialTargets.indexOf(materialTargetName) >= 0;
}
elDivOptions.propertyValue = propertyValue;
}
function roundAndFixNumber(number, propertyData) {
let result = number;
if (propertyData.round !== undefined) {
result = Math.round(result * propertyData.round) / propertyData.round;
}
if (propertyData.decimals !== undefined) {
return result.toFixed(propertyData.decimals)
}
return result;
}
function applyInputNumberPropertyModifiers(number, propertyData) {
const multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1;
return roundAndFixNumber(number / multiplier, propertyData);
}
function applyOutputNumberPropertyModifiers(number, propertyData) {
const multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1;
return roundAndFixNumber(number * multiplier, propertyData);
}
const areSetsEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value));
function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
const previouslySelectedEntityIDs = selectedEntityIDs;
currentSelections = selections;
selectedEntityIDs = new Set(selections.map(selection => selection.id));
const multipleSelections = currentSelections.length > 1;
const hasSelectedEntityChanged = !areSetsEqual(selectedEntityIDs, previouslySelectedEntityIDs);
if (selections.length === 1) {
if (maSelectedId !== selections[0].id) {
closeMaterialAssistant();
}
maSelectedId = selections[0].id;
if (selections[0].properties.type === "Zone") {
skyboxColorForCopy = selections[0].properties.skybox.color;
} else {
skyboxColorForCopy = undefined;
}
} else {
closeMaterialAssistant();
maSelectedId = "";
skyboxColorForCopy = undefined;
}
requestZoneList();
if (selections.length === 0) {
deleteJSONEditor();
deleteJSONMaterialEditor();
deleteJSONParticleUpdateEditor();
deleteJSONParticleRenderEditor();
resetProperties();
showGroupsForType("None");
let elIcon = properties.type.elSpan;
elIcon.innerText = NO_SELECTION;
elIcon.style.display = 'inline-block';
getPropertyInputElement("userData").value = "";
showUserDataTextArea();
showSaveUserDataButton();
showNewJSONEditorButton();
getPropertyInputElement("materialData").value = "";
showMaterialDataTextArea();
showSaveMaterialDataButton();
showNewJSONMaterialEditorButton();
getPropertyInputElement("particleUpdateData").value = "";
showParticleUpdateDataTextArea();
showSaveParticleUpdateDataButton();
showNewJSONParticleUpdateEditorButton();
getPropertyInputElement("particleRenderData").value = "";
showParticleRenderDataTextArea();
showSaveParticleRenderDataButton();
showNewJSONParticleRenderEditorButton();
setCopyPastePositionAndRotationAvailability (selections.length, true);
disableProperties();
setParentIdNavigationAvailable(selections.length);
} else {
let entityHostType = selections[0].properties.entityHostType;
if (!isPropertiesToolUpdate && !hasSelectedEntityChanged && document.hasFocus()) {
// in case the selection has not changed and we still have focus on the properties page,
// we will ignore the event.
return;
}
if (hasSelectedEntityChanged) {
closeCreateChildEntityAssistant();
if (!multipleSelections) {
resetServerScriptStatus();
}
}
const doSelectElement = !hasSelectedEntityChanged;
// Get unique entity types, and convert the types Sphere and Box to Shape
const shapeTypes = ["Sphere", "Box"];
const entityTypes = [...new Set(currentSelections.map(a =>
shapeTypes.includes(a.properties.type) ? "Shape" : a.properties.type))];
const shownGroups = getGroupsForTypes(entityTypes);
showGroupsForTypes(entityTypes);
showOnTheSamePage(entityTypes);
const lockedMultiValue = getMultiplePropertyValue('locked');
if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
disableProperties();
getPropertyInputElement('locked').removeAttribute('disabled');
setCopyPastePositionAndRotationAvailability (selections.length, true);
setParentIdNavigationAvailable(selections.length);
} else {
enableProperties();
disableSaveUserDataButton();
disableSaveMaterialDataButton();
disableSaveParticleUpdateDataButton();
disableSaveParticleRenderDataButton();
setCopyPastePositionAndRotationAvailability (selections.length, false);
setParentIdNavigationAvailable(selections.length);
}
Object.entries(properties).forEach(function([propertyID, property]) {
const propertyData = property.data;
const propertyName = property.name;
let propertyMultiValue = getMultiplePropertyValue(propertyName);
let isMultiDiffValue = propertyMultiValue.isMultiDiffValue;
let propertyValue = propertyMultiValue.value;
if (propertyData.selectionVisibility !== undefined) {
let visibility = propertyData.selectionVisibility;
let propertyVisible = true;
if (!multipleSelections) {
propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.SINGLE_SELECTION);
} else if (isMultiDiffValue) {
propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.MULTI_DIFF_SELECTIONS);
} else {
propertyVisible = isFlagSet(visibility, PROPERTY_SELECTION_VISIBILITY.MULTIPLE_SELECTIONS);
}
setPropertyVisibility(property, propertyVisible);
}
const isSubProperty = propertyData.subPropertyOf !== undefined;
if (propertyValue === undefined && !isMultiDiffValue && !isSubProperty) {
if (propertyData.type !== "childList") {
return;
}
}
if (!shownGroups.includes(property.group_id)) {
const WANT_DEBUG_SHOW_HIDDEN_FROM_GROUPS = false;
if (WANT_DEBUG_SHOW_HIDDEN_FROM_GROUPS) {
console.log("Skipping property " + property.data.label + " [" + property.name +
"] from hidden group " + property.group_id);
}
return;
}
if (propertyName === "type") {
propertyValue = entityTypes.length > 1 ? "Multiple" : propertyMultiValue.values[0];
}
switch (propertyData.type) {
case 'string': {
if (isMultiDiffValue) {
if (propertyData.readOnly && propertyData.multiDisplayMode
&& propertyData.multiDisplayMode === PROPERTY_MULTI_DISPLAY_MODE.COMMA_SEPARATED_VALUES) {
property.elInput.value = propertyMultiValue.values.join(", ");
} else {
property.elInput.classList.add('multi-diff');
property.elInput.value = "";
}
if (propertyName === "id") {
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_DOMAIN;
}
} else {
property.elInput.classList.remove('multi-diff');
property.elInput.value = propertyValue;
if (propertyName === "name" || propertyName === "id") {
if (selections.length === 1) {
switch (entityHostType) {
case "domain":
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_DOMAIN;
break;
case "avatar":
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_AVATAR;
break;
case "local":
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_LOCAL;
break;
default:
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_DOMAIN;
}
} else {
property.elInput.style.color = ENTITY_HOST_TYPE_COLOR_DOMAIN;
}
}
}
break;
}
case 'bool': {
const inverse = propertyData.inverse !== undefined ? propertyData.inverse : false;
if (isSubProperty) {
let subPropertyMultiValue = getMultiplePropertyValue(propertyData.subPropertyOf);
let propertyValue = subPropertyMultiValue.value;
isMultiDiffValue = subPropertyMultiValue.isMultiDiffValue;
if (isMultiDiffValue) {
let detailedSubProperty = getDetailedSubPropertyMPVDiff(subPropertyMultiValue, propertyName);
property.elInput.checked = detailedSubProperty.isChecked;
property.elInput.classList.toggle('multi-diff', detailedSubProperty.isMultiDiff);
} else {
let subProperties = propertyValue.split(",");
let subPropertyValue = subProperties.indexOf(propertyName) > -1;
property.elInput.checked = inverse ? !subPropertyValue : subPropertyValue;
property.elInput.classList.remove('multi-diff');
}
} else {
if (isMultiDiffValue) {
property.elInput.checked = false;
} else {
property.elInput.checked = inverse ? !propertyValue : propertyValue;
}
property.elInput.classList.toggle('multi-diff', isMultiDiffValue);
}
break;
}
case 'number': {
property.elInput.value = isMultiDiffValue ? "" : propertyValue;
property.elInput.classList.toggle('multi-diff', isMultiDiffValue);
break;
}
case 'number-draggable': {
let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData);
property.elNumber.setValue(detailedNumberDiff.averagePerPropertyComponent[0], detailedNumberDiff.propertyComponentDiff[0]);
break;
}
case 'rect': {
let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData);
property.elNumberX.setValue(detailedNumberDiff.averagePerPropertyComponent.x, detailedNumberDiff.propertyComponentDiff.x);
property.elNumberY.setValue(detailedNumberDiff.averagePerPropertyComponent.y, detailedNumberDiff.propertyComponentDiff.y);
property.elNumberWidth.setValue(detailedNumberDiff.averagePerPropertyComponent.width, detailedNumberDiff.propertyComponentDiff.width);
property.elNumberHeight.setValue(detailedNumberDiff.averagePerPropertyComponent.height, detailedNumberDiff.propertyComponentDiff.height);
break;
}
case 'vec3':
case 'vec2': {
let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData);
property.elNumberX.setValue(detailedNumberDiff.averagePerPropertyComponent.x, detailedNumberDiff.propertyComponentDiff.x);
property.elNumberY.setValue(detailedNumberDiff.averagePerPropertyComponent.y, detailedNumberDiff.propertyComponentDiff.y);
if (property.elNumberZ !== undefined) {
property.elNumberZ.setValue(detailedNumberDiff.averagePerPropertyComponent.z, detailedNumberDiff.propertyComponentDiff.z);
}
break;
}
case 'color': {
let displayColor = propertyMultiValue.isMultiDiffValue ? propertyMultiValue.values[0] : propertyValue;
property.elColorPicker.style.backgroundColor = "rgb(" + displayColor.red + "," +
displayColor.green + "," +
displayColor.blue + ")";
property.elColorPicker.classList.toggle('multi-diff', propertyMultiValue.isMultiDiffValue);
if (hasSelectedEntityChanged && $(property.elColorPicker).attr('active') === 'true') {
// Set the color picker inactive before setting the color,
// otherwise an update will be sent directly after setting it here.
$(property.elColorPicker).attr('active', 'false');
colorPickers['#' + property.elementID].colpickSetColor({
"r": displayColor.red,
"g": displayColor.green,
"b": displayColor.blue
});
$(property.elColorPicker).attr('active', 'true');
}
property.elNumberR.setValue(displayColor.red);
property.elNumberG.setValue(displayColor.green);
property.elNumberB.setValue(displayColor.blue);
break;
}
case 'vec3rgb': {
let detailedNumberDiff = getDetailedNumberMPVDiff(propertyMultiValue, propertyData);
property.elNumberR.setValue(detailedNumberDiff.averagePerPropertyComponent.red, detailedNumberDiff.propertyComponentDiff.red);
property.elNumberG.setValue(detailedNumberDiff.averagePerPropertyComponent.green, detailedNumberDiff.propertyComponentDiff.green);
property.elNumberB.setValue(detailedNumberDiff.averagePerPropertyComponent.blue, detailedNumberDiff.propertyComponentDiff.blue);
break;
}
case 'dropdown': {
property.elInput.classList.toggle('multi-diff', isMultiDiffValue);
property.elInput.value = isMultiDiffValue ? "" : propertyValue;
setDropdownText(property.elInput);
break;
}
case 'textarea':
case 'code': {
property.elInput.value = propertyValue;
setTextareaScrolling(property.elInput);
break;
}
case 'multipleZonesSelection': {
property.elInput.value = JSON.stringify(propertyValue);
if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
setZonesSelectionData(property.elInput, false);
} else {
setZonesSelectionData(property.elInput, true);
}
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 'zonesCoefficient': {
property.elInput.value = JSON.stringify(propertyValue);
if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
setZonesCoefficientUi(property.elInput.id, false);
} else {
setZonesCoefficientUi(property.elInput.id, true);
}
break;
}
case 'childList': {
let parentID = selections[0].properties.parentID;
if (selections.length !== 1 || parentID === UUID_NONE) {
parentID = "";
}
setChildListData(property.elInput, propertyValue, parentID, entityHostType);
break;
}
case 'icon': {
property.elSpan.innerHTML = propertyData.icons[propertyValue];
property.elSpan.style.display = "inline-block";
break;
}
case 'texture': {
property.elInput.value = isMultiDiffValue ? "" : propertyValue;
property.elInput.classList.toggle('multi-diff', isMultiDiffValue);
if (isMultiDiffValue) {
property.elInput.setMultipleValues();
} else {
property.elInput.imageLoad(property.elInput.value);
}
break;
}
case 'dynamic-multiselect': {
if (!isMultiDiffValue && property.data.propertyUpdate) {
property.data.propertyUpdate(propertyValue);
}
break;
}
}
let showPropertyRules = property.showPropertyRules;
if (showPropertyRules !== undefined) {
for (let propertyToShow in showPropertyRules) {
let showIfThisPropertyValue = showPropertyRules[propertyToShow];
let show = String(propertyValue) === String(showIfThisPropertyValue);
showPropertyElement(propertyToShow, show);
}
}
});
updateVisibleSpaceModeProperties();
let userDataMultiValue = getMultiplePropertyValue("userData");
let userDataTextArea = getPropertyInputElement("userData");
let json = null;
if (!userDataMultiValue.isMultiDiffValue) {
try {
json = JSON.parse(userDataMultiValue.value);
} catch (e) {
}
}
if (json !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
if (editor === null) {
createJSONEditor();
}
userDataTextArea.classList.remove('multi-diff');
setEditorJSON(json);
showSaveUserDataButton();
hideUserDataTextArea();
hideNewJSONEditorButton();
hideUserDataSaved();
} else {
// normal text
deleteJSONEditor();
userDataTextArea.classList.toggle('multi-diff', userDataMultiValue.isMultiDiffValue);
userDataTextArea.value = userDataMultiValue.isMultiDiffValue ? "" : userDataMultiValue.value;
showUserDataTextArea();
showNewJSONEditorButton();
hideSaveUserDataButton();
hideUserDataSaved();
}
let materialDataMultiValue = getMultiplePropertyValue("materialData");
let materialDataTextArea = getPropertyInputElement("materialData");
let materialJSON = null;
if (!materialDataMultiValue.isMultiDiffValue) {
try {
materialJSON = JSON.parse(materialDataMultiValue.value);
} catch (e) {
}
}
if (materialJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
if (materialEditor === null) {
createJSONMaterialEditor();
}
materialDataTextArea.classList.remove('multi-diff');
setMaterialEditorJSON(materialJSON);
showSaveMaterialDataButton();
hideMaterialDataTextArea();
hideNewJSONMaterialEditorButton();
hideMaterialDataSaved();
} else {
// normal text
deleteJSONMaterialEditor();
materialDataTextArea.classList.toggle('multi-diff', materialDataMultiValue.isMultiDiffValue);
materialDataTextArea.value = materialDataMultiValue.isMultiDiffValue ? "" : materialDataMultiValue.value;
showMaterialDataTextArea();
showNewJSONMaterialEditorButton();
hideSaveMaterialDataButton();
hideMaterialDataSaved();
}
maGetMaterialDataAssistantAvailability(materialJSON);
if (hasSelectedEntityChanged && selections.length === 1 && entityTypes[0] === "Material") {
requestMaterialTarget();
}
let particleUpdateDataMultiValue = getMultiplePropertyValue("particleUpdateData");
let particleUpdateDataTextArea = getPropertyInputElement("particleUpdateData");
let particleUpdateJSON = null;
if (!particleUpdateDataMultiValue.isMultiDiffValue) {
try {
particleUpdateJSON = JSON.parse(particleUpdateDataMultiValue.value);
} catch (e) {
}
}
if (particleUpdateJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
if (particleUpdateEditor === null) {
createJSONParticleUpdateEditor();
}
particleUpdateDataTextArea.classList.remove('multi-diff');
setParticleUpdateEditorJSON(particleUpdateJSON);
showSaveParticleUpdateDataButton();
hideParticleUpdateDataTextArea();
hideNewJSONParticleUpdateEditorButton();
hideParticleUpdateDataSaved();
} else {
// normal text
deleteJSONParticleUpdateEditor();
particleUpdateDataTextArea.classList.toggle('multi-diff', particleUpdateDataMultiValue.isMultiDiffValue);
particleUpdateDataTextArea.value = particleUpdateDataMultiValue.isMultiDiffValue ? "" : particleUpdateDataMultiValue.value;
showParticleUpdateDataTextArea();
showNewJSONParticleUpdateEditorButton();
hideSaveParticleUpdateDataButton();
hideParticleUpdateDataSaved();
}
let particleRenderDataMultiValue = getMultiplePropertyValue("particleRenderData");
let particleRenderDataTextArea = getPropertyInputElement("particleRenderData");
let particleRenderJSON = null;
if (!particleRenderDataMultiValue.isMultiDiffValue) {
try {
particleRenderJSON = JSON.parse(particleRenderDataMultiValue.value);
} catch (e) {
}
}
if (particleRenderJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
if (particleRenderEditor === null) {
createJSONParticleRenderEditor();
}
particleRenderDataTextArea.classList.remove('multi-diff');
setParticleRenderEditorJSON(particleRenderJSON);
showSaveParticleRenderDataButton();
hideParticleRenderDataTextArea();
hideNewJSONParticleRenderEditorButton();
hideParticleRenderDataSaved();
} else {
// normal text
deleteJSONParticleRenderEditor();
particleRenderDataTextArea.classList.toggle('multi-diff', particleRenderDataMultiValue.isMultiDiffValue);
particleRenderDataTextArea.value = particleRenderDataMultiValue.isMultiDiffValue ? "" : particleRenderDataMultiValue.value;
showParticleRenderDataTextArea();
showNewJSONParticleRenderEditorButton();
hideSaveParticleRenderDataButton();
hideParticleRenderDataSaved();
}
let activeElement = document.activeElement;
if (doSelectElement && typeof activeElement.select !== "undefined") {
activeElement.select();
}
}
}
function loaded() {
openEventBridge(function() {
let elPropertiesList = document.getElementById("properties-pages");
let elTabs = document.getElementById("tabs");
GROUPS.forEach(function(group) {
let elGroup;
elGroup = document.createElement('div');
elGroup.className = 'section ' + "major";
elGroup.setAttribute("id", "properties-" + group.id);
elPropertiesList.appendChild(elGroup);
if (group.label !== undefined) {
let elLegend = document.createElement('div');
elLegend.className = "tab-section-header";
elLegend.appendChild(createElementFromHTML(`
${group.label}
`));
elGroup.appendChild(elLegend);
elTabs.appendChild(createElementFromHTML(''));
}
group.properties.forEach(function(propertyData) {
let propertyType = propertyData.type;
let propertyID = propertyData.propertyID;
let propertyName = propertyData.propertyName !== undefined ? propertyData.propertyName : propertyID;
let propertySpaceMode = propertyData.spaceMode !== undefined ? propertyData.spaceMode : PROPERTY_SPACE_MODE.ALL;
let propertyElementID = "property-" + propertyID;
propertyElementID = propertyElementID.replace('.', '-');
let elContainer, elLabel;
if (propertyData.replaceID === undefined) {
// Create subheader, or create new property and append it.
if (propertyType === "sub-header") {
elContainer = createElementFromHTML(
`
${propertyData.label}
`);
} else {
elContainer = document.createElement('div');
elContainer.setAttribute("id", "div-" + propertyElementID);
elContainer.className = 'property container';
}
if (group.twoColumn && propertyData.column !== undefined && propertyData.column !== -1) {
let columnName = group.id + "column" + propertyData.column;
let elColumn = document.getElementById(columnName);
if (!elColumn) {
let columnDivName = group.id + "columnDiv";
let elColumnDiv = document.getElementById(columnDivName);
if (!elColumnDiv) {
elColumnDiv = document.createElement('div');
elColumnDiv.className = "two-column";
elColumnDiv.setAttribute("id", group.id + "columnDiv");
elGroup.appendChild(elColumnDiv);
}
elColumn = document.createElement('fieldset');
elColumn.className = "column";
elColumn.setAttribute("id", columnName);
elColumnDiv.appendChild(elColumn);
}
elColumn.appendChild(elContainer);
} else {
elGroup.appendChild(elContainer);
}
let labelText = propertyData.label !== undefined ? propertyData.label : "";
let className = '';
if (propertyData.indentedLabel || propertyData.showPropertyRule !== undefined) {
className = 'indented';
}
elLabel = createElementFromHTML(
``);
elContainer.appendChild(elLabel);
} else {
elContainer = document.getElementById(propertyData.replaceID);
}
if (elLabel) {
createAppTooltip.registerTooltipElement(elLabel.childNodes[0], propertyID, propertyName);
}
let elProperty = createElementFromHTML('');
elContainer.appendChild(elProperty);
if (propertyType === 'triple') {
elProperty.className = 'flex-row';
for (let i = 0; i < propertyData.properties.length; ++i) {
let innerPropertyData = propertyData.properties[i];
let elWrapper = createElementFromHTML('');
elProperty.appendChild(elWrapper);
let propertyID = innerPropertyData.propertyID;
let propertyName = innerPropertyData.propertyName !== undefined ? innerPropertyData.propertyName : propertyID;
let propertyElementID = "property-" + propertyID;
propertyElementID = propertyElementID.replace('.', '-');
let property = createProperty(innerPropertyData, propertyElementID, propertyName, propertyID, elWrapper);
property.isParticleProperty = group.id.includes("particles");
property.elContainer = elContainer;
property.spaceMode = propertySpaceMode;
property.group_id = group.id;
let elLabel = createElementFromHTML(`
${innerPropertyData.label}
`);
createAppTooltip.registerTooltipElement(elLabel, propertyID, propertyName);
elWrapper.appendChild(elLabel);
if (property.type !== 'placeholder') {
properties[propertyID] = property;
}
if (innerPropertyData.type === 'number' || innerPropertyData.type === 'number-draggable') {
propertyRangeRequests.push(propertyID);
}
}
} else {
let property = createProperty(propertyData, propertyElementID, propertyName, propertyID, elProperty);
property.isParticleProperty = group.id.includes("particles");
property.elContainer = elContainer;
property.spaceMode = propertySpaceMode;
property.group_id = group.id;
if (property.type !== 'placeholder') {
properties[propertyID] = property;
}
if (propertyData.type === 'number' || propertyData.type === 'number-draggable' ||
propertyData.type === 'vec2' || propertyData.type === 'vec3' ||
propertyData.type === 'rect' || propertyData.type === 'vec3rgb') {
propertyRangeRequests.push(propertyID);
}
let showPropertyRule = propertyData.showPropertyRule;
if (showPropertyRule !== undefined) {
let dependentProperty = Object.keys(showPropertyRule)[0];
let dependentPropertyValue = showPropertyRule[dependentProperty];
if (properties[dependentProperty] === undefined) {
properties[dependentProperty] = {};
}
if (properties[dependentProperty].showPropertyRules === undefined) {
properties[dependentProperty].showPropertyRules = {};
}
properties[dependentProperty].showPropertyRules[propertyID] = dependentPropertyValue;
}
}
});
elGroups[group.id] = elGroup;
});
updateVisibleSpaceModeProperties();
requestZoneList();
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.type === "server_script_status" && selectedEntityIDs.size === 1) {
let elServerScriptError = document.getElementById("property-serverScripts-error");
let elServerScriptStatus = document.getElementById("property-serverScripts-status");
elServerScriptError.value = data.errorInfo;
// If we just set elServerScriptError's display to block or none, we still end up with
// it's parent contributing 21px bottom padding even when elServerScriptError is display:none.
// So set it's parent to block or none
elServerScriptError.parentElement.style.display = data.errorInfo ? "block" : "none";
if (data.statusRetrieved === false) {
elServerScriptStatus.innerText = "Failed to retrieve status";
} else if (data.isRunning) {
elServerScriptStatus.innerText = ENTITY_SCRIPT_STATUS[data.status] || data.status;
} else {
elServerScriptStatus.innerText = NOT_RUNNING_SCRIPT_STATUS;
}
} else if (data.type === "update" && data.selections) {
if (data.spaceMode !== undefined) {
currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD;
}
handleEntitySelectionUpdate(data.selections, data.isPropertiesToolUpdate);
} else if (data.type === 'tooltipsReply') {
createAppTooltip.setIsEnabled(!data.hmdActive);
createAppTooltip.setTooltipData(data.tooltips);
} else if (data.type === 'hmdActiveChanged') {
createAppTooltip.setIsEnabled(!data.hmdActive);
} else if (data.type === 'setSpaceMode') {
currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD;
updateVisibleSpaceModeProperties();
} else if (data.type === 'propertyRangeReply') {
let propertyRanges = data.propertyRanges;
for (let property in propertyRanges) {
let propertyRange = propertyRanges[property];
if (propertyRange !== undefined) {
let propertyData = properties[property].data;
let multiplier = propertyData.multiplier;
if (propertyData.min === undefined && propertyRange.minimum !== "") {
propertyData.min = propertyRange.minimum;
if (multiplier !== undefined) {
propertyData.min /= multiplier;
}
}
if (propertyData.max === undefined && propertyRange.maximum !== "") {
propertyData.max = propertyRange.maximum;
if (multiplier !== undefined) {
propertyData.max /= multiplier;
}
}
switch (propertyData.type) {
case 'number':
updateNumberMinMax(properties[property]);
break;
case 'number-draggable':
updateNumberDraggableMinMax(properties[property]);
break;
case 'vec3':
case 'vec2':
updateVectorMinMax(properties[property]);
break;
case 'vec3rgb':
updateVectorMinMax(properties[property]);
break;
case 'rect':
updateRectMinMax(properties[property]);
break;
}
}
}
} else if (data.type === 'materialTargetReply') {
if (data.entityID === getFirstSelectedID()) {
setMaterialTargetData(data.materialTargetData);
}
} else if (data.type === 'zoneListRequest') {
zonesList = data.zones;
} else if (data.type === 'urlPermissionChanged') {
canViewAssetURLs = data.canViewAssetURLs;
Object.entries(properties).forEach(function ([propertyID, property]) {
if (property.data.placeholder && property.data.placeholder === "URL") {
if (!canViewAssetURLs) {
property.elInput.value = "";
}
property.elInput.placeholder = canViewAssetURLs ? property.data.placeholder : "You don't have permission to view this URL";
}
});
}
});
// Request tooltips and property ranges as soon as we can process a reply:
EventBridge.emitWebEvent(JSON.stringify({ type: 'tooltipsRequest' }));
EventBridge.emitWebEvent(JSON.stringify({ type: 'propertyRangeRequest', properties: propertyRangeRequests }));
}
// Server Script Status
let elServerScriptStatusOuter = document.getElementById('div-property-serverScriptStatus');
let elServerScriptStatusContainer = document.getElementById('div-property-serverScriptStatus').childNodes[1];
let serverScriptStatusElementID = 'property-serverScripts-status';
createAppTooltip.registerTooltipElement(elServerScriptStatusOuter.childNodes[0], "serverScriptsStatus");
let elServerScriptStatus = document.createElement('div');
elServerScriptStatus.setAttribute("id", serverScriptStatusElementID);
elServerScriptStatusContainer.appendChild(elServerScriptStatus);
// Server Script Error
let elServerScripts = getPropertyInputElement("serverScripts");
let elDiv = document.createElement('div');
elDiv.className = "property";
let elServerScriptError = document.createElement('textarea');
let serverScriptErrorElementID = 'property-serverScripts-error';
elServerScriptError.setAttribute("id", serverScriptErrorElementID);
elDiv.appendChild(elServerScriptError);
elServerScriptStatusContainer.appendChild(elDiv);
let elScript = getPropertyInputElement("script");
elScript.parentNode.className = "url refresh";
elServerScripts.parentNode.className = "url refresh";
let elParentID = getPropertyInputElement("parentID");
elParentID.parentNode.className = "url refresh";
// User Data
let userDataProperty = properties["userData"];
let elUserData = userDataProperty.elInput;
let userDataElementID = userDataProperty.elementID;
elDiv = elUserData.parentNode;
let elUserDataEditor = document.createElement('div');
elUserDataEditor.setAttribute("id", userDataElementID + "-editor");
let elUserDataEditorStatus = document.createElement('div');
elUserDataEditorStatus.setAttribute("id", userDataElementID + "-editorStatus");
let elUserDataSaved = document.createElement('span');
elUserDataSaved.setAttribute("id", userDataElementID + "-saved");
elUserDataSaved.innerText = "Saved!";
elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elUserDataSaved);
elDiv.insertBefore(elUserDataEditor, elUserData);
elDiv.insertBefore(elUserDataEditorStatus, elUserData);
// Material Data
let materialDataProperty = properties["materialData"];
let elMaterialData = materialDataProperty.elInput;
let materialDataElementID = materialDataProperty.elementID;
elDiv = elMaterialData.parentNode;
let elMaterialDataEditor = document.createElement('div');
elMaterialDataEditor.setAttribute("id", materialDataElementID + "-editor");
let elMaterialDataEditorStatus = document.createElement('div');
elMaterialDataEditorStatus.setAttribute("id", materialDataElementID + "-editorStatus");
let elMaterialDataSaved = document.createElement('span');
elMaterialDataSaved.setAttribute("id", materialDataElementID + "-saved");
elMaterialDataSaved.innerText = "Saved!";
elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elMaterialDataSaved);
elDiv.insertBefore(elMaterialDataEditor, elMaterialData);
elDiv.insertBefore(elMaterialDataEditorStatus, elMaterialData);
// Particle Update + Render Data
let particleUpdateDataProperty = properties["particleUpdateData"];
let elParticleUpdateData = particleUpdateDataProperty.elInput;
let particleUpdateDataElementID = particleUpdateDataProperty.elementID;
elDiv = elParticleUpdateData.parentNode;
let elParticleUpdateDataEditor = document.createElement('div');
elParticleUpdateDataEditor.setAttribute("id", particleUpdateDataElementID + "-editor");
let elParticleUpdateDataEditorStatus = document.createElement('div');
elParticleUpdateDataEditorStatus.setAttribute("id", particleUpdateDataElementID + "-editorStatus");
let elParticleUpdateDataSaved = document.createElement('span');
elParticleUpdateDataSaved.setAttribute("id", particleUpdateDataElementID + "-saved");
elParticleUpdateDataSaved.innerText = "Saved!";
elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elParticleUpdateDataSaved);
elDiv.insertBefore(elParticleUpdateDataEditor, elParticleUpdateData);
elDiv.insertBefore(elParticleUpdateDataEditorStatus, elParticleUpdateData);
let particleRenderDataProperty = properties["particleRenderData"];
let elParticleRenderData = particleRenderDataProperty.elInput;
let particleRenderDataElementID = particleRenderDataProperty.elementID;
elDiv = elParticleRenderData.parentNode;
let elParticleRenderDataEditor = document.createElement('div');
elParticleRenderDataEditor.setAttribute("id", particleRenderDataElementID + "-editor");
let elParticleRenderDataEditorStatus = document.createElement('div');
elParticleRenderDataEditorStatus.setAttribute("id", particleRenderDataElementID + "-editorStatus");
let elParticleRenderDataSaved = document.createElement('span');
elParticleRenderDataSaved.setAttribute("id", particleRenderDataElementID + "-saved");
elParticleRenderDataSaved.innerText = "Saved!";
elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elParticleRenderDataSaved);
elDiv.insertBefore(elParticleRenderDataEditor, elParticleRenderData);
elDiv.insertBefore(elParticleRenderDataEditorStatus, elParticleRenderData);
// Textarea scrollbars
let elTextareas = document.getElementsByTagName("TEXTAREA");
let textareaOnChangeEvent = function(event) {
setTextareaScrolling(event.target);
};
for (let textAreaIndex = 0, numTextAreas = elTextareas.length; textAreaIndex < numTextAreas; ++textAreaIndex) {
let curTextAreaElement = elTextareas[textAreaIndex];
setTextareaScrolling(curTextAreaElement);
curTextAreaElement.addEventListener("input", textareaOnChangeEvent, false);
curTextAreaElement.addEventListener("change", textareaOnChangeEvent, false);
/* FIXME: Detect and update textarea scrolling attribute on resize. Unfortunately textarea doesn't have a resize
event; mouseup is a partial stand-in but doesn't handle resizing if mouse moves outside textarea rectangle. */
curTextAreaElement.addEventListener("mouseup", textareaOnChangeEvent, false);
}
// Dropdowns
// For each dropdown the following replacement is created in place of the original dropdown...
// Structure created:
//
//
display textcarat
//
//
//
0) {
let el = elDropdowns[0];
el.parentNode.removeChild(el);
elDropdowns = document.getElementsByTagName("select");
}
const KEY_CODES = {
BACKSPACE: 8,
DELETE: 46
};
document.addEventListener("keyup", function (keyUpEvent) {
const FILTERED_NODE_NAMES = ["INPUT", "TEXTAREA"];
if (FILTERED_NODE_NAMES.includes(keyUpEvent.target.nodeName)) {
return;
}
if (elUserDataEditor.contains(keyUpEvent.target) || elMaterialDataEditor.contains(keyUpEvent.target) || elParticleUpdateDataEditor.contains(keyUpEvent.target)
|| elParticleRenderDataEditor.contains(keyUpEvent.target)) {
return;
}
let {code, key, keyCode, altKey, ctrlKey, metaKey, shiftKey} = keyUpEvent;
let controlKey = window.navigator.platform.startsWith("Mac") ? metaKey : ctrlKey;
let keyCodeString;
switch (keyCode) {
case KEY_CODES.DELETE:
keyCodeString = "Delete";
break;
case KEY_CODES.BACKSPACE:
keyCodeString = "Backspace";
break;
default:
keyCodeString = String.fromCharCode(keyUpEvent.keyCode);
break;
}
EventBridge.emitWebEvent(JSON.stringify({
type: 'keyUpEvent',
keyUpEvent: {
code,
key,
keyCode,
keyCodeString,
altKey,
controlKey,
shiftKey,
}
}));
}, false);
window.onblur = function() {
// Fake a change event
let ev = document.createEvent("HTMLEvents");
ev.initEvent("change", true, true);
document.activeElement.dispatchEvent(ev);
};
// For input and textarea elements, select all of the text on focus
let els = document.querySelectorAll("input, textarea");
for (let i = 0; i < els.length; ++i) {
els[i].onfocus = function (e) {
e.target.select();
};
}
bindAllNonJSONEditorElements();
showGroupsForType("None");
showPage("base");
resetProperties();
disableProperties();
});
augmentSpinButtons();
disableDragDrop();
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
document.addEventListener("contextmenu", function(event) {
event.preventDefault();
}, false);
setTimeout(function() {
EventBridge.emitWebEvent(JSON.stringify({ type: 'propertiesPageReady' }));
}, 1000);
}
function showOnTheSamePage(entityType) {
let numberOfTypes = entityType.length;
let matchingType = 0;
for (let i = 0; i < numberOfTypes; i++) {
if (GROUPS_PER_TYPE[entityType[i]].includes(currentTab)) {
matchingType = matchingType + 1;
}
}
if (matchingType !== numberOfTypes) {
currentTab = "base";
}
showPage(currentTab);
}
function showPage(id) {
currentTab = id;
Object.entries(elGroups).forEach(([groupKey, elGroup]) => {
if (groupKey === id) {
elGroup.style.display = "block";
document.getElementById("tab-" + groupKey).style.backgroundColor = "#2E2E2E";
} else {
elGroup.style.display = "none";
document.getElementById("tab-" + groupKey).style.backgroundColor = "#404040";
}
});
}