} [entityIDsToUpdate] - Entity IDs to update materialData for.
+ */
+function saveJSONMaterialData(noUpdate, entityIDsToUpdate) {
+ setMaterialDataFromEditor(noUpdate, entityIDsToUpdate ? entityIDsToUpdate : selectedEntityIDs);
$('#property-materialData-saved').show();
$('#property-materialData-button-save').attr('disabled', true);
if (savedMaterialJSONTimer !== null) {
@@ -3101,13 +3364,12 @@ function bindAllNonJSONEditorElements() {
if (e.target.id === "property-userData-button-edit" || e.target.id === "property-userData-button-clear" ||
e.target.id === "property-materialData-button-edit" || e.target.id === "property-materialData-button-clear") {
return;
- } else {
- if ($('#property-userData-editor').css('height') !== "0px") {
- saveUserData();
- }
- if ($('#property-materialData-editor').css('height') !== "0px") {
- saveMaterialData();
- }
+ }
+ if ($('#property-userData-editor').css('height') !== "0px") {
+ saveUserData();
+ }
+ if ($('#property-materialData-editor').css('height') !== "0px") {
+ saveMaterialData();
}
});
}
@@ -3140,14 +3402,14 @@ function toggleDropdown(event) {
}
function closeAllDropdowns() {
- elDropdowns = document.querySelectorAll("div.dropdown > dl");
+ let elDropdowns = document.querySelectorAll("div.dropdown > dl");
for (let i = 0; i < elDropdowns.length; ++i) {
elDropdowns[i].setAttribute('dropped', 'false');
}
}
function setDropdownValue(event) {
- let dt = event.target.parentNode.parentNode.previousSibling;
+ let dt = event.target.parentNode.parentNode.previousSibling.previousSibling;
dt.value = event.target.getAttribute("value");
dt.firstChild.textContent = event.target.textContent;
@@ -3174,7 +3436,10 @@ function setTextareaScrolling(element) {
*/
function requestMaterialTarget() {
- EventBridge.emitWebEvent(JSON.stringify({ type: 'materialTargetRequest', entityID: selectedEntityProperties.id }));
+ EventBridge.emitWebEvent(JSON.stringify({
+ type: 'materialTargetRequest',
+ entityID: getFirstSelectedID(),
+ }));
}
function setMaterialTargetData(materialTargetData) {
@@ -3268,7 +3533,7 @@ function sendMaterialTargetProperty() {
if (elInput.checked) {
let targetID = elInput.getAttribute("targetID");
if (elInput.getAttribute("isMaterialName") === "true") {
- materialTargetList.push("mat::" + targetID);
+ materialTargetList.push(MATERIAL_PREFIX_STRING + targetID);
} else {
materialTargetList.push(targetID);
}
@@ -3300,7 +3565,7 @@ function materialTargetPropertyUpdate(propertyValue) {
let targetID = elInput.getAttribute("targetID");
let materialTargetName = targetID;
if (elInput.getAttribute("isMaterialName") === "true") {
- materialTargetName = "mat::" + targetID;
+ materialTargetName = MATERIAL_PREFIX_STRING + targetID;
}
elInput.checked = materialTargets.indexOf(materialTargetName) >= 0;
}
@@ -3308,12 +3573,358 @@ function materialTargetPropertyUpdate(propertyValue) {
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 === 0) {
+ deleteJSONEditor();
+ deleteJSONMaterialEditor();
+
+ 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();
+
+ disableProperties();
+ } else {
+ 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) {
+ 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);
+
+ const lockedMultiValue = getMultiplePropertyValue('locked');
+
+ if (lockedMultiValue.isMultiDiffValue || lockedMultiValue.value) {
+ disableProperties();
+ getPropertyInputElement('locked').removeAttribute('disabled');
+ } else {
+ enableProperties();
+ disableSaveUserDataButton();
+ disableSaveMaterialDataButton()
+ }
+
+ const certificateIDMultiValue = getMultiplePropertyValue('certificateID');
+ const hasCertifiedInSelection = certificateIDMultiValue.isMultiDiffValue || certificateIDMultiValue.value !== "";
+
+ 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) {
+ 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 (propertyData.hideIfCertified && hasCertifiedInSelection) {
+ propertyValue = "** Certified **";
+ property.elInput.disabled = true;
+ }
+
+ 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 = "";
+ }
+ } else {
+ property.elInput.classList.remove('multi-diff');
+ property.elInput.value = propertyValue;
+ }
+ 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 'dropdown': {
+ property.elInput.classList.toggle('multi-diff', isMultiDiffValue);
+ property.elInput.value = isMultiDiffValue ? "" : propertyValue;
+ setDropdownText(property.elInput);
+ break;
+ }
+ case 'textarea': {
+ property.elInput.value = propertyValue;
+ setTextareaScrolling(property.elInput);
+ 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) {
+ 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) {
+ 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();
+ }
+
+ if (hasSelectedEntityChanged && selections.length === 1 && entityTypes[0] === "Material") {
+ requestMaterialTarget();
+ }
+
+ let activeElement = document.activeElement;
+ if (doSelectElement && typeof activeElement.select !== "undefined") {
+ activeElement.select();
+ }
+ }
+}
function loaded() {
openEventBridge(function() {
let elPropertiesList = document.getElementById("properties-list");
-
- let templatePropertyRow = document.getElementById('property-row');
GROUPS.forEach(function(group) {
let elGroup;
@@ -3420,6 +4031,7 @@ function loaded() {
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);
@@ -3438,6 +4050,7 @@ function loaded() {
property.isParticleProperty = group.id.includes("particles");
property.elContainer = elContainer;
property.spaceMode = propertySpaceMode;
+ property.group_id = group.id;
if (property.type !== 'placeholder') {
properties[propertyID] = property;
@@ -3473,7 +4086,7 @@ function loaded() {
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
data = JSON.parse(data);
- if (data.type === "server_script_status") {
+ 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;
@@ -3492,324 +4105,7 @@ function loaded() {
if (data.spaceMode !== undefined) {
currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD;
}
- if (data.selections.length === 0) {
- if (lastEntityID !== null) {
- if (editor !== null) {
- saveUserData();
- deleteJSONEditor();
- }
- if (materialEditor !== null) {
- saveMaterialData();
- deleteJSONMaterialEditor();
- }
- }
- lastEntityID = null;
-
- resetProperties();
- showGroupsForType("None");
-
- let elIcon = properties.type.elSpan;
- elIcon.innerText = NO_SELECTION;
- elIcon.style.display = 'inline-block';
-
- deleteJSONEditor();
- getPropertyInputElement("userData").value = "";
- showUserDataTextArea();
- showSaveUserDataButton();
- showNewJSONEditorButton();
-
- deleteJSONMaterialEditor();
- getPropertyInputElement("materialData").value = "";
- showMaterialDataTextArea();
- showSaveMaterialDataButton();
- showNewJSONMaterialEditorButton();
-
- disableProperties();
- } else if (data.selections.length > 1) {
- deleteJSONEditor();
- deleteJSONMaterialEditor();
-
- let selections = data.selections;
-
- let ids = [];
- let types = {};
- let numTypes = 0;
-
- for (let i = 0; i < selections.length; ++i) {
- ids.push(selections[i].id);
- let currentSelectedType = selections[i].properties.type;
- if (types[currentSelectedType] === undefined) {
- types[currentSelectedType] = 0;
- numTypes += 1;
- }
- types[currentSelectedType]++;
- }
-
- let type = "Multiple";
- if (numTypes === 1) {
- type = selections[0].properties.type;
- }
-
- resetProperties();
- showGroupsForType(type);
-
- let typeProperty = properties["type"];
- typeProperty.elSpan.innerHTML = typeProperty.data.icons[type];
- typeProperty.elSpan.style.display = "inline-block";
-
- disableProperties();
- } else {
- selectedEntityProperties = data.selections[0].properties;
-
- if (lastEntityID !== '"' + selectedEntityProperties.id + '"' && lastEntityID !== null) {
- if (editor !== null) {
- saveUserData();
- }
- if (materialEditor !== null) {
- saveMaterialData();
- }
- }
-
- let hasSelectedEntityChanged = lastEntityID !== '"' + selectedEntityProperties.id + '"';
-
- if (!data.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;
- }
-
- let doSelectElement = !hasSelectedEntityChanged;
-
- // the event bridge and json parsing handle our avatar id string differently.
- lastEntityID = '"' + selectedEntityProperties.id + '"';
-
- showGroupsForType(selectedEntityProperties.type);
-
- if (selectedEntityProperties.locked) {
- disableProperties();
- getPropertyInputElement("locked").removeAttribute('disabled');
- } else {
- enableProperties();
- disableSaveUserDataButton();
- disableSaveMaterialDataButton()
- }
-
- for (let propertyID in properties) {
- let property = properties[propertyID];
- let propertyData = property.data;
- let propertyName = property.name;
- let propertyValue = getPropertyValue(propertyName);
-
- let isSubProperty = propertyData.subPropertyOf !== undefined;
- if (propertyValue === undefined && !isSubProperty) {
- continue;
- }
-
- if (propertyData.hideIfCertified) {
- let shouldHide = selectedEntityProperties.certificateID !== "";
- if (shouldHide) {
- propertyValue = "** Certified **";
- property.elInput.disabled = true;
- }
- }
-
- let isPropertyNotNumber = false;
- switch (propertyData.type) {
- case 'number':
- case 'number-draggable':
- isPropertyNotNumber = isNaN(propertyValue) || propertyValue === null;
- break;
- case 'rect':
- case 'vec3':
- case 'vec2':
- isPropertyNotNumber = isNaN(propertyValue.x) || propertyValue.x === null;
- break;
- case 'color':
- isPropertyNotNumber = isNaN(propertyValue.red) || propertyValue.red === null;
- break;
- }
- if (isPropertyNotNumber && propertyData.fallbackProperty !== undefined) {
- propertyValue = getPropertyValue(propertyData.fallbackProperty);
- }
-
- switch (propertyData.type) {
- case 'string': {
- property.elInput.value = propertyValue;
- break;
- }
- case 'bool': {
- let inverse = propertyData.inverse !== undefined ? propertyData.inverse : false;
- if (isSubProperty) {
- let propertyValue = selectedEntityProperties[propertyData.subPropertyOf];
- let subProperties = propertyValue.split(",");
- let subPropertyValue = subProperties.indexOf(propertyName) > -1;
- property.elInput.checked = inverse ? !subPropertyValue : subPropertyValue;
- } else {
- property.elInput.checked = inverse ? !propertyValue : propertyValue;
- }
- break;
- }
- case 'number': {
- property.elInput.value = propertyValue;
- break;
- }
- case 'number-draggable': {
- let multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1;
- let value = propertyValue / multiplier;
- if (propertyData.round !== undefined) {
- value = Math.round(value.round) / propertyData.round;
- }
- property.elNumber.setValue(value);
- break;
- }
- case 'rect':
- property.elNumberX.setValue(propertyValue.x);
- property.elNumberY.setValue(propertyValue.y);
- property.elNumberWidth.setValue(propertyValue.width);
- property.elNumberHeight.setValue(propertyValue.height);
- break;
- case 'vec3':
- case 'vec2': {
- let multiplier = propertyData.multiplier !== undefined ? propertyData.multiplier : 1;
- let valueX = propertyValue.x / multiplier;
- let valueY = propertyValue.y / multiplier;
- let valueZ = propertyValue.z / multiplier;
- if (propertyData.round !== undefined) {
- valueX = Math.round(valueX * propertyData.round) / propertyData.round;
- valueY = Math.round(valueY * propertyData.round) / propertyData.round;
- valueZ = Math.round(valueZ * propertyData.round) / propertyData.round;
- }
- if (propertyData.decimals !== undefined) {
- property.elNumberX.setValue(valueX.toFixed(propertyData.decimals));
- property.elNumberY.setValue(valueY.toFixed(propertyData.decimals));
- if (property.elNumberZ !== undefined) {
- property.elNumberZ.setValue(valueZ.toFixed(propertyData.decimals));
- }
- } else {
- property.elNumberX.setValue(valueX);
- property.elNumberY.setValue(valueY);
- if (property.elNumberZ !== undefined) {
- property.elNumberZ.setValue(valueZ);
- }
- }
- break;
- }
- case 'color': {
- property.elColorPicker.style.backgroundColor = "rgb(" + propertyValue.red + "," +
- propertyValue.green + "," +
- propertyValue.blue + ")";
- 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": propertyValue.red,
- "g": propertyValue.green,
- "b": propertyValue.blue
- });
- $(property.elColorPicker).attr('active', 'true');
- }
-
- property.elNumberR.setValue(propertyValue.red);
- property.elNumberG.setValue(propertyValue.green);
- property.elNumberB.setValue(propertyValue.blue);
- break;
- }
- case 'dropdown': {
- property.elInput.value = propertyValue;
- setDropdownText(property.elInput);
- break;
- }
- case 'textarea': {
- property.elInput.value = propertyValue;
- setTextareaScrolling(property.elInput);
- break;
- }
- case 'icon': {
- property.elSpan.innerHTML = propertyData.icons[propertyValue];
- property.elSpan.style.display = "inline-block";
- break;
- }
- case 'texture': {
- property.elInput.value = propertyValue;
- property.elInput.imageLoad(property.elInput.value);
- break;
- }
- case 'dynamic-multiselect': {
- if (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 json = null;
- try {
- json = JSON.parse(selectedEntityProperties.userData);
- } catch (e) {
- // normal text
- deleteJSONEditor();
- getPropertyInputElement("userData").value = selectedEntityProperties.userData;
- showUserDataTextArea();
- showNewJSONEditorButton();
- hideSaveUserDataButton();
- hideUserDataSaved();
- }
- if (json !== null) {
- if (editor === null) {
- createJSONEditor();
- }
- setEditorJSON(json);
- showSaveUserDataButton();
- hideUserDataTextArea();
- hideNewJSONEditorButton();
- hideUserDataSaved();
- }
-
- let materialJson = null;
- try {
- materialJson = JSON.parse(selectedEntityProperties.materialData);
- } catch (e) {
- // normal text
- deleteJSONMaterialEditor();
- getPropertyInputElement("materialData").value = selectedEntityProperties.materialData;
- showMaterialDataTextArea();
- showNewJSONMaterialEditorButton();
- hideSaveMaterialDataButton();
- hideMaterialDataSaved();
- }
- if (materialJson !== null) {
- if (materialEditor === null) {
- createJSONMaterialEditor();
- }
- setMaterialEditorJSON(materialJson);
- showSaveMaterialDataButton();
- hideMaterialDataTextArea();
- hideNewJSONMaterialEditorButton();
- hideMaterialDataSaved();
- }
-
- if (hasSelectedEntityChanged && selectedEntityProperties.type === "Material") {
- requestMaterialTarget();
- }
-
- let activeElement = document.activeElement;
- if (doSelectElement && typeof activeElement.select !== "undefined") {
- activeElement.select();
- }
- }
+ handleEntitySelectionUpdate(data.selections, data.isPropertiesToolUpdate);
} else if (data.type === 'tooltipsReply') {
createAppTooltip.setIsEnabled(!data.hmdActive);
createAppTooltip.setTooltipData(data.tooltips);
@@ -3825,13 +4121,13 @@ function loaded() {
if (propertyRange !== undefined) {
let propertyData = properties[property].data;
let multiplier = propertyData.multiplier;
- if (propertyData.min === undefined && propertyRange.minimum != "") {
+ if (propertyData.min === undefined && propertyRange.minimum !== "") {
propertyData.min = propertyRange.minimum;
if (multiplier !== undefined) {
propertyData.min /= multiplier;
}
}
- if (propertyData.max === undefined && propertyRange.maximum != "") {
+ if (propertyData.max === undefined && propertyRange.maximum !== "") {
propertyData.max = propertyRange.maximum;
if (multiplier !== undefined) {
propertyData.max /= multiplier;
@@ -3855,7 +4151,7 @@ function loaded() {
}
}
} else if (data.type === 'materialTargetReply') {
- if (data.entityID === selectedEntityProperties.id) {
+ if (data.entityID === getFirstSelectedID()) {
setMaterialTargetData(data.materialTargetData);
}
}
@@ -3877,7 +4173,7 @@ function loaded() {
// Server Script Error
let elServerScripts = getPropertyInputElement("serverScripts");
- elDiv = document.createElement('div');
+ let elDiv = document.createElement('div');
elDiv.className = "property";
let elServerScriptError = document.createElement('textarea');
let serverScriptErrorElementID = 'property-serverScripts-error';
@@ -3994,6 +4290,10 @@ function loaded() {
dt.addEventListener("click", toggleDropdown, true);
dl.appendChild(dt);
+ let elMultiDiff = document.createElement('span');
+ elMultiDiff.className = "multi-diff";
+ dl.appendChild(elMultiDiff);
+
let span = document.createElement("span");
span.setAttribute("value", options[selectedOption].value);
span.textContent = options[selectedOption].firstChild.textContent;
diff --git a/scripts/system/html/js/utils.js b/scripts/system/html/js/utils.js
index d61b4d1762..9556856089 100644
--- a/scripts/system/html/js/utils.js
+++ b/scripts/system/html/js/utils.js
@@ -25,3 +25,70 @@ function disableDragDrop() {
event.preventDefault();
}, false);
}
+
+// mergeDeep function from https://stackoverflow.com/a/34749873
+/**
+ * Simple object check.
+ * @param item
+ * @returns {boolean}
+ */
+function mergeDeepIsObject(item) {
+ return (item && typeof item === 'object' && !Array.isArray(item));
+}
+
+/**
+ * Deep merge two objects.
+ * @param target
+ * @param sources
+ */
+function mergeDeep(target, ...sources) {
+ if (!sources.length) {
+ return target;
+ }
+ const source = sources.shift();
+
+ if (mergeDeepIsObject(target) && mergeDeepIsObject(source)) {
+ for (const key in source) {
+ if (!source.hasOwnProperty(key)) {
+ continue;
+ }
+ if (mergeDeepIsObject(source[key])) {
+ if (!target[key]) {
+ Object.assign(target, { [key]: {} });
+ }
+ mergeDeep(target[key], source[key]);
+ } else {
+ Object.assign(target, { [key]: source[key] });
+ }
+ }
+ }
+
+ return mergeDeep(target, ...sources);
+}
+
+function deepEqual(a, b) {
+ if (a === b) {
+ return true;
+ }
+
+ if (typeof(a) !== "object" || typeof(b) !== "object") {
+ return false;
+ }
+
+ if (Object.keys(a).length !== Object.keys(b).length) {
+ return false;
+ }
+
+ for (let property in a) {
+ if (!a.hasOwnProperty(property)) {
+ continue;
+ }
+ if (!b.hasOwnProperty(property)) {
+ return false;
+ }
+ if (!deepEqual(a[property], b[property])) {
+ return false;
+ }
+ }
+ return true;
+}