diff --git a/Runtime/ChromeDevtools/Browser.cs b/Runtime/ChromeDevtools/Browser.cs index ca1bbaf81f56b0492cfaa361d12af2d5179a0606..ec6755bab861105d67b2d857943b513ff2bb51cf 100644 --- a/Runtime/ChromeDevtools/Browser.cs +++ b/Runtime/ChromeDevtools/Browser.cs @@ -14,7 +14,7 @@ namespace bessw.Unity.WebView.ChromeDevTools { /* singleton */ private static Browser instance; - private static Process browserProcess; + private Process browserProcess; /* browser settings */ public static string browserExecutablePath = "chrome"; @@ -37,7 +37,7 @@ namespace bessw.Unity.WebView.ChromeDevTools */ public static Browser getInstance() { - if (instance == null) + if (instance == null || instance.browserProcess.HasExited) { instance = new Browser(); instance.launchBrowser(); @@ -64,31 +64,45 @@ namespace bessw.Unity.WebView.ChromeDevTools private void launchBrowser() { // allow only one instance of chrome - if (Browser.browserProcess == null || Browser.browserProcess.HasExited) + if (browserProcess == null || browserProcess.HasExited) { - Browser.browserProcess = new Process(); - Browser.browserProcess.StartInfo.FileName = browserExecutablePath; - Browser.browserProcess.StartInfo.Arguments = $"--user-data-dir={Path.Join(Application.temporaryCachePath, "BrowserView")} --remote-debugging-port={debugPort} --remote-allow-origins=http://localhost:{debugPort} --hide-crash-restore-bubble"; + browserProcess = new Process(); + browserProcess.StartInfo.FileName = browserExecutablePath; + browserProcess.StartInfo.Arguments = String.Join(" ", new []{ + $"--user-data-dir={Path.Join(Application.temporaryCachePath, "BrowserView")}", + $"--remote-debugging-port={debugPort}", + $"--remote-allow-origins=http://localhost:{debugPort}", + "--hide-crash-restore-bubble", + "--disable-first-run-ui", + "--no-first-run" + }); // set headlessBrowser to false to see the browser window if (headless) { - Browser.browserProcess.StartInfo.Arguments = string.Concat(Browser.browserProcess.StartInfo.Arguments, " --headless=new"); + browserProcess.StartInfo.Arguments = string.Concat(browserProcess.StartInfo.Arguments, " --headless=new"); } else { - Browser.browserProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized; + browserProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized; } - Browser.browserProcess.Start(); - UnityEngine.Debug.Log($"launched '{Browser.browserProcess.StartInfo.FileName} {Browser.browserProcess.StartInfo.Arguments}'"); + // register an error handler + browserProcess.ErrorDataReceived += (sender, e) => UnityEngine.Debug.LogError($"Browser Error: {e.Data} ExitCode: {browserProcess.ExitCode}"); + browserProcess.Exited += (sender, e) => UnityEngine.Debug.LogError($"Browser Exited, ExitCode: {browserProcess.ExitCode}"); + + browserProcess.Start(); + if (browserProcess.HasExited) { + UnityEngine.Debug.LogError("Failed to start browser"); + } + UnityEngine.Debug.Log($"launched '{browserProcess.StartInfo.FileName} {browserProcess.StartInfo.Arguments}'"); } } /** * send web request to the devTools API */ - private IEnumerator DevToolsApiRequest(bool isPUT, string apiAddress, System.Action<string> callback) + private IEnumerator DevToolsApiRequest(bool isPUT, string apiAddress, Action<string> callback) { UnityEngine.Debug.Log($"DevTools api Request: {apiAddress}"); UnityWebRequest webRequest; @@ -114,7 +128,7 @@ namespace bessw.Unity.WebView.ChromeDevTools } } - public IEnumerator OpenNewTab(string targetUrl, System.Action<BrowserTab> callback) + public IEnumerator OpenNewTab(string targetUrl, Action<BrowserTab> callback) { yield return DevToolsApiRequest(true, $"/json/new?{targetUrl}", (response) => { diff --git a/Runtime/ChromeDevtools/BrowserTab.cs b/Runtime/ChromeDevtools/BrowserTab.cs index 74b8ce03cb956f0cec38af16b1ac6ba3a7143693..0f4e23f92575d37e712e05287aee5b0c0171114f 100644 --- a/Runtime/ChromeDevtools/BrowserTab.cs +++ b/Runtime/ChromeDevtools/BrowserTab.cs @@ -3,6 +3,7 @@ using bessw.Unity.WebView.ChromeDevTools.Protocol.Page; using bessw.Unity.WebView.ChromeDevTools.Protocol.Target; using System; using System.Collections; +using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; @@ -12,19 +13,31 @@ namespace bessw.Unity.WebView.ChromeDevTools public class BrowserTab { private PageTargetInfo pageTarget; - private DevtoolsProtocolHandler devtools; + public DevtoolsProtocolHandler devtools; /// <summary> /// width and height of the brower device /// </summary> public Vector2Int size { get; private set; } + public Dictionary<int, DomNodeWrapper> domNodes = new Dictionary<int, DomNodeWrapper>(); + public BrowserTab(PageTargetInfo pageTarget) { this.pageTarget = pageTarget; Debug.Log($"tab WebSocket: '{pageTarget.WebSocketDebuggerUrl}'"); this.devtools = new DevtoolsProtocolHandler(new DevtoolsWebsocket(pageTarget.WebSocketDebuggerUrl)); + + // register DOM event handlers + this.devtools.DOM_AttributeModifiedEventHandler += (attributeModifiedEvent) => DomNodeWrapper.onAttributeModified(this, attributeModifiedEvent); + this.devtools.DOM_AttributeRemovedEventHandler += (attributeRemovedEvent) => DomNodeWrapper.onAttributeRemoved(this, attributeRemovedEvent); + this.devtools.DOM_CharacterDataModifiedEventHandler += (characterDataModifiedEvent) => DomNodeWrapper.onCharacterDataModified(this, characterDataModifiedEvent); + this.devtools.DOM_ChildNodeCountUpdatedEventHandler += (childNodeCountUpdatedEvent) => DomNodeWrapper.onChildNodeCountUpdated(this, childNodeCountUpdatedEvent); + this.devtools.DOM_ChildNodeInsertedEventHandler += (childNodeInsertedEvent) => DomNodeWrapper.onChildNodeInserted(this, childNodeInsertedEvent); + this.devtools.DOM_ChildNodeRemovedEventHandler += (childNodeRemovedEvent) => DomNodeWrapper.onChildNodeRemoved(this, childNodeRemovedEvent); + this.devtools.DOM_DocumentUpdatedEventHandler += (documentUpdatedEvent) => DomNodeWrapper.onDocumentUpdated(this, documentUpdatedEvent); + this.devtools.DOM_SetChildNodesEventHandler += (setChildNodesEvent) => DomNodeWrapper.onSetChildNodes(this, setChildNodesEvent); } public IEnumerator Update() @@ -34,10 +47,14 @@ namespace bessw.Unity.WebView.ChromeDevTools public IEnumerator CreateScreenshot(double width, double height, Action<Texture2D> callback) { - var screenshotCommand = new captureScreenshot(); - screenshotCommand.Clip = new Protocol.Types.Viewport(); - screenshotCommand.Clip.Width = width; - screenshotCommand.Clip.Height = height; + var screenshotCommand = new captureScreenshot + { + Clip = new Protocol.Types.Viewport + { + Width = width, + Height = height + } + }; return devtools.SendCommand(screenshotCommand, (response) => { @@ -59,8 +76,10 @@ namespace bessw.Unity.WebView.ChromeDevTools devtools.screencastFrameEventHandler += (screencastFrameEvent frameEvent) => { // send an ack for this frame - var frameAck = new screencastFrameAck(); - frameAck.sessionId = frameEvent.sessionId; + var frameAck = new screencastFrameAck + { + sessionId = frameEvent.sessionId + }; _ = devtools.SendCommandAsync(frameAck); size = new Vector2Int(frameEvent.metadata.deviceWidth, frameEvent.metadata.deviceHeight); @@ -76,10 +95,12 @@ namespace bessw.Unity.WebView.ChromeDevTools callback(frameTexture); }; - var startScreencast = new startScreencast(); - startScreencast.MaxWidth = maxWidth; - startScreencast.maxHeight = maxHeight; - startScreencast.everyNthFrame = 1; + var startScreencast = new startScreencast + { + MaxWidth = maxWidth, + maxHeight = maxHeight, + everyNthFrame = 1 + }; return devtools.SendCommand(startScreencast); } @@ -139,6 +160,11 @@ namespace bessw.Unity.WebView.ChromeDevTools _ = devtools.SendCommandAsync(new cancelDragging()); } + public IEnumerator GetDocument(Action<DomNodeWrapper> callback) + { + return DomNodeWrapper.getDocument(this, callback); + } + /** * close this tab */ diff --git a/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs index aed39162b4422e9b2c1ded8ffa35485af7b10bad..fe7e7104ce703a04b3e9acf125e77d553c875b6b 100644 --- a/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs +++ b/Runtime/ChromeDevtools/DevtoolsProtocolHandler.cs @@ -1,4 +1,5 @@ using bessw.Unity.WebView.ChromeDevTools.Protocol; +using bessw.Unity.WebView.ChromeDevTools.Protocol.DOM; using bessw.Unity.WebView.ChromeDevTools.Protocol.Page; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -25,6 +26,19 @@ namespace bessw.Unity.WebView.ChromeDevTools public event Action<screencastFrameEvent> screencastFrameEventHandler; public event Action<screencastVisibilityChangedEvent> screencastVisibilityChangedEventHandler; + #region DOM events + public event Action<attributeModifiedEvent> DOM_AttributeModifiedEventHandler; + public event Action<attributeRemovedEvent> DOM_AttributeRemovedEventHandler; + public event Action<characterDataModifiedEvent> DOM_CharacterDataModifiedEventHandler; + public event Action<childNodeCountUpdatedEvent> DOM_ChildNodeCountUpdatedEventHandler; + public event Action<childNodeInsertedEvent> DOM_ChildNodeInsertedEventHandler; + public event Action<childNodeRemovedEvent> DOM_ChildNodeRemovedEventHandler; + public event Action<documentUpdatedEvent> DOM_DocumentUpdatedEventHandler; + public event Action<setChildNodesEvent> DOM_SetChildNodesEventHandler; + #endregion DOM events + + public event Action<DevtoolsEventWrapper> unknownEventHandler; + public DevtoolsProtocolHandler(IDevtoolsConnection devtools) { this.devtools = devtools; @@ -113,8 +127,42 @@ namespace bessw.Unity.WebView.ChromeDevTools case "Page.screencastVisibilityChanged": screencastVisibilityChangedEventHandler?.Invoke( ev.Params.ToObject<screencastVisibilityChangedEvent>(Browser.devtoolsSerializer) ); break; + + // switch cases that invoke the event handlers for the DOM events + #region DOM events + case "DOM.attributeModified": + DOM_AttributeModifiedEventHandler?.Invoke( ev.Params.ToObject<attributeModifiedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.attributeRemoved": + DOM_AttributeRemovedEventHandler?.Invoke( ev.Params.ToObject<attributeRemovedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.characterDataModified": + DOM_CharacterDataModifiedEventHandler?.Invoke( ev.Params.ToObject<characterDataModifiedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.childNodeCountUpdated": + DOM_ChildNodeCountUpdatedEventHandler?.Invoke( ev.Params.ToObject<childNodeCountUpdatedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.childNodeInserted": + DOM_ChildNodeInsertedEventHandler?.Invoke( ev.Params.ToObject<childNodeInsertedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.childNodeRemoved": + DOM_ChildNodeRemovedEventHandler?.Invoke( ev.Params.ToObject<childNodeRemovedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.documentUpdated": + DOM_DocumentUpdatedEventHandler?.Invoke( ev.Params.ToObject<documentUpdatedEvent>(Browser.devtoolsSerializer) ); + break; + case "DOM.setChildNodes": + DOM_SetChildNodesEventHandler?.Invoke( ev.Params.ToObject<setChildNodesEvent>(Browser.devtoolsSerializer) ); + break; + #endregion DOM events + default: - throw new UnexpectedMessageException($"Event of type '{ev}' is not implemented"); + if (unknownEventHandler != null) { + unknownEventHandler.Invoke(ev); + break; + } else { + throw new UnexpectedMessageException($"Event of type '{ev}' is not implemented"); + } } } diff --git a/Runtime/ChromeDevtools/DomNodeWrapper.cs b/Runtime/ChromeDevtools/DomNodeWrapper.cs new file mode 100644 index 0000000000000000000000000000000000000000..5f97af3b7ffa972b7fe4cac3751b94d2f37c7cf0 --- /dev/null +++ b/Runtime/ChromeDevtools/DomNodeWrapper.cs @@ -0,0 +1,376 @@ +using bessw.Unity.WebView.ChromeDevTools.Protocol.DOM; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +#nullable enable +namespace bessw.Unity.WebView.ChromeDevTools +{ + public class DomNodeWrapper + { + /// <summary> + /// Node identifier that is passed into the rest of the DOM messages as the `nodeId`. Backend + /// will only push node with given `id` once. It is aware of all requested nodes and will only + /// fire DOM events for nodes known to the client. + /// </summary> + public int NodeId + { + get => Node.nodeId; + protected set => Node.nodeId = value; + } + /// <summary> + /// The id of the parent node if any. + /// </summary> + public int? ParentId + { + get => Node.parentId; + protected set => Node.parentId = value; + } + + /// <summary> + /// The `Node`object returend by the browser + /// </summary> + /// <remarks>May be null if it has not jet been requested from the browser</remarks> + public Node Node { get; protected set; } + + + /// <summary> + /// Reference to the browser tab that this dom node belongs to + /// </summary> + private BrowserTab tab; + + /// <summary> + /// private constructor, create instances with the static method <see cref="getDocument"/>, + /// or by calling instance methods on a <see cref="DomNodeWrapper"/> to get its child nodes. + /// </summary> + /// <param name="tab"></param> + private DomNodeWrapper(BrowserTab tab, Node node) + { + this.tab = tab; + this.Node = node; + } + + private static DomNodeWrapper createOrUpdateNode(BrowserTab tab, int nodeId, int? parentId = null, int? backendNodeId = null, Node? node = null) + { + if (tab.domNodes.ContainsKey(nodeId)) + { + var domNode = tab.domNodes[nodeId]; + if (node != null) domNode.Node = node; + if (parentId != null) domNode.ParentId = parentId; + if (backendNodeId != null) domNode.Node.backendNodeId = (int)backendNodeId; + return domNode; + } + else + { + var domNode = new DomNodeWrapper(tab, node ?? new Node() + { + nodeId = nodeId, + parentId = parentId + }); + tab.domNodes[nodeId] = domNode; + return domNode; + } + } + + #region Event Handlers + + public static void onAttributeModified(BrowserTab tab, attributeModifiedEvent eventData) + { + var domNode = createOrUpdateNode(tab, eventData.nodeId); + if (domNode.Node != null) + { + domNode.Node.attributes[eventData.name] = eventData.value; + } else { + throw new InvalidOperationException("AttributeModified event was fired, the node info has not yet been recieved"); + } + } + + public static void onAttributeRemoved(BrowserTab tab, attributeRemovedEvent eventData) + { + var domNode = createOrUpdateNode(tab, eventData.nodeId); + if (domNode.Node != null) + { + domNode.Node.attributes.Remove(eventData.name); + } else { + throw new InvalidOperationException("AttributeRemoved event was fired, the node info has not yet been recieved"); + } + } + + public static void onCharacterDataModified(BrowserTab tab, characterDataModifiedEvent eventData) + { + var domNode = createOrUpdateNode(tab, eventData.nodeId); + if (domNode.Node != null) + { + domNode.Node.nodeValue = eventData.characterData; + } else { + throw new InvalidOperationException("CharacterDataModified event was fired, the node info has not yet been recieved"); + } + } + + public static void onChildNodeCountUpdated(BrowserTab tab, childNodeCountUpdatedEvent eventData) + { + var domNode = createOrUpdateNode(tab, eventData.nodeId); + if (domNode.Node != null) + { + domNode.Node.childNodeCount = eventData.childNodeCount; + } else { + throw new InvalidOperationException("ChildNodeCountUpdated event was fired, the node info has not yet been recieved"); + } + } + + public static void onChildNodeInserted(BrowserTab tab, childNodeInsertedEvent eventData) + { + var parentNode = createOrUpdateNode(tab, eventData.parentNodeId); + var childNode = createOrUpdateNode(tab, eventData.node.nodeId, eventData.parentNodeId, eventData.node.backendNodeId, eventData.node); + if (parentNode.Node != null && childNode.Node != null) + { + parentNode.Node.children.Insert(eventData.previousNodeId, childNode.Node); + } else { + throw new InvalidOperationException("ChildNodeInserted event was fired, the node info has not yet been recieved"); + } + } + + public static void onChildNodeRemoved(BrowserTab tab, childNodeRemovedEvent eventData) + { + if ( + tab.domNodes.TryGetValue(eventData.parentNodeId, out var parentNode) && + tab.domNodes.TryGetValue(eventData.nodeId, out var childNode) && + parentNode.Node != null && + childNode.Node != null) + { + parentNode.Node.children.Remove(childNode.Node); + } else { + //throw new InvalidOperationException("ChildNodeRemoved event was fired, the node info has not yet been recieved"); + } + } + + public static void onDocumentUpdated(BrowserTab tab, documentUpdatedEvent eventData) + { + // clear the domNodes dictionary + tab.domNodes.Clear(); + } + + public static void onSetChildNodes(BrowserTab tab, setChildNodesEvent eventData) + { + var parentNode = createOrUpdateNode(tab, eventData.parentId); + if (parentNode.Node != null) + { + foreach (var node in eventData.nodes) + { + createOrUpdateNode(tab, node.nodeId, eventData.parentId, node.backendNodeId, node); + } + parentNode.Node.children = new(eventData.nodes); + } else { + throw new InvalidOperationException("SetChildNodes event was fired, the node info has not yet been recieved"); + } + } + + #endregion Event Handlers + + #region Commands + + /// <summary> + /// Enables DOM agent for the given page. + /// </summary> + public static IEnumerator enable(BrowserTab tab) + { + var enableCommand = new enable(); + return tab.devtools.SendCommand(enableCommand); + } + + /// <summary> + /// Disables DOM agent for the given page. + /// </summary> + public static IEnumerator disable(BrowserTab tab) + { + return tab.devtools.SendCommand( new disable() ); + } + + /// <summary> + /// Get the root node of the document, the root node is returned as an argument to the callback. + /// </summary> + /// <param name="tab"></param> + /// <param name="callback">The callback recieves the root node as argument</param> + /// <returns><see cref="DomNodeWrapper"/></returns> + public static IEnumerator getDocument(BrowserTab tab, Action<DomNodeWrapper> callback) + { + var domCommand = new getDocument(); + return tab.devtools.SendCommand(domCommand, (response) => + { + Node documentRoot = ((getDocumentCommandResponse)response).root; + + var domNode = createOrUpdateNode(tab, + documentRoot.nodeId, + documentRoot.parentId, + documentRoot.backendNodeId, + documentRoot + ); + + callback(domNode); + }); + } + + /// <summary> + /// Describes the node, does not require domain to be enabled. Does not start tracking any + /// objects, can be used for automation. + /// </summary> + /// <param name="callback">The callback recieves the node as argument</param> + public IEnumerator describeNode(Action<Node> callback, int? depth = null, bool? pierce = null) + { + var describeNodeCommand = new describeNode + { + nodeId = NodeId, + depth = depth, + pierce = pierce + }; + return tab.devtools.SendCommand(describeNodeCommand, (response) => + { + callback(((describeNodeCommandResponse)response).node); + }); + } + + /// <summary> + /// Focus this node. + /// </summary> + public IEnumerator focus() + { + var focusCommand = new focus + { + nodeId = NodeId + }; + return tab.devtools.SendCommand(focusCommand); + } + + /// <summary> + /// Gets the nodes Attributes + /// </summary> + public IEnumerator getAttributes(Action<Dictionary<string, string>> callback) + { + var attributesCommand = new getAttributes + { + nodeId = NodeId + }; + return tab.devtools.SendCommand(attributesCommand, (response) => + { + var attibutes = ((getAttributesCommandResponse)response).attributes; + tab.domNodes[NodeId].Node.attributes = attibutes; + + callback(attibutes); + }); + } + + public IEnumerator getBoxModel(Action<BoxModel> callback) + { + var boxModelCommand = new getBoxModel + { + nodeId = NodeId + }; + return tab.devtools.SendCommand(boxModelCommand, (response) => + { + callback(((getBoxModelCommandResponse) response).model); + }); + } + + public IEnumerator getNodeForLocation(int x, int y, Action<DomNodeWrapper> callback, Action<string>? errorCallback = null) + { + var nodeForLocationCommand = new getNodeForLocation + { + x = x, + y = y + }; + return tab.devtools.SendCommand(nodeForLocationCommand, (response) => + { + var responseNodeId = ((getNodeForLocationCommandResponse) response).nodeId; + if (responseNodeId != null) { + var domNode = createOrUpdateNode(tab, (int)responseNodeId); + callback(domNode); + } else { + errorCallback?.Invoke("nodeId was not provided, is the dom domain enabled?"); + } + }); + } + + /// <summary> + /// Returns node's HTML markup. + /// </summary> + public IEnumerator getOuterHtml(Action<string> callback) + { + var outerHtmlCommand = new getOuterHTML + { + nodeId = NodeId + }; + return tab.devtools.SendCommand(outerHtmlCommand, (response) => + { + callback(((getOuterHTMLCommandResponse) response).outerHTML); + }); + } + + /// <summary> + /// Moves node into an other container node + /// </summary> + public IEnumerator moveTo(DomNodeWrapper targetNode, DomNodeWrapper? insertBeforeNode = null) + { + var moveToCommand = new moveTo + { + nodeId = NodeId, + targetNodeId = targetNode.NodeId, + insertBeforeNodeId = insertBeforeNode?.NodeId + }; + return tab.devtools.SendCommand(moveToCommand, (response) => + { + // update the new node id of the moved node + tab.domNodes.Remove(NodeId); + NodeId = ((moveToCommandResponse) response).nodeId; + tab.domNodes[NodeId] = this; + }); + } + + /// <summary> + /// search a child node by querySelector + /// </summary> + public IEnumerator querySelector(string selector, Action<DomNodeWrapper> callback) + { + var querySelectorCommand = new querySelector + { + nodeId = NodeId, + selector = selector + }; + return tab.devtools.SendCommand(querySelectorCommand, (response) => + { + var domNode = createOrUpdateNode(tab, ((querySelectorCommandResponse) response).nodeId); + + callback(domNode); + }); + } + + /// <summary> + /// search all child nodes matching the querySelector + /// </summary> + public IEnumerator querySelectorAll(string selector, Action<DomNodeWrapper[]> callback) + { + var querySelectorAllCommand = new querySelectorAll + { + nodeId = NodeId, + selector = selector + }; + return tab.devtools.SendCommand(querySelectorAllCommand, (response) => + { + var nodeIds = ((querySelectorAllCommandResponse) response).nodeIds; + var domNodes = new DomNodeWrapper[nodeIds.Length]; + for (int i = 0; i < nodeIds.Length; i++) + { + domNodes[i] = createOrUpdateNode(tab, nodeIds[i]); + } + callback(domNodes); + }); + } + + //TODO: implement the other commands of the DOM domain + + #endregion Commands + + + } +} diff --git a/Runtime/ChromeDevtools/DomNodeWrapper.cs.meta b/Runtime/ChromeDevtools/DomNodeWrapper.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..8b4877463daadd97e0c794a4a91e77cae798b76e --- /dev/null +++ b/Runtime/ChromeDevtools/DomNodeWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a49fdc400bfe5d46b76c0c1e154940e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ChromeDevtools/Protocol/DOM/DOM.cs b/Runtime/ChromeDevtools/Protocol/DOM/DOM.cs index ac13b5785a1d37bb5c3c8d6e012af37fe45d1169..08c6e7023d698ee37381f8b56bd80c37df7149d6 100644 --- a/Runtime/ChromeDevtools/Protocol/DOM/DOM.cs +++ b/Runtime/ChromeDevtools/Protocol/DOM/DOM.cs @@ -1,3 +1,9 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +#nullable enable annotations namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM { #region commands @@ -5,30 +11,35 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Describes node given its id, does not require domain to be enabled. Does not start tracking any /// objects, can be used for automation. /// </summary> - [CommandResponseAttribute(typeof(describeNodeCommandResponse))] - public class describeNode : IDevtoolsCommand + [CommandResponse(typeof(describeNodeCommandResponse))] + public class describeNode : IDevtoolsCommandWithResponse { /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } /// <summary> /// The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the /// entire subtree or provide an integer larger than 0. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? depth { get; set; } /// <summary> /// Whether or not iframes and shadow roots should be traversed when returning the subtree /// (default is false). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? pierce { get; set; } } @@ -57,6 +68,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Whether to include whitespaces in the children array of returned Nodes. /// </summary> /// <remarks>experimental</remarks> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? includeWhitespace { get; set; } } @@ -68,22 +80,25 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } } /// <summary> /// Returns attributes for the specified node. /// </summary> - [CommandResponseAttribute(typeof(getAttributesCommandResponse))] - public class getAttributes : IDevtoolsCommand + [CommandResponse(typeof(getAttributesCommandResponse))] + public class getAttributes : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to retrieve attibutes for. @@ -99,26 +114,30 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// An interleaved array of node attribute names and values. /// </summary> - public string[] attributes { get; set; } + [JsonConverter(typeof(JsonInterleavedArrayConverter<string, string>))] + public Dictionary<string, string> attributes { get; set; } } /// <summary> /// Returns boxes for the currently selected nodes. /// </summary> - [CommandResponseAttribute(typeof(getBoxModelCommandResponse))] - public class getBoxModel : IDevtoolsCommand + [CommandResponse(typeof(getBoxModelCommandResponse))] + public class getBoxModel : IDevtoolsCommandWithResponse { /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } } @@ -138,18 +157,20 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Returns the root DOM node (and optionally the subtree) to the caller. /// Implicitly enables the DOM domain events for the current target. /// </summary> - [CommandResponseAttribute(typeof(getDocumentCommandResponse))] - public class getDocument : IDevtoolsCommand + [CommandResponse(typeof(getDocumentCommandResponse))] + public class getDocument : IDevtoolsCommandWithResponse { /// <summary> /// The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the /// entire subtree or provide an integer larger than 0. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? depth { get; set; } /// <summary> /// Whether or not iframes and shadow roots should be traversed when returning the subtree /// (default is false). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? pierce { get; set; } } @@ -169,8 +190,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Returns node id at given location. Depending on whether DOM domain is enabled, nodeId is /// either returned or not. /// </summary> - [CommandResponseAttribute(typeof(getNodeForLocationCommandResponse))] - public class getNodeForLocation : IDevtoolsCommand + [CommandResponse(typeof(getNodeForLocationCommandResponse))] + public class getNodeForLocation : IDevtoolsCommandWithResponse { /// <summary> /// X coordinate. @@ -183,10 +204,12 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// False to skip to the nearest non-UA shadow root ancestor (default: false). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? includeUserAgentShadowDOM { get; set; } /// <summary> /// Whether to ignore pointer-events: none on elements and hit test them. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? ignorePointerEventsNone { get; set; } } @@ -198,14 +221,15 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Resulting node. /// </summary> - public int? backendNodeId { get; set; } + public int backendNodeId { get; set; } /// <summary> /// Frame this node belongs to. /// </summary> public string frameId { get; set; } /// <summary> - /// Id of the node at given coordinates. + /// Id of the node at given coordinates, only when enabled and requested document. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } } @@ -213,20 +237,23 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Returns node's HTML markup. /// </summary> - [CommandResponseAttribute(typeof(getOuterHTMLCommandResponse))] - public class getOuterHTML : IDevtoolsCommand + [CommandResponse(typeof(getOuterHTMLCommandResponse))] + public class getOuterHTML : IDevtoolsCommandWithResponse { /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } } @@ -245,6 +272,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Hides any highlight. /// </summary> + /// <remarks>see Overlay.hideHighlight</remarks> public class hideHighlight : IDevtoolsCommand { } @@ -252,6 +280,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Highlights DOM node. /// </summary> + /// <remarks>see Overlay.highlightNode</remarks> public class highlightNode : IDevtoolsCommand { } @@ -259,6 +288,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// highlights given rectangle. /// </summary> + /// <remarks>see Overlay.highlightRect</remarks> public class highlightRect : IDevtoolsCommand { } @@ -266,8 +296,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Moves node into the new container, places it before the given anchor. /// </summary> - [CommandResponseAttribute(typeof(moveToCommandResponse))] - public class moveTo : IDevtoolsCommand + [CommandResponse(typeof(moveToCommandResponse))] + public class moveTo : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to move. @@ -281,6 +311,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Drop node before this one (if absent, the moved node becomes the last child of /// `targetNodeId`). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? insertBeforeNodeId { get; set; } } @@ -299,8 +330,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Executes `querySelector` on a given node. /// </summary> - [CommandResponseAttribute(typeof(querySelectorCommandResponse))] - public class querySelector : IDevtoolsCommand + [CommandResponse(typeof(querySelectorCommandResponse))] + public class querySelector : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to query upon. @@ -327,8 +358,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Executes `querySelectorAll` on a given node. /// </summary> - [CommandResponseAttribute(typeof(querySelectorAllCommandResponse))] - public class querySelectorAll : IDevtoolsCommand + [CommandResponse(typeof(querySelectorAllCommandResponse))] + public class querySelectorAll : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to query upon. @@ -393,11 +424,13 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the /// entire subtree or provide an integer larger than 0. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? depth { get; set; } /// <summary> /// Whether or not iframes and shadow roots should be traversed when returning the sub-tree /// (default is false). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? pierce { get; set; } } @@ -406,8 +439,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// nodes that form the path from the node to the root are also sent to the client as a series of /// `setChildNodes` notifications. /// </summary> - [CommandResponseAttribute(typeof(requestNodeCommandResponse))] - public class requestNode : IDevtoolsCommand + [CommandResponse(typeof(requestNodeCommandResponse))] + public class requestNode : IDevtoolsCommandWithResponse { /// <summary> /// JavaScript object id to convert into node. @@ -426,43 +459,43 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM public int nodeId { get; set; } } -/* // Runtime.RemoteObject is not implemented - - /// <summary> - /// Resolves the JavaScript node object for a given NodeId or BackendNodeId. - /// </summary> - [CommandResponseAttribute(typeof(resolveNodeCommandResponse))] - public class resolveNode : IDevtoolsCommand - { - /// <summary> - /// Id of the node to resolve. - /// </summary> - public int? nodeId { get; set; } - /// <summary> - /// Backend identifier of the node to resolve. - /// </summary> - public int? backendNodeId { get; set; } - /// <summary> - /// Symbolic group name that can be used to release multiple objects. - /// </summary> - public string? objectGroup { get; set; } - /// <summary> - /// Execution context in which to resolve the node. - /// </summary> - public int? executionContextId { get; set; } - } - - /// <summary> - /// Response to <see cref="resolveNode"/> command - /// </summary> - public class resolveNodeCommandResponse : IDevtoolsResponse - { - /// <summary> - /// JavaScript object for given node. - /// </summary> - public Runtime.RemoteObject object_ { get; set; } - } -*/ + /* // Runtime.RemoteObject is not implemented + + /// <summary> + /// Resolves the JavaScript node object for a given NodeId or BackendNodeId. + /// </summary> + [CommandResponse(typeof(resolveNodeCommandResponse))] + public class resolveNode : IDevtoolsCommandWithResponse + { + /// <summary> + /// Id of the node to resolve. + /// </summary> + public int? nodeId { get; set; } + /// <summary> + /// Backend identifier of the node to resolve. + /// </summary> + public int? backendNodeId { get; set; } + /// <summary> + /// Symbolic group name that can be used to release multiple objects. + /// </summary> + public string? objectGroup { get; set; } + /// <summary> + /// Execution context in which to resolve the node. + /// </summary> + public int? executionContextId { get; set; } + } + + /// <summary> + /// Response to <see cref="resolveNode"/> command + /// </summary> + public class resolveNodeCommandResponse : IDevtoolsResponse + { + /// <summary> + /// JavaScript object for given node. + /// </summary> + public Runtime.RemoteObject object_ { get; set; } + } + */ /// <summary> /// Scrolls the specified rect of the given node into view if not already visible. @@ -474,19 +507,23 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } /// <summary> /// The rect to be scrolled into view, relative to the node's border box, in CSS pixels. /// When omitted, center of the node will be used, similar to Element.scrollIntoView. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Rect? rect { get; set; } } @@ -508,6 +545,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// Attribute name to replace with new attributes derived from text in case text parsed /// successfully. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? name { get; set; } } @@ -542,22 +580,25 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Identifier of the node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? nodeId { get; set; } /// <summary> /// Identifier of the backend node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? backendNodeId { get; set; } /// <summary> /// JavaScript object id of the node wrapper. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? objectId { get; set; } } /// <summary> /// Set node name for a node with given id. /// </summary> - [CommandResponseAttribute(typeof(setNodeNameCommandResponse))] - public class setNodeName : IDevtoolsCommand + [CommandResponse(typeof(setNodeNameCommandResponse))] + public class setNodeName : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to set name for. @@ -599,8 +640,8 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Sets node HTML markup, returns new node id. /// </summary> - [CommandResponseAttribute(typeof(setOuterHTMLCommandResponse))] - public class setOuterHTML : IDevtoolsCommand + [CommandResponse(typeof(setOuterHTMLCommandResponse))] + public class setOuterHTML : IDevtoolsCommandWithResponse { /// <summary> /// Id of the node to set markup for. @@ -802,6 +843,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Shape outside coordinates /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public ShapeOutsideInfo? shapeOutside { get; set; } } @@ -850,6 +892,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// The id of the parent node if any. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? parentId { get; set; } /// <summary> /// The BackendNodeId for this node. @@ -874,79 +917,97 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// Child count for `Container` nodes. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? childNodeCount { get; set; } /// <summary> /// Child nodes of this node when requested with children. /// </summary> - public Node[]? children { get; set; } + public List<Node> children { get; set; } /// <summary> /// Attributes of the `Element` node in the form of flat array `[name1, value1, name2, value2]`. /// </summary> - public string[]? attributes { get; set; } + [JsonConverter(typeof(JsonInterleavedArrayConverter<string, string>))] + public Dictionary<string,string> attributes { get; set; } /// <summary> /// Document URL that `Document` or `FrameOwner` node points to. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? documentURL { get; set; } /// <summary> /// Base URL that `Document` or `FrameOwner` node uses for URL completion. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? baseURL { get; set; } /// <summary> /// `DocumentType`'s publicId. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? publicId { get; set; } /// <summary> /// `DocumentType`'s systemId. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? systemId { get; set; } /// <summary> /// `DocumentType`'s internalSubset. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? internalSubset { get; set; } /// <summary> /// `Document`'s XML version in case of XML documents. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? xmlVersion { get; set; } /// <summary> /// `Attr`'s name. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? name { get; set; } /// <summary> /// `Attr`'s value. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? value { get; set; } /// <summary> /// Pseudo element type for this node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public PseudoType? pseudoType { get; set; } /// <summary> /// Pseudo element identifier for this node. Only present if there is a /// valid pseudoType. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? pseudoIdentifier { get; set; } /// <summary> /// Shadow root type. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public ShadowRootType? shadowRootType { get; set; } /// <summary> /// Frame ID for frame owner elements. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string? frameId { get; set; } /// <summary> /// Content document for frame owner elements. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Node? contentDocument { get; set; } /// <summary> /// Shadow root list for given element host. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Node[]? shadowRoots { get; set; } /// <summary> /// Content document fragment for template elements. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Node? templateContent { get; set; } /// <summary> /// Pseudo elements associated with this node. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Node[]? pseudoElements { get; set; } /// <summary> /// Deprecated, as the HTML Imports API has been removed (crbug.com/937746). @@ -954,16 +1015,21 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// The property is always undefined now. /// </summary> /// <remarks>deprecated</remarks> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Node? importedDocument { get; set; } /// <summary> /// Distributed nodes for given insertion point. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public BackendNode[]? distributedNodes { get; set; } /// <summary> /// Whether the node is SVG. /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public bool? isSVG { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public CompatibilityMode? compatibilityMode { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public BackendNode? assignedSlot { get; set; } } @@ -985,6 +1051,17 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM firstLine, firstLetter, before, after, marker, backdrop, selection, targetText, spellingError, grammarError, highlight, firstLineInherited, scrollbar, scrollbarThumb, scrollbarButton, scrollbarTrack, scrollbarTrackPiece, scrollbarCorner, resizer, inputListButton, viewTransition, viewTransitionGroup, viewTransitionImagePair, viewTransitionOld, viewTransitionNew } + /// <summary> + /// An array of quad vertices, x immediately followed by y for each point, points clock-wise. + /// </summary> + public class Quad + { + /// <summary> + /// Quad vertices + /// </summary> + public double[] quad { get; set; } + } + /// <summary> /// Rectangle. /// </summary> @@ -1028,6 +1105,7 @@ namespace bessw.Unity.WebView.ChromeDevTools.Protocol.DOM /// <summary> /// The alpha component, in the [0-1] range (default: 1). /// </summary> + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public double? a { get; set; } } diff --git a/Runtime/ChromeDevtools/Protocol/DOM/DOM_api.json.meta b/Runtime/ChromeDevtools/Protocol/DOM/DOM_api.json.meta new file mode 100644 index 0000000000000000000000000000000000000000..364952ee6bbef02e3a8304724cee2d6fba45b288 --- /dev/null +++ b/Runtime/ChromeDevtools/Protocol/DOM/DOM_api.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f4e9b65319713e3478ca1d350419f8c4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/ChromeDevtools/Protocol/Input/Input.cs b/Runtime/ChromeDevtools/Protocol/Input/Input.cs index c15cfcd846025913b5efde647d1b18c9122a41d9..cd1fedb411b48a0b670bd951b7e324e4040df26e 100644 --- a/Runtime/ChromeDevtools/Protocol/Input/Input.cs +++ b/Runtime/ChromeDevtools/Protocol/Input/Input.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json.Serialization; using UnityEngine.EventSystems; using static UnityEngine.EventSystems.PointerEventData; +#nullable enable annotations namespace bessw.Unity.WebView.ChromeDevTools.Protocol.Input { #region dispatchMouseEvent diff --git a/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs b/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs new file mode 100644 index 0000000000000000000000000000000000000000..17842d57f5473705da181902cd0abce211f53527 --- /dev/null +++ b/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; + +namespace bessw.Unity.WebView.ChromeDevTools.Protocol +{ + /// <summary> + /// Converts a interleaved JSON array like `[key1, value1, key2, value2, ...]` to a C# dictionary. + /// </summary> + /// <typeparam name="keyT"></typeparam> + /// <typeparam name="valueT"></typeparam> + public class JsonInterleavedArrayConverter<keyT, valueT> : JsonConverter<Dictionary<keyT,valueT>> + { + public override void WriteJson(JsonWriter writer, Dictionary<keyT,valueT> value, JsonSerializer serializer) + { + JArray obj = new JArray(); + + foreach (var pair in value) + { + obj.Add(pair.Key); + obj.Add(pair.Value); + } + obj.WriteTo(writer); + } + + public override Dictionary<keyT,valueT> ReadJson(JsonReader reader, Type objectType, Dictionary<keyT,valueT> existingValue, bool hasExistingValue, JsonSerializer serializer) + { + JArray obj = JArray.Load(reader); + Dictionary<keyT,valueT> result = new Dictionary<keyT,valueT>(); + + for (int i = 0; i < obj.Count; i+=2) + { + result.Add(obj[i].Value<keyT>(), obj[i+1].Value<valueT>()); + } + return result; + } + } +} \ No newline at end of file diff --git a/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs.meta b/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..bafd844b3942abbba3d77faac6d85c89b7bd99d3 --- /dev/null +++ b/Runtime/ChromeDevtools/Protocol/JsonInterleavedArrayConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31c472a5e6adcf247b4e0d9835835e75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/WebViewComponent.cs b/Runtime/WebViewComponent.cs index fa94db7f2cac7188bc05cb44471306c61509c253..76dad434bc110f261ea9eb7b7e536010ac9184dd 100644 --- a/Runtime/WebViewComponent.cs +++ b/Runtime/WebViewComponent.cs @@ -39,7 +39,7 @@ namespace bessw.Unity.WebView #endregion json serializer private Browser browser; - private BrowserTab tab; + protected BrowserTab tab; private RawImage rawImage; private RectTransform rectTransform; @@ -87,6 +87,32 @@ namespace bessw.Unity.WebView }); } + private IEnumerator getDropzoneState () + { + Debug.LogWarning($"dropzone pre"); + + DomNodeWrapper doc = null; + yield return DomNodeWrapper.getDocument(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}'"); + + // alternative way to get the dropzone state + + } + // Update is called once per frame private void Update() { @@ -132,12 +158,13 @@ namespace bessw.Unity.WebView } } - // TODO: OnDragMove -> PointerMove - public void OnDrop(PointerEventData eventData) { Debug.LogWarning($"OnDrop: {eventData.position}"); createDragEvent(DragEventType.drop, eventData); + + // TODO: remove debug code + StartCoroutine(getDropzoneState()); } public void OnPointerExit(PointerEventData eventData) diff --git a/WebViewComponent.prefab b/WebViewComponent.prefab index 4b9baec086607a73417a9ba579b51fa31a96f159..9bf29f6cb7b4a9d52efc2d792d3af8da26f08e5b 100644 --- a/WebViewComponent.prefab +++ b/WebViewComponent.prefab @@ -34,11 +34,11 @@ RectTransform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -444.39624, y: -175.33963} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0.5, y: 0.5} + m_Pivot: {x: 0, y: 0} --- !u!222 &5559415116192402672 CanvasRenderer: m_ObjectHideFlags: 0 @@ -87,3 +87,4 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: headlessBrowser: 1 + targetUrl: https://google.de