Newer
Older
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;
Björn Eßwein
committed
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
Björn Eßwein
committed
public class WebViewController : ScrollView
{
private WebViewComponent webViewComponent;
private DomNodeWrapper[] dropzones;
private void Awake()
{
Björn Eßwein
committed
Debug.LogWarning("awake Webview Controller");
webViewComponent = GetComponent<WebViewComponent>();
WebViewComponent.serializerSettings.Converters.Add(new FactObjectUIConverter());
Björn Eßwein
committed
webViewComponent.targetUrl = Path.Join(CommunicationEvents.Get_DataPath(), "scrollView.html");
webViewComponent.OnWebViewComponentReady += OnWebViewComponentReady;
// TODO: handle webViewComponent.onDomDocumentUpdated
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
}
private void OnWebViewComponentReady()
{
webViewComponent.onDomDocumentUpdated += DocumentUpdatedHandler;
SwitchScrollUI.activeScrollData.OnScrollChanged.AddListener(SetScrollContent);
SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.AddListener(SetScrollContent);
webViewComponent.tab.AddJSBinding("applyScroll", ApplyScrollHandler);
webViewComponent.tab.AddJSBinding("getHint", GetHintHandler);
RegisterBrowserEventhandlers();
}
private void OnDisable()
{
webViewComponent.onDomDocumentUpdated -= DocumentUpdatedHandler;
SwitchScrollUI.activeScrollData.OnScrollChanged.RemoveListener(SetScrollContent);
SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.RemoveListener(SetScrollContent);
webViewComponent.tab.RemoveJSBinding("applyScroll");
webViewComponent.tab.RemoveJSBinding("getHint");
DeRegisterBrowserEventhandlers();
}
private void DocumentUpdatedHandler(documentUpdatedEvent _)
{
// all old DomNodeWrapper objects are invalid, because the whole document has been updated
dropzones = null;
RegisterBrowserEventhandlers();
}
private async void RegisterBrowserEventhandlers()
{
// register js event handlers in the browser
_ = webViewComponent.tab.Evaluate("dropZones = document.querySelectorAll('[dropzone=\"copy\"]'); dropZones.forEach( dropZone => dropZone.addEventListener(\"drop\", ev => dropHandler(ev, \"DropEvent\")) )");
// register c# event handlers
// get the dropzones from the scroll and add the event handler to track when something is dropped
DomNodeWrapper document = await webViewComponent.tab.GetDocument();
dropzones = await document.querySelectorAllAsync("[dropzone='copy']");
dropzones.ForEach(dropzone => dropzone.OnAttributeModified += DropzoneAttributeModifiedHandler);
}
private void DeRegisterBrowserEventhandlers()
{
dropzones?.ForEach(dropzone => dropzone.OnAttributeModified -= DropzoneAttributeModifiedHandler);
}
/// <summary>
/// sets or updates the content of the scroll container dom element
/// </summary>
/// <param name="scrollHTML"></param>
private async void SetScrollContent(Scroll scroll)
{
// update scroll container content
DomNodeWrapper document = await webViewComponent.tab.GetDocument();
DomNodeWrapper scrollContainer = await document.querySelectorAsync("#scrollContainer");
var description = scroll.description;
// if scroll is a lagacy plain text scroll, generate html with slots for the required facts
if (!scroll.description.StartsWith("<scroll-description"))
{
// generate slots for a plane text scroll description
var factSlots = SwitchScrollUI.activeScrollData.Assignments
.Where(pair => pair.Value.IsVisible)
.Select(pair =>
@$"<span class='lagacySlot' dropzone='copy' data-slot-id='{pair.Key}' {(pair.Value.IsSet ? $"data-fact-id='{pair.Value.fact.Id}'" : "")}>
{(pair.Value.IsSet ?
pair.Value.fact.GetLabel(StageStatic.stage.factState) :
scroll.requiredFacts.Find(fact => fact.@ref.uri == pair.Key).label )}
</span>");
description = $"<scroll-description><p>{scroll.description}</p><div id='lagacySlots'>{String.Join("", factSlots)}</div></scroll-description>";
}
// display the scroll description
await scrollContainer.setOuterHtmlAsync($"<div id='scrollContainer'>{description}</div>");
RegisterBrowserEventhandlers();
private async 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")
{
// get the slot id
var node = await webViewComponent.tab.GetNode(attributeModifiedEvent.nodeId);
if (! (node.Node.attributes.TryGetValue("data-slot-id", out string slot)
|| (await node.getAttributesAsync()).TryGetValue("data-slot-id", out slot)))
{
Debug.LogError($"dropzoneAtrributeModifiedHandler: data-slot-id attribute not found on dropzone");
throw new Exception("data-slot-id attribute not found on dropzone");
}
// get the fact from the fact id
if (!FactRecorder.AllFacts.TryGetValue(attributeModifiedEvent.value, out Fact fact))
{
Debug.LogError($"dropzoneAtrributeModifiedHandler: fact with id '{attributeModifiedEvent.value}' not found");
throw new Exception($"fact with id '{attributeModifiedEvent.value}' not found");
}
// assign fact to slot
SwitchScrollUI.activeScrollData.AssignFact(slot, fact);
private void ApplyScrollHandler(string button)
{
SwitchScrollUI.activeScrollData.ButtonClicked(new MagicScrollButton());
}
private void GetHintHandler(string url)
{
SwitchScrollUI.activeScrollData.ButtonClicked(new HintScrollButton(url));
}
public string[] GetFactAssignments()
{
return dropzones.Select(dropzone => dropzone.Node.attributes.GetValueOrDefault("data-fact-id", null)).ToArray();
}
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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;
}
}