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/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/Protocols/ModelProtocols/MoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift index 03c9c596..f7927a1b 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/MoleculeModelProtocol.swift @@ -23,28 +23,29 @@ public extension MoleculeModelProtocol { public extension MoleculeModelProtocol { - func reduceDepthFirstTraverse(initialResult:Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result { - + // Base case. No additional children to traverse. + func reduceDepthFirstTraverse(options: TreeTraversalOptions, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result { return nextPartialResult(initialResult, self) } - func depthFirstTraverse(callback: (MoleculeModelProtocol)->Void) { - callback(self) + // Base case. No additional children to traverse. + func depthFirstTraverse(options: TreeTraversalOptions, onVisit: (MoleculeModelProtocol)->Void) { + onVisit(self) } } public extension Array where Element == MoleculeModelProtocol { - func reduceDepthFirstTraverse(initialResult:Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result { + func reduceDepthFirstTraverse(options: TreeTraversalOptions, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result { return reduce(initialResult) { (result, molecule) -> Result in - return molecule.reduceDepthFirstTraverse(initialResult: result, nextPartialResult: nextPartialResult) + return molecule.reduceDepthFirstTraverse(options: options, initialResult: result, nextPartialResult: nextPartialResult) } } - func depthFirstTraverse(callback: (MoleculeModelProtocol)->Void) { + func depthFirstTraverse(options: TreeTraversalOptions, callback: (MoleculeModelProtocol)->Void) { forEach { (molecule) in - molecule.depthFirstTraverse(callback: callback) + molecule.depthFirstTraverse(options: options, onVisit: callback) } } } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift index 5afa57f7..a1d9d225 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/ParentMoleculeModelProtocol.swift @@ -16,24 +16,39 @@ public protocol ParentMoleculeModelProtocol: MoleculeModelProtocol { public extension ParentMoleculeModelProtocol { - func reduceDepthFirstTraverse(initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol) -> Result) -> Result { - - let result = children.reduce(initialResult) { (result, molecule) -> Result in - if let additionalParent = molecule as? ParentMoleculeModelProtocol { - return additionalParent.reduceDepthFirstTraverse(initialResult: result, nextPartialResult: nextPartialResult) - } - return molecule.reduceDepthFirstTraverse(initialResult: result, nextPartialResult: nextPartialResult) + func reduceDepthFirstTraverse(options: TreeTraversalOptions, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol) -> Result) -> Result { + var result = initialResult + if (options == .parentFirst) { + result = nextPartialResult(result, self) } - return nextPartialResult(result, self) + 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, initialResult: result, nextPartialResult: nextPartialResult) + } + return molecule.reduceDepthFirstTraverse(options: options, initialResult: result, nextPartialResult: nextPartialResult) + } + if (options == .childFirst) { + result = nextPartialResult(result, self) + } + // if options == .leafOnly don't call on self. + return result } - func depthFirstTraverse(callback: (MoleculeModelProtocol)->Void) { + func depthFirstTraverse(options: TreeTraversalOptions, onVisit: (MoleculeModelProtocol)->Void) { + if (options == .parentFirst) { + onVisit(self) + } children.forEach { (molecule) in if let additionalParent = molecule as? ParentMoleculeModelProtocol { - additionalParent.depthFirstTraverse(callback: callback) + // Safety net to make sure the ParentMoleculeModelProtocol's method extension is called over the base MoleculeModelProtocol. + additionalParent.depthFirstTraverse(options: options, onVisit: onVisit) } - molecule.depthFirstTraverse(callback: callback) + molecule.depthFirstTraverse(options: options, onVisit: onVisit) } - callback(self) + if (options == .childFirst) { + onVisit(self) + } + // if options == .leafOnly don't call on self. } } diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift index dc5ff7f2..137d8a77 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeTreeTraversalProtocol.swift @@ -7,13 +7,19 @@ // 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(initialResult:Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result + func reduceDepthFirstTraverse(options: TreeTraversalOptions, initialResult: Result, nextPartialResult: (Result, MoleculeModelProtocol)->Result) -> Result - func depthFirstTraverse(callback: (MoleculeModelProtocol)->Void) + func depthFirstTraverse(options: TreeTraversalOptions, onVisit: (MoleculeModelProtocol)->Void) //func breadthFirstTraverse() } @@ -24,20 +30,20 @@ public protocol MoleculeTreeTraversalProtocol { extension MoleculeTreeTraversalProtocol { - func countMolecules() -> Int { - return reduceDepthFirstTraverse(initialResult: 0) { (accumulator, molecule) in + func countMolecules(options: TreeTraversalOptions = .parentFirst) -> Int { + return reduceDepthFirstTraverse(options: options, initialResult: 0) { (accumulator, molecule) in return accumulator + 1 } } - func printMolecules() { - depthFirstTraverse { (molecule) in - print(molecule) + func printMolecules(options: TreeTraversalOptions = .parentFirst) { + depthFirstTraverse(options: options) { (molecule) in + print("\"\(molecule.moleculeName)\" [\(molecule)]") } } - func allMoleculesOfType() -> [T] { - return reduceDepthFirstTraverse(initialResult: []) { (accumulator, molecule) in + func allMoleculesOfType(options: TreeTraversalOptions = .parentFirst) -> [T] { + return reduceDepthFirstTraverse(options: options, initialResult: []) { (accumulator, molecule) in if let typedMolecule = molecule as? T { return accumulator + [typedMolecule] } diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift index 405a94ce..25e7d1e9 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerModelBase.swift @@ -16,14 +16,7 @@ import Foundation public var footer: MoleculeModelProtocol? public override var rootMolecules: [MoleculeModelProtocol] { - var rootMolecules:[MoleculeModelProtocol] = [] - if let header = header { - rootMolecules.append(header) - } - if let footer = footer { - rootMolecules.append(footer) - } - return rootMolecules + return [header, footer].compactMap { $0 } } public override init(pageType: String) {