using bessw.Unity.WebView; using bessw.Unity.WebView.ChromeDevTools; using bessw.Unity.WebView.ChromeDevTools.Protocol.DOM; using MoreLinq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using UnityEngine.Events; public class WebViewController : MonoBehaviour { // TODO: onFactAssignment event shoud hav a dropzone id and a fact id as parameters public UnityEvent<DomNodeWrapper, string> onFactAssignment; // TODO: implement onHintRequested event public UnityEvent<DomNodeWrapper, string> onHintRequested; // TODO: click events (option for custom buttons for a scroll) public UnityEvent<DomNodeWrapper> onClick; private WebViewComponent webViewComponent; private DomNodeWrapper[] dropzones; private void Awake() { Debug.LogWarning("awake Webview Controller"); webViewComponent = GetComponent<WebViewComponent>(); WebViewComponent.serializerSettings.Converters.Add(new FactObjectUIConverter()); webViewComponent.targetUrl = Path.Join(Application.dataPath, "scrollView.html"); // TODO: handle webViewComponent.onDomDocumentUpdated // TODO: remove this debug code onFactAssignment.AddListener((DomNodeWrapper node, string factId) => { Debug.LogWarning($"onFactAssignment: '{string.Join(", ", GetFactAssignments())}'"); }); } /// <summary> /// sets or updates the content of the scroll container dom element /// </summary> /// <param name="scrollHTML"></param> public async void SetScrollContent(string scrollHTML) { // update scroll container content DomNodeWrapper scrollContainer = await DomNodeWrapper.requestNodeAsync(webViewComponent.tab, "scrollContainer"); await scrollContainer.setNodeValueAsync(scrollHTML); // get the dropzones from the scroll and add the event handler to track when something is dropped dropzones = await scrollContainer.querySelectorAllAsync("[dropzone='copy']"); dropzones.ForEach(dropzone => dropzone.OnAttributeModified += DropzoneAttributeModifiedHandler); } private void DropzoneAttributeModifiedHandler(attributeModifiedEvent attributeModifiedEvent) { Debug.LogWarning($"dropzoneAtrributeModifiedHandler: '{attributeModifiedEvent.name}'"); // call the onFactAssignment event if the data-fact-id attribute was modified if (attributeModifiedEvent.name == "data-fact-id") { var node = webViewComponent.tab.domNodes.GetValueOrDefault(attributeModifiedEvent.nodeId); onFactAssignment.Invoke(node, attributeModifiedEvent.value); } } public string[] GetFactAssignments() { return dropzones.Select(dropzone => dropzone.Node.attributes.GetValueOrDefault("data-fact-id", null)).ToArray(); } private async void GetDropzoneStateAsync() { // alternative way to get the dropzone state DomNodeWrapper document = await DomNodeWrapper.getDocumentAsync(webViewComponent.tab); Debug.LogWarning($"dropzone 1: '{document}'"); var dropzones = await document.querySelectorAllAsync("[dropzone='copy']"); Debug.LogWarning($"dropzone 2: '{dropzones.Index().Aggregate("", (currentString, dropzone) => $"{currentString}, {dropzone.Key}: {dropzone.Value.Node.attributes.GetValueOrDefault("data-fact-id")}")}'"); string[] factIDs = new string[dropzones.Length]; // get attributes for each dropzone //for (int i = 0; i < dropzones.Length; i++) //{ // factIDs[i] = ( await dropzones[i].getAttributesAsync() ).GetValueOrDefault("data-fact-id", null); //} //Debug.LogWarning($"dropzone 3: '{string.Join(", ", factIDs)}'"); } /// <summary> /// First try to get the dropzone state using coroutines. /// Doesn't work because coroutines can't access method local temporary variables. /// </summary> /// <returns></returns> [Obsolete("Use getDropzoneStateAsync instead")] private IEnumerator GetDropzoneState() { Debug.LogWarning($"dropzone pre"); DomNodeWrapper doc = null; yield return DomNodeWrapper.getDocument(webViewComponent.tab, (document) => { Debug.LogWarning($"dropzone 1: '{document}'"); doc = document; StartCoroutine(document.querySelectorAll("[dropzone='copy']", (dropzones) => { foreach (var dropzone in dropzones) { Debug.LogWarning($"dropzone 2: Node is Null?: '{dropzone.Node == null}'"); StartCoroutine(dropzone.getAttributes((attributes) => { Debug.LogWarning($"dropzone 3 getAttributes: '{string.Join(", ", attributes.Values)}'"); })); } })); }); Debug.LogWarning($"dropzone post: '{doc}'"); } } public class FactObjectUIConverter : JsonConverter<FactObjectUI> { public override void WriteJson(JsonWriter writer, FactObjectUI value, JsonSerializer serializer) { //serializer.Serialize(writer, value.Fact); JObject o = JObject.FromObject(value.Fact, WebViewComponent.serializer); o.AddFirst(new JProperty("id", value.Fact.Id)); o.WriteTo(writer); } public override FactObjectUI ReadJson(JsonReader reader, Type objectType, FactObjectUI existingValue, bool hasExistingValue, JsonSerializer serializer) { var factObject = new FactObjectUI(); factObject.Fact = serializer.Deserialize<Fact>(reader); return factObject; } }