From 332810035b16b5889e8c973e77d4a1ca7015c704 Mon Sep 17 00:00:00 2001 From: Vasyl Horbachenko Date: Tue, 7 Apr 2020 17:43:08 +0300 Subject: [PATCH] Added more patch classes: replace and insert as sibling --- UIExtenderLib/Prefab/Patches.cs | 33 ++++++++ UIExtenderLibModule/Prefab/PrefabComponent.cs | 80 +++++++++++++++---- UIExtenderLibModule/UIExtenderLibModule.cs | 8 ++ 3 files changed, 104 insertions(+), 17 deletions(-) diff --git a/UIExtenderLib/Prefab/Patches.cs b/UIExtenderLib/Prefab/Patches.cs index 7ebd868..e7999c9 100644 --- a/UIExtenderLib/Prefab/Patches.cs +++ b/UIExtenderLib/Prefab/Patches.cs @@ -9,11 +9,17 @@ public interface IPrefabPatch { } + /** + * Custom patch on either whole XmlDocument (if T is XmlDocument) or Xpath specified node (if XmlNode is the generic argument) + */ public abstract class CustomPatch : IPrefabPatch where T: XmlNode { public abstract void Apply(T document); } + /** + * Base class for insert patches + */ public abstract class InsertPatch : IPrefabPatch { public static int PositionFirst = 0; @@ -22,8 +28,35 @@ public abstract class InsertPatch : IPrefabPatch public abstract int Position { get; } } + /** + * Patch that inserts prefab extension (specified by `Name`) as a child in XPath specified node, at specific position (`Position` property) + */ public abstract class PrefabExtensionInsertPatch: InsertPatch { public abstract string Name { get; } } + + /** + * Patch that replaces node specified by XPath with node from prefab extension + */ + public abstract class PrefabExtensionReplacePatch : IPrefabPatch + { + public abstract string Name { get; } + } + + /** + * Patch that inserts prefab extension as a sibling to node specified by Xpath. + * Order is controlled by `Type` property. + */ + public abstract class PrefabExtensionInsertAsSiblingPatch + { + public enum InsertType + { + Prepend, + Append, + } + + public virtual InsertType Type => InsertType.Append; + public abstract string Name { get; } + } } \ No newline at end of file diff --git a/UIExtenderLibModule/Prefab/PrefabComponent.cs b/UIExtenderLibModule/Prefab/PrefabComponent.cs index dfb058e..8d61ada 100644 --- a/UIExtenderLibModule/Prefab/PrefabComponent.cs +++ b/UIExtenderLibModule/Prefab/PrefabComponent.cs @@ -27,7 +27,7 @@ internal class PrefabComponent internal void RegisterPatch(string movie, Action patcher) { Debug.Assert(movie != null && !movie.IsEmpty(), $"Invalid movie name: {movie}!"); - + _moviePatches.Get(movie, () => new List>()).Add(patcher); } @@ -50,7 +50,7 @@ internal void RegisterPatch(string movie, string xpath, Action patcher) } /** - * Register Gauntlet movie XML insert patch. + * Register XML insert patch */ internal void RegisterPatch(string movie, string xpath, PrefabExtensionInsertPatch patch) { @@ -58,28 +58,53 @@ internal void RegisterPatch(string movie, string xpath, PrefabExtensionInsertPat RegisterPatch(movie, xpath, (node) => { - var path = _prefabExtensionPaths[patch.Name]; - var doc = new XmlDocument(); - - using (var reader = XmlReader.Create(path, new XmlReaderSettings - { - IgnoreComments = true, - IgnoreWhitespace = true, - })) - { - doc.Load(reader); - } - - Debug.Assert(doc.HasChildNodes, $"Failed to parse extension ({patch.Name}) XML!"); - var newNode = node.OwnerDocument.ImportNode(doc.DocumentElement, true); + var extensionNode = LoadPrefabExtension(patch.Name); + var importedExtensionNode = node.OwnerDocument.ImportNode(extensionNode, true); var position = Math.Min(patch.Position, node.ChildNodes.Count - 1); position = Math.Max(position, 0); Debug.Assert(position >= 0 && position < node.ChildNodes.Count, $"Invalid position ({position}) for insert (patching in {patch.Name})"); - node.InsertAfter(newNode, node.ChildNodes[position]); + node.InsertAfter(importedExtensionNode, node.ChildNodes[position]); + }); + } + + /** + * Register XML replace patch + */ + internal void RegisterPatch(string movie, string xpath, PrefabExtensionReplacePatch patch) + { + RegisterPatch(movie, xpath, (node) => + { + var extensionNode = LoadPrefabExtension(patch.Name); + var importedExtensionNode = node.OwnerDocument.ImportNode(extensionNode, true); + + node.ParentNode.ReplaceChild(importedExtensionNode, node); }); } + /** + * Register XML sibling insert patch + */ + internal void RegisterPatch(string movie, string xpath, PrefabExtensionInsertAsSiblingPatch patch) + { + RegisterPatch(movie, xpath, (node) => + { + var extensionNode = LoadPrefabExtension(patch.Name); + var importedExtensionNode = node.OwnerDocument.ImportNode(extensionNode, true); + + switch (patch.Type) + { + case PrefabExtensionInsertAsSiblingPatch.InsertType.Append: + node.ParentNode.InsertAfter(importedExtensionNode, node); + break; + + case PrefabExtensionInsertAsSiblingPatch.InsertType.Prepend: + node.ParentNode.InsertBefore(importedExtensionNode, node); + break; + } + }); + } + /** * Search loaded modules for PrefabExtensions and save them for further reference */ @@ -101,6 +126,27 @@ internal void FindPrefabExtensions() } } + /** + * Load and parse prefab extension + */ + private XmlNode LoadPrefabExtension(string name) + { + var path = _prefabExtensionPaths[name]; + var doc = new XmlDocument(); + + using (var reader = XmlReader.Create(path, new XmlReaderSettings + { + IgnoreComments = true, + IgnoreWhitespace = true, + })) + { + doc.Load(reader); + } + + Debug.Assert(doc.HasChildNodes, $"Failed to parse extension ({name}) XML!"); + return doc.DocumentElement; + } + /** * Make WidgetFactory reload Movies that were extended by _moviePatches. * diff --git a/UIExtenderLibModule/UIExtenderLibModule.cs b/UIExtenderLibModule/UIExtenderLibModule.cs index 0d42719..f448ed7 100644 --- a/UIExtenderLibModule/UIExtenderLibModule.cs +++ b/UIExtenderLibModule/UIExtenderLibModule.cs @@ -46,6 +46,14 @@ protected override void OnBeforeInitialModuleScreenSetAsRoot() WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; + case PrefabExtensionReplacePatch patch: + WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); + break; + + case PrefabExtensionInsertAsSiblingPatch patch: + WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); + break; + case CustomPatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, patch.Apply); break;