diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9ba02cb8..664974b2 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -123,6 +123,8 @@ 0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; }; 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; }; 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; }; + 27F6B08826051831008529AA /* MoleculeTreeTraversalProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */; }; + 27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */; }; 27F973532466074500CAB5C5 /* PageBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F973522466074500CAB5C5 /* PageBehavior.swift */; }; 27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */; }; 31BE15CB23D8924D00452370 /* CheckboxLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */; }; @@ -679,6 +681,8 @@ 0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = ""; }; 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = ""; }; + 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTreeTraversalProtocol.swift; sourceTree = ""; }; + 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentMoleculeModelProtocol.swift; sourceTree = ""; }; 27F973522466074500CAB5C5 /* PageBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageBehavior.swift; sourceTree = ""; }; 27F97369246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenBrightnessModifierBehavior.swift; sourceTree = ""; }; 31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxLabelModel.swift; sourceTree = ""; }; @@ -1147,6 +1151,7 @@ D2092354244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift */, D2509ED02472ED9B001BFB9D /* NavigationItemModelProtocol.swift */, D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */, + 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */, ); path = ModelProtocols; sourceTree = ""; @@ -2275,6 +2280,7 @@ isa = PBXGroup; children = ( 012A88C7238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift */, + 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */, 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */, D20F3B43252E00E4004B3F56 /* PageProtocol.swift */, 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, @@ -2820,6 +2826,7 @@ 0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */, D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */, AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */, + 27F6B08826051831008529AA /* MoleculeTreeTraversalProtocol.swift in Sources */, D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */, @@ -2945,6 +2952,7 @@ 8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */, D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */, 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, + 27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */, 0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */, D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */, 94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift index d4da0ba4..c767dc36 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/TwoButtonViewModel.swift @@ -9,7 +9,7 @@ import UIKit -public class TwoButtonViewModel: MoleculeModelProtocol { +public class TwoButtonViewModel: ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -19,6 +19,10 @@ public class TwoButtonViewModel: MoleculeModelProtocol { public var primaryButton: ButtonModel? public var secondaryButton: ButtonModel? + public var children: [MoleculeModelProtocol] { + return [primaryButton, secondaryButton].compactMap { $0 } + } + //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/Items/TabsListItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/TabsListItemModel.swift index c83b8933..d0f13c1f 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/TabsListItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/TabsListItemModel.swift @@ -12,7 +12,7 @@ public class TabsListItemModel: ListItemModel, MoleculeModelProtocol { public static var identifier: String = "tabsListItem" var tabs: TabsModel var molecules: [[ListItemModelProtocol & MoleculeModelProtocol]] - + private enum CodingKeys: String, CodingKey { case moleculeName case tabs diff --git a/MVMCoreUI/Atomic/Molecules/OtherContainers/BGVideoImageMoleculeModel.swift b/MVMCoreUI/Atomic/Molecules/OtherContainers/BGVideoImageMoleculeModel.swift index f2ee20af..6b9a89c3 100644 --- a/MVMCoreUI/Atomic/Molecules/OtherContainers/BGVideoImageMoleculeModel.swift +++ b/MVMCoreUI/Atomic/Molecules/OtherContainers/BGVideoImageMoleculeModel.swift @@ -15,6 +15,10 @@ open class BGVideoImageMoleculeModel: BGImageMoleculeModel { public var video: VideoModel + public override var children: [MoleculeModelProtocol] { + return [video, molecule] + } + private enum CodingKeys: String, CodingKey { case video } diff --git a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerModel.swift b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerModel.swift index 77b40716..5ddec277 100644 --- a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerModel.swift +++ b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerModel.swift @@ -15,6 +15,10 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco public var backgroundColor: Color? public var molecule: MoleculeModelProtocol + public var children: [MoleculeModelProtocol] { + return [molecule] + } + private enum CodingKeys: String, CodingKey { case moleculeName case molecule @@ -40,7 +44,7 @@ open class MoleculeContainerModel: ContainerModel, MoleculeContainerModelProtoco backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) try super.init(from: decoder) } - + open override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) diff --git a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift index 882cf181..1e34932f 100644 --- a/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift +++ b/MVMCoreUI/Atomic/Molecules/OtherContainers/MoleculeContainerProtocol.swift @@ -8,6 +8,14 @@ import Foundation -public protocol MoleculeContainerModelProtocol: ContainerModelProtocol { +public protocol MoleculeContainerModelProtocol: ContainerModelProtocol, ParentMoleculeModelProtocol { var molecule: MoleculeModelProtocol { get set } } + +public extension MoleculeContainerModelProtocol { + + var children: [MoleculeModelProtocol] { + return [molecule] + } + +} diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index ebc5614e..a7ff7280 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -9,7 +9,7 @@ import Foundation -@objcMembers open class HeadlineBodyModel: MoleculeModelProtocol { +@objcMembers open class HeadlineBodyModel: ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -21,6 +21,10 @@ import Foundation public var style: Style? public var backgroundColor: Color? + public var children: [MoleculeModelProtocol] { + return [headline, body].compactMap { $0 } + } + //-------------------------------------------------- // MARK: - Enum //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift index 5bf0728c..8721db72 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel/CarouselModel.swift @@ -9,7 +9,7 @@ import UIKit -@objcMembers public class CarouselModel: MoleculeModelProtocol, FormFieldProtocol { +@objcMembers public class CarouselModel: ParentMoleculeModelProtocol, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties @@ -144,3 +144,11 @@ import UIKit try container.encode(selectedIndex, forKey: .selectedIndex) } } + +extension CarouselModel { + + public var children: [MoleculeModelProtocol] { + return molecules + } + +} diff --git a/MVMCoreUI/Atomic/Organisms/StackModel.swift b/MVMCoreUI/Atomic/Organisms/StackModel.swift index d96da035..8b1dcc0f 100644 --- a/MVMCoreUI/Atomic/Organisms/StackModel.swift +++ b/MVMCoreUI/Atomic/Organisms/StackModel.swift @@ -7,7 +7,8 @@ // -@objcMembers public class StackModel: ContainerModel, StackModelProtocol, MoleculeModelProtocol { +@objcMembers public class StackModel: ContainerModel, StackModelProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -24,6 +25,10 @@ public var spacing: CGFloat = StackModel.defaultSpacing public var useStackSpacingBeforeFirstItem = false + public var children: [MoleculeModelProtocol] { + return molecules + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- @@ -77,4 +82,5 @@ try container.encode(moleculeName, forKey: .moleculeName) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } + } diff --git a/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift b/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift index 54f6c9d0..068418f0 100644 --- a/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift +++ b/MVMCoreUI/Atomic/Organisms/StackModelProtocol.swift @@ -8,9 +8,15 @@ import Foundation -public protocol StackModelProtocol { +public protocol StackModelProtocol: ParentMoleculeModelProtocol { var molecules: [StackItemModelProtocol & MoleculeModelProtocol] { get set } var axis: NSLayoutConstraint.Axis { get set } var spacing: CGFloat { get set } var useStackSpacingBeforeFirstItem: Bool { get set } } + +extension StackModelProtocol { + + public var children: [MoleculeModelProtocol] { return molecules } + +} diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift index a998b79d..79368f01 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift @@ -7,7 +7,7 @@ public enum MolecularError: Swift.Error { } -public protocol MoleculeModelProtocol: ModelProtocol, AccessibilityModelProtocol { +public protocol MoleculeModelProtocol: ModelProtocol, AccessibilityModelProtocol, MoleculeTreeTraversalProtocol { var moleculeName: String { get } var backgroundColor: Color? { get set } } @@ -20,3 +20,55 @@ public extension MoleculeModelProtocol { static var categoryCodingKey: String { "moleculeName" } } + +public extension MoleculeModelProtocol { + + // Base case. No additional children to traverse. + func reduceDepthFirstTraverse(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int)->Result) -> Result { + return nextPartialResult(initialResult, self, depth) + } + + // Base case. No additional children to traverse. + func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol)->Void) { + onVisit(depth, self) + } + +} + +public extension Array where Element == MoleculeModelProtocol { + + func reduceDepthFirstTraverse(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int)->Result) -> Result { + return reduce(initialResult) { (result, molecule) -> Result in + return molecule.reduceDepthFirstTraverse(options: options, depth: depth, initialResult: result, nextPartialResult: nextPartialResult) + } + } + + func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol)->Void) { + forEach { (molecule) in + molecule.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit) + } + } +} + +// Would prefer these to be defined in MoleculeTreeTraversalProtocol that MoleculeModelProtocol inherits. +public extension Array where Element == MoleculeModelProtocol { + + func countMolecules() -> Int { + return reduce(0) { (accumulator, molecule) in + return accumulator + molecule.countMolecules() + } + } + + func printMolecules() { + forEach { (molecule) in + molecule.printMolecules() + } + } + + func allMoleculesOfType() -> [T] { + return reduce([]) { (accumulator, molecule) in + return accumulator + molecule.allMoleculesOfType() + } + } + +} diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift new file mode 100644 index 00000000..2ec05db4 --- /dev/null +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift @@ -0,0 +1,55 @@ +// +// ParentModelProtocol.swift +// MVMCoreUI +// +// Created by Kyle on 3/19/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol ParentMoleculeModelProtocol: MoleculeModelProtocol { + + var children: [MoleculeModelProtocol] { get } + +} + +public extension ParentMoleculeModelProtocol { + + func reduceDepthFirstTraverse(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result { + var result = initialResult + if (options == .parentFirst) { + result = nextPartialResult(result, self, depth) + } + result = children.reduce(result) { (result, molecule) -> Result in + if let additionalParent = molecule as? ParentMoleculeModelProtocol { + // Safety net to make sure the ParentMoleculeModelProtocol's method extension is called over the base MoleculeModelProtocol. + return additionalParent.reduceDepthFirstTraverse(options: options, depth: depth + 1, initialResult: result, nextPartialResult: nextPartialResult) + } + return molecule.reduceDepthFirstTraverse(options: options, depth: depth + 1, initialResult: result, nextPartialResult: nextPartialResult) + } + if (options == .childFirst) { + result = nextPartialResult(result, self, depth) + } + // if options == .leafOnly don't call on self. + return result + } + + func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol)->Void) { + if (options == .parentFirst) { + onVisit(depth, self) + } + children.forEach { (molecule) in + if let additionalParent = molecule as? ParentMoleculeModelProtocol { + // Safety net to make sure the ParentMoleculeModelProtocol's method extension is called over the base MoleculeModelProtocol. + additionalParent.depthFirstTraverse(options: options, depth: depth + 1, onVisit: onVisit) + } else { + molecule.depthFirstTraverse(options: options, depth: depth + 1, onVisit: onVisit) + } + } + if (options == .childFirst) { + onVisit(depth, self) + } + // if options == .leafOnly don't call on self. + } +} diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift index 3ed37d6b..1f9db75b 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/TemplateModelProtocol.swift @@ -9,8 +9,9 @@ import Foundation -public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol { +public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, MoleculeTreeTraversalProtocol { var template: String { get } + var rootMolecules: [MoleculeModelProtocol] { get } } public extension TemplateModelProtocol { @@ -26,4 +27,12 @@ public extension TemplateModelProtocol { static var categoryName: String { return "\(TemplateModelProtocol.self)" } + + func reduceDepthFirstTraverse(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int) -> Result) -> Result { + return rootMolecules.reduceDepthFirstTraverse(options: options, depth: depth, initialResult: initialResult, nextPartialResult: nextPartialResult) + } + + func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol) -> Void) { + return rootMolecules.depthFirstTraverse(options: options, depth: depth, onVisit: onVisit) + } } diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift new file mode 100644 index 00000000..4e7efabb --- /dev/null +++ b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift @@ -0,0 +1,54 @@ + +// +// TreeTraversalProtocol.swift +// MVMCoreUI +// +// Created by Kyle on 3/19/21. +// Copyright © 2021 Verizon Wireless. All rights reserved. +// + +public enum TreeTraversalOptions { + case parentFirst + case childFirst + case leafNodesOnly +} + +public protocol MoleculeTreeTraversalProtocol { + + // Future options -- Parent first depth first, leaves only. + + func reduceDepthFirstTraverse(options: TreeTraversalOptions, depth: Int, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol, Int)->Result) -> Result + + func depthFirstTraverse(options: TreeTraversalOptions, depth: Int, onVisit: (Int, MoleculeModelProtocol)->Void) + + //func breadthFirstTraverse() +} + +// +// Helper Extensions +// + +extension MoleculeTreeTraversalProtocol { + + func countMolecules(options: TreeTraversalOptions = .parentFirst) -> Int { + return reduceDepthFirstTraverse(options: options, depth: 0, initialResult: 0) { (accumulator, molecule, depth) in + return accumulator + 1 + } + } + + func printMolecules(options: TreeTraversalOptions = .parentFirst) { + depthFirstTraverse(options: options, depth: 1) { (depth, molecule) in + print("\(String(repeating: ">>", count: depth)) \"\(molecule.moleculeName)\" [\(molecule)]") + } + } + + func allMoleculesOfType(options: TreeTraversalOptions = .parentFirst) -> [T] { + return reduceDepthFirstTraverse(options: options, depth: 0, initialResult: []) { (accumulator, molecule, depth) in + if let typedMolecule = molecule as? T { + return accumulator + [typedMolecule] + } + return accumulator + } + } + +} diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift index f9d8c0a7..b0f3ae92 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift @@ -18,6 +18,13 @@ import Foundation } public var molecules: [CollectionItemModelProtocol & MoleculeModelProtocol]? public var columns: Int? + + public override var rootMolecules: [MoleculeModelProtocol] { + if let molecules = molecules { + return super.rootMolecules + molecules + } + return super.rootMolecules + } //-------------------------------------------------- // MARK: - Initializer diff --git a/MVMCoreUI/Atomic/Templates/ListPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/ListPageTemplateModel.swift index a7c92a08..44868e10 100644 --- a/MVMCoreUI/Atomic/Templates/ListPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/ListPageTemplateModel.swift @@ -20,6 +20,13 @@ import Foundation public var line: LineModel? public var scrollToRowIndex: Int? + public override var rootMolecules: [MoleculeModelProtocol] { + if let molecules = molecules { + return super.rootMolecules + molecules + } + return super.rootMolecules + } + /// This template requires content. func validateModelHasContent() throws { if header == nil, diff --git a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift index f21a0421..6491bd8d 100644 --- a/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/StackPageTemplateModel.swift @@ -15,6 +15,10 @@ import Foundation } public var moleculeStack: StackModel + public override var rootMolecules: [MoleculeModelProtocol] { + return [header, moleculeStack, footer].compactMap { $0 } + } + public init(pageType: String, moleculeStack: StackModel) { self.moleculeStack = moleculeStack super.init(pageType: pageType) diff --git a/MVMCoreUI/Atomic/Templates/TemplateModel.swift b/MVMCoreUI/Atomic/Templates/TemplateModel.swift index bb8bb104..c3d9bbbb 100644 --- a/MVMCoreUI/Atomic/Templates/TemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/TemplateModel.swift @@ -30,6 +30,7 @@ import Foundation public var navigationBar: (NavigationItemModelProtocol & MoleculeModelProtocol)? public var formRules: [FormGroupRule]? public var behaviors: [PageBehaviorProtocol]? + public var rootMolecules: [MoleculeModelProtocol] { [] } public var tabBarHidden: Bool = false public var tabBarIndex: Int? diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift index 1120b0e7..25e7d1e9 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift @@ -9,11 +9,16 @@ import Foundation @objcMembers open class ThreeLayerModelBase: TemplateModel, ThreeLayerTemplateModelProtocol { + public var anchorHeader: Bool = false public var header: MoleculeModelProtocol? public var anchorFooter: Bool = false public var footer: MoleculeModelProtocol? + public override var rootMolecules: [MoleculeModelProtocol] { + return [header, footer].compactMap { $0 } + } + public override init(pageType: String) { super.init(pageType: pageType) } diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift index c4e93f7a..ced0b9ab 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift @@ -14,6 +14,13 @@ import Foundation } public var middle: MoleculeModelProtocol? + public override var rootMolecules: [MoleculeModelProtocol] { + if let middle = middle { + return super.rootMolecules + [middle] + } + return super.rootMolecules + } + public init(pageType: String, header: MoleculeModelProtocol?, middle: MoleculeModelProtocol?, footer: MoleculeModelProtocol?) { super.init(pageType: pageType) self.header = header