// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System; using System.Collections.Generic; using System.Linq; using Jint; using Jint.Native; using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Descriptors; using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper { public sealed class ContentFieldObject : ObjectInstance { private readonly ContentDataObject contentData; private readonly ContentFieldData? fieldData; private HashSet? valuesToDelete; private Dictionary valueProperties; private bool isChanged; public ContentFieldData? FieldData { get { return fieldData; } } public override bool Extensible => true; public ContentFieldObject(ContentDataObject contentData, ContentFieldData? fieldData, bool isNew) : base(contentData.Engine) { this.contentData = contentData; this.fieldData = fieldData; if (isNew) { MarkChanged(); } } public void MarkChanged() { isChanged = true; contentData.MarkChanged(); } public bool TryUpdate(out ContentFieldData? result) { result = fieldData; if (isChanged && fieldData != null) { if (valuesToDelete != null) { foreach (var field in valuesToDelete) { fieldData.Remove(field); } } if (valueProperties != null) { foreach (var (key, propertyDescriptor) in valueProperties) { var value = (ContentFieldProperty)propertyDescriptor; if (value.IsChanged) { fieldData[key] = value.ContentValue; } } } } return isChanged; } public override void RemoveOwnProperty(JsValue property) { var propertyName = property.AsString(); valuesToDelete ??= new HashSet(); valuesToDelete.Add(propertyName); valueProperties?.Remove(propertyName); MarkChanged(); } public override bool Set(JsValue property, JsValue value, JsValue receiver) { EnsurePropertiesInitialized(); var propertyName = property.AsString(); valueProperties.GetOrAdd(propertyName, k => new ContentFieldProperty(this)).Value = value; return true; } public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc) { EnsurePropertiesInitialized(); var propertyName = property.AsString(); if (!valueProperties.ContainsKey(propertyName)) { valueProperties[propertyName] = new ContentFieldProperty(this) { Value = desc.Value }; } return true; } public override PropertyDescriptor GetOwnProperty(JsValue property) { EnsurePropertiesInitialized(); var propertyName = property.AsString(); if (propertyName.Equals("toJSON", StringComparison.OrdinalIgnoreCase)) { return PropertyDescriptor.Undefined; } return valueProperties?.GetOrDefault(propertyName) ?? PropertyDescriptor.Undefined; } public override IEnumerable> GetOwnProperties() { EnsurePropertiesInitialized(); return valueProperties.Select(x => new KeyValuePair(x.Key, x.Value)); } public override List GetOwnPropertyKeys(Types types = Types.String | Types.Symbol) { EnsurePropertiesInitialized(); return valueProperties.Keys.Select(x => (JsValue)x).ToList(); } private void EnsurePropertiesInitialized() { if (valueProperties == null) { valueProperties = new Dictionary(fieldData?.Count ?? 0); if (fieldData != null) { foreach (var (key, value) in fieldData) { valueProperties.Add(key, new ContentFieldProperty(this, value)); } } } } } }