new mole
This commit is contained in:
parent
8b49de569d
commit
d078753828
@ -114,8 +114,8 @@
|
|||||||
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; };
|
0ABD1371237DB0450081388D /* ItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */; };
|
||||||
0AD93A9F24C0AA5100E56A97 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; };
|
0AD93A9F24C0AA5100E56A97 /* ImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7918F423F5E7EA00772FF4 /* ImageView.swift */; };
|
||||||
0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; };
|
0AE14F64238315D2005417F8 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE14F63238315D2005417F8 /* TextField.swift */; };
|
||||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEndryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277E825D2ED4B0048A38D /* MultiItemDropdownEndryField.swift */; };
|
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */; };
|
||||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEndryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277EB25D2EE310048A38D /* MultiItemDropdownEndryFieldModel.swift */; };
|
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */; };
|
||||||
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BAE23FEF956004C5109 /* ExternalLink.swift */; };
|
0AE98BAF23FEF956004C5109 /* ExternalLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BAE23FEF956004C5109 /* ExternalLink.swift */; };
|
||||||
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */; };
|
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */; };
|
||||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
|
||||||
@ -661,8 +661,8 @@
|
|||||||
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = "<group>"; };
|
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||||
0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
0AE14F63238315D2005417F8 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEndryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEndryField.swift; sourceTree = "<group>"; };
|
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryField.swift; sourceTree = "<group>"; };
|
||||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEndryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEndryFieldModel.swift; sourceTree = "<group>"; };
|
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiItemDropdownEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
0AE98BAE23FEF956004C5109 /* ExternalLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLink.swift; sourceTree = "<group>"; };
|
0AE98BAE23FEF956004C5109 /* ExternalLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLink.swift; sourceTree = "<group>"; };
|
||||||
0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkModel.swift; sourceTree = "<group>"; };
|
0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkModel.swift; sourceTree = "<group>"; };
|
||||||
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
|
||||||
@ -2051,8 +2051,8 @@
|
|||||||
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
0ABD1370237DB0450081388D /* ItemDropdownEntryField.swift */,
|
||||||
0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */,
|
0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */,
|
||||||
0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */,
|
0A25209524645AFD000FA9F6 /* TextViewEntryField.swift */,
|
||||||
0AE277EB25D2EE310048A38D /* MultiItemDropdownEndryFieldModel.swift */,
|
0AE277EB25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift */,
|
||||||
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEndryField.swift */,
|
0AE277E825D2ED4B0048A38D /* MultiItemDropdownEntryField.swift */,
|
||||||
);
|
);
|
||||||
path = TextFields;
|
path = TextFields;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2458,7 +2458,7 @@
|
|||||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||||
0AE277EC25D2EE310048A38D /* MultiItemDropdownEndryFieldModel.swift in Sources */,
|
0AE277EC25D2EE310048A38D /* MultiItemDropdownEntryFieldModel.swift in Sources */,
|
||||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */,
|
||||||
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */,
|
||||||
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */,
|
||||||
@ -2473,7 +2473,7 @@
|
|||||||
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */,
|
||||||
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */,
|
94382086243238D100B43AF3 /* WebViewModel.swift in Sources */,
|
||||||
D28764F9245A327200CB882D /* TwoLinkView.swift in Sources */,
|
D28764F9245A327200CB882D /* TwoLinkView.swift in Sources */,
|
||||||
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEndryField.swift in Sources */,
|
0AE277E925D2ED4B0048A38D /* MultiItemDropdownEntryField.swift in Sources */,
|
||||||
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
|
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */,
|
||||||
0A6682B5243769C700AD3CA1 /* TextView.swift in Sources */,
|
0A6682B5243769C700AD3CA1 /* TextView.swift in Sources */,
|
||||||
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
|
D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */,
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import UIKit
|
|||||||
public var baseDropdownEntryFieldModel: BaseDropdownEntryFieldModel? {
|
public var baseDropdownEntryFieldModel: BaseDropdownEntryFieldModel? {
|
||||||
model as? BaseDropdownEntryFieldModel
|
model as? BaseDropdownEntryFieldModel
|
||||||
}
|
}
|
||||||
|
|
||||||
var additionalData: [AnyHashable: Any]?
|
var additionalData: [AnyHashable: Any]?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -29,7 +29,7 @@ open class ItemDropdownEntryField: BaseDropdownEntryField {
|
|||||||
public var observeDropdownSelection: ((String)->())?
|
public var observeDropdownSelection: ((String)->())?
|
||||||
|
|
||||||
public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? {
|
public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? {
|
||||||
return model as? ItemDropdownEntryFieldModel
|
model as? ItemDropdownEntryFieldModel
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -16,10 +16,14 @@
|
|||||||
public var options: [String] = []
|
public var options: [String] = []
|
||||||
public var selectedIndex: Int?
|
public var selectedIndex: Int?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Validation
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public override func formFieldValue() -> AnyHashable? {
|
public override func formFieldValue() -> AnyHashable? {
|
||||||
guard !options.isEmpty,
|
guard !options.isEmpty,
|
||||||
let index = selectedIndex
|
let index = selectedIndex
|
||||||
else { return nil }
|
else { return nil }
|
||||||
|
|
||||||
return options[index]
|
return options[index]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,210 +0,0 @@
|
|||||||
//
|
|
||||||
// MultiItemDropdownEndryField.swift
|
|
||||||
// MVMCoreUI
|
|
||||||
//
|
|
||||||
// Created by Kevin Christiano on 2/9/21.
|
|
||||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
class MultiItemDropdownEndryField {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
//
|
|
||||||
// ItemDropdownEntryField.swift
|
|
||||||
// MVMCoreUI
|
|
||||||
//
|
|
||||||
// Created by Kevin Christiano on 11/14/19.
|
|
||||||
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
public typealias TextFieldAndPickerDelegate = (UITextFieldDelegate & UIPickerViewDelegate & UIPickerViewDataSource)
|
|
||||||
|
|
||||||
|
|
||||||
open class ItemDropdownEntryField: BaseDropdownEntryField {
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Outlets
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open var pickerView: UIPickerView?
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// Datasource of the picker view.
|
|
||||||
open var pickerComponents: [[String]] {
|
|
||||||
dropdownModel?.options ?? [[]]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
|
||||||
public var setInitialValueInTextField = true
|
|
||||||
|
|
||||||
/// Closure passed here will run as picker changes items.
|
|
||||||
public var observeDropdownChange: ((String, String) -> ())?
|
|
||||||
|
|
||||||
/// Closure passed here will run upon dismissing the selection picker.
|
|
||||||
public var observeDropdownSelection: ((String) -> ())?
|
|
||||||
|
|
||||||
public var dropdownModel: ItemDropdownEntryFieldModel? {
|
|
||||||
model as? ItemDropdownEntryFieldModel
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The number of components available
|
|
||||||
public var componentCount: Int {
|
|
||||||
pickerComponents.count
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Initializers
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
@objc public override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public convenience init() {
|
|
||||||
self.init(frame: .zero)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc required public init?(coder: NSCoder) {
|
|
||||||
fatalError("ItemDropdownEntryField init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
|
||||||
super.init(model: model, delegateObject, additionalData)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Methods
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
|
||||||
super.setupFieldContainerContent(container)
|
|
||||||
|
|
||||||
pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
|
||||||
textField.hideBlinkingCaret = true
|
|
||||||
textField.autocorrectionType = .no
|
|
||||||
uiTextFieldDelegate = self
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
|
||||||
|
|
||||||
pickerView?.delegate = delegate
|
|
||||||
pickerView?.dataSource = delegate
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the textField with the first value of the available picker data.
|
|
||||||
@objc private func setInitialValueFromPicker() {
|
|
||||||
|
|
||||||
guard setInitialValueInTextField,
|
|
||||||
!pickerComponents.isEmpty,
|
|
||||||
let rowText = dropdownModel?.selectedRowText
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
observeDropdownChange?(text ?? "", rowText)
|
|
||||||
text = rowText
|
|
||||||
|
|
||||||
for component in 0..<componentCount {
|
|
||||||
let pickerIndex = pickerView?.selectedRow(inComponent: component)
|
|
||||||
dropdownModel?.selectedIndicies[component] = pickerIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - TextField Observation
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// Observing action of the textfield for initial interaction with the picker.
|
|
||||||
@objc override func startEditing() {
|
|
||||||
super.startEditing()
|
|
||||||
|
|
||||||
setInitialValueFromPicker()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Observing action for when the user has ended inputting with the picker.
|
|
||||||
@objc override func endInputing() {
|
|
||||||
super.endInputing()
|
|
||||||
|
|
||||||
guard !pickerComponents.isEmpty,
|
|
||||||
let rowText = dropdownModel?.selectedRowText
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
observeDropdownSelection?(rowText)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - MoleculeViewProtocol
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
|
||||||
super.set(with: model, delegateObject, additionalData)
|
|
||||||
|
|
||||||
guard let model = model as? ItemDropdownEntryFieldModel else { return }
|
|
||||||
|
|
||||||
setPickerDelegates(delegate: self)
|
|
||||||
|
|
||||||
if let pickerView = pickerView {
|
|
||||||
for (component, index) in model.selectedIndicies {
|
|
||||||
self.pickerView(pickerView, didSelectRow: index, inComponent: component)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK:- Picker Delegate
|
|
||||||
extension ItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
|
||||||
|
|
||||||
@objc public func numberOfComponents(in pickerView: UIPickerView) -> Int { componentCount }
|
|
||||||
|
|
||||||
@objc public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
|
||||||
pickerComponents[component].count
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
|
||||||
|
|
||||||
guard !pickerComponents.isEmpty,
|
|
||||||
!pickerComponents[component].isEmpty
|
|
||||||
else { return nil }
|
|
||||||
|
|
||||||
return pickerComponents[component][row]
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
|
||||||
|
|
||||||
guard !pickerComponents.isEmpty,
|
|
||||||
!pickerComponents[component].isEmpty,
|
|
||||||
let rowText = dropdownModel?.selectedRowText
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
observeDropdownChange?(text ?? "", rowText)
|
|
||||||
text = rowText
|
|
||||||
dropdownModel?.selectedIndicies[component] = row
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Accessibility
|
|
||||||
extension ItemDropdownEntryField {
|
|
||||||
|
|
||||||
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
|
||||||
|
|
||||||
var accessibilityString = accessibilityString ?? ""
|
|
||||||
|
|
||||||
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
|
||||||
accessibilityString += textPickerItem
|
|
||||||
}
|
|
||||||
|
|
||||||
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
//
|
|
||||||
// MultiItemDropdownEndryFieldModel.swift
|
|
||||||
// MVMCoreUI
|
|
||||||
//
|
|
||||||
// Created by Kevin Christiano on 2/9/21.
|
|
||||||
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
class MultiItemDropdownEndryFieldModel {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
@objcMembers open class ItemDropdownEntryFieldModel: BaseDropdownEntryFieldModel {
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Properties
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public override class var identifier: String { "dropDown" }
|
|
||||||
|
|
||||||
public var options: [[String]] = [[]]
|
|
||||||
public var selectedIndicies: [Int: Int] = [:]
|
|
||||||
|
|
||||||
@available(*, deprecated, message: "Here for backwards compatibility for when this options was a single array.")
|
|
||||||
public var selectedIndex: Int?
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Validation
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public override func formFieldValue() -> AnyHashable? {
|
|
||||||
|
|
||||||
guard !options.isEmpty && !selectedIndicies.isEmpty else { return nil }
|
|
||||||
|
|
||||||
return selectedRowText
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A string of the picker row concatenated by whitespace.
|
|
||||||
public var selectedRowText: String {
|
|
||||||
|
|
||||||
var text = ""
|
|
||||||
|
|
||||||
for i in 0..<options.count {
|
|
||||||
let pickerIndex = selectedIndicies[i] ?? 0
|
|
||||||
text += options[i][pickerIndex] + (i == options.count - 1 ? "" : " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
||||||
public var selectedIndiciesArray: [Int] {
|
|
||||||
|
|
||||||
var indexArray: [Int] = []
|
|
||||||
|
|
||||||
for i in 0..<selectedIndicies.count {
|
|
||||||
guard let selectIndex = selectedIndicies[i] else { return [] }
|
|
||||||
indexArray.append(selectIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
return indexArray
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Keys
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
private enum CodingKeys: String, CodingKey {
|
|
||||||
case options
|
|
||||||
case selectedIndex // Deprecated: for backwards compatability
|
|
||||||
case selectedIndicies
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Initializers
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
|
||||||
try super.init(from: decoder)
|
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
|
||||||
|
|
||||||
if let singleOptions = try? typeContainer.decodeIfPresent([String].self, forKey: .options) {
|
|
||||||
options = [singleOptions]
|
|
||||||
} else {
|
|
||||||
options = try typeContainer.decode([[String]].self, forKey: .options)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let selectedIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .selectedIndex) {
|
|
||||||
self.selectedIndicies[0] = selectedIndex
|
|
||||||
}
|
|
||||||
|
|
||||||
if let index = self.selectedIndicies[0] {
|
|
||||||
baseValue = options.indices.contains(index) ? options[index] : nil
|
|
||||||
|
|
||||||
} else if let indicies = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndicies) {
|
|
||||||
for (component, index) in indicies.enumerated() {
|
|
||||||
self.selectedIndicies[component] = index
|
|
||||||
}
|
|
||||||
|
|
||||||
baseValue = selectedRowText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override func encode(to encoder: Encoder) throws {
|
|
||||||
try super.encode(to: encoder)
|
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
||||||
try container.encode(options, forKey: .options)
|
|
||||||
try container.encodeIfPresent(options, forKey: .selectedIndex)
|
|
||||||
try container.encode(selectedIndiciesArray, forKey: .selectedIndicies)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
//
|
||||||
|
// MultiItemDropdownEndryField.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/9/21.
|
||||||
|
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class MultiItemDropdownEntryField: BaseDropdownEntryField {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Outlets
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open var pickerView: UIPickerView?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Datasource of the picker view.
|
||||||
|
open var pickerComponents: [[String]] {
|
||||||
|
dropdownModel?.options ?? [[]]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When selecting for first responder, allow initial selected value to appear in empty text field.
|
||||||
|
public var setInitialValueInTextField = true
|
||||||
|
|
||||||
|
/// Closure passed here will run as picker changes items.
|
||||||
|
// public var observeDropdownChange: ((String, String) -> ())?
|
||||||
|
|
||||||
|
/// Closure passed here will run upon dismissing the selection picker.
|
||||||
|
// public var observeDropdownSelection: ((String) -> ())?
|
||||||
|
|
||||||
|
public var dropdownModel: MultiItemDropdownEntryFieldModel? {
|
||||||
|
model as? MultiItemDropdownEntryFieldModel
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The number of components available
|
||||||
|
public var componentCount: Int {
|
||||||
|
pickerComponents.count
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
@objc public override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public convenience init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc required public init?(coder: NSCoder) {
|
||||||
|
fatalError("MultiItemDropdownEntryField init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.init(model: model, delegateObject, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Methods
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
@objc open override func setupFieldContainerContent(_ container: UIView) {
|
||||||
|
super.setupFieldContainerContent(container)
|
||||||
|
|
||||||
|
pickerView = UIPickerView.addPicker(to: textField, delegate: self, dismissAction: #selector(dismissFieldInput))
|
||||||
|
textField.hideBlinkingCaret = true
|
||||||
|
textField.autocorrectionType = .no
|
||||||
|
uiTextFieldDelegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func setPickerDelegates(delegate: UIPickerViewDelegate & UIPickerViewDataSource) {
|
||||||
|
|
||||||
|
pickerView?.delegate = delegate
|
||||||
|
pickerView?.dataSource = delegate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the textField with the first value of the available picker data.
|
||||||
|
@objc private func setInitialValueFromPicker() {
|
||||||
|
|
||||||
|
guard setInitialValueInTextField,
|
||||||
|
!pickerComponents.isEmpty,
|
||||||
|
let rowText = dropdownModel?.selectedRowText
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
// observeDropdownChange?(text ?? "", rowText)
|
||||||
|
text = rowText
|
||||||
|
|
||||||
|
for component in 0..<componentCount {
|
||||||
|
let pickerIndex = pickerView?.selectedRow(inComponent: component)
|
||||||
|
dropdownModel?.selectedIndexes[component] = pickerIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - TextField Observation
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/// Observing action of the textfield for initial interaction with the picker.
|
||||||
|
@objc override func startEditing() {
|
||||||
|
super.startEditing()
|
||||||
|
|
||||||
|
setInitialValueFromPicker()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Observing action for when the user has ended inputting with the picker.
|
||||||
|
@objc override func endInputing() {
|
||||||
|
super.endInputing()
|
||||||
|
|
||||||
|
guard !pickerComponents.isEmpty,
|
||||||
|
let rowText = dropdownModel?.selectedRowText
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
// observeDropdownSelection?(rowText)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let model = model as? MultiItemDropdownEntryFieldModel else { return }
|
||||||
|
|
||||||
|
setPickerDelegates(delegate: self)
|
||||||
|
|
||||||
|
if let pickerView = pickerView {
|
||||||
|
for (component, index) in model.selectedIndexes {
|
||||||
|
self.pickerView(pickerView, didSelectRow: index, inComponent: component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK:- Picker Delegate
|
||||||
|
extension MultiItemDropdownEntryField: UIPickerViewDelegate, UIPickerViewDataSource {
|
||||||
|
|
||||||
|
@objc public func numberOfComponents(in pickerView: UIPickerView) -> Int { componentCount }
|
||||||
|
|
||||||
|
@objc public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
|
||||||
|
pickerComponents[component].count
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
|
||||||
|
|
||||||
|
guard !pickerComponents.isEmpty,
|
||||||
|
!pickerComponents[component].isEmpty
|
||||||
|
else { return nil }
|
||||||
|
|
||||||
|
return pickerComponents[component][row]
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||||
|
|
||||||
|
guard !pickerComponents.isEmpty,
|
||||||
|
!pickerComponents[component].isEmpty,
|
||||||
|
let rowText = dropdownModel?.selectedRowText
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
// observeDropdownChange?(text ?? "", rowText)
|
||||||
|
text = rowText
|
||||||
|
dropdownModel?.selectedIndexes[component] = row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Accessibility
|
||||||
|
extension MultiItemDropdownEntryField {
|
||||||
|
|
||||||
|
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
|
||||||
|
|
||||||
|
var accessibilityString = accessibilityString ?? ""
|
||||||
|
|
||||||
|
if let textPickerItem = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item") {
|
||||||
|
accessibilityString += textPickerItem
|
||||||
|
}
|
||||||
|
|
||||||
|
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
//
|
||||||
|
// MultiItemDropdownEntryFieldModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 2/9/21.
|
||||||
|
// Copyright © 2021 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
@objcMembers open class MultiItemDropdownEntryFieldModel: BaseDropdownEntryFieldModel {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override class var identifier: String { "multiDropdown" }
|
||||||
|
|
||||||
|
public var options: [[String]] = [[]]
|
||||||
|
public var selectedIndexes: [Int: Int] = [:]
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Validation
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public override func formFieldValue() -> AnyHashable? {
|
||||||
|
|
||||||
|
guard !options.isEmpty && !selectedIndexes.isEmpty else { return nil }
|
||||||
|
|
||||||
|
return selectedRowText
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A string of the picker row concatenated by whitespace.
|
||||||
|
public var selectedRowText: String {
|
||||||
|
|
||||||
|
var text = ""
|
||||||
|
|
||||||
|
for i in 0..<options.count {
|
||||||
|
let pickerIndex = selectedIndexes[i] ?? 0
|
||||||
|
text += options[i][pickerIndex] + (i == options.count - 1 ? "" : " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
public var selectedIndexesArray: [Int] {
|
||||||
|
|
||||||
|
var indexArray: [Int] = []
|
||||||
|
|
||||||
|
for i in 0..<selectedIndexes.count {
|
||||||
|
guard let selectIndex = selectedIndexes[i] else { return [] }
|
||||||
|
indexArray.append(selectIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexArray
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case options
|
||||||
|
case selectedIndex // Deprecated: for backwards compatability
|
||||||
|
case selectedIndexes
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializers
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
try super.init(from: decoder)
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
|
options = try typeContainer.decode([[String]].self, forKey: .options)
|
||||||
|
|
||||||
|
if let indicies = try typeContainer.decodeIfPresent([Int].self, forKey: .selectedIndexes) {
|
||||||
|
for (component, index) in indicies.enumerated() {
|
||||||
|
self.selectedIndexes[component] = index
|
||||||
|
}
|
||||||
|
|
||||||
|
baseValue = selectedRowText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func encode(to encoder: Encoder) throws {
|
||||||
|
try super.encode(to: encoder)
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encode(options, forKey: .options)
|
||||||
|
try container.encode(selectedIndexesArray, forKey: .selectedIndexes)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -235,6 +235,11 @@ import UIKit
|
|||||||
/// Executes on UITextField.textDidBeginEditingNotification
|
/// Executes on UITextField.textDidBeginEditingNotification
|
||||||
@objc override func startEditing() {
|
@objc override func startEditing() {
|
||||||
super.startEditing()
|
super.startEditing()
|
||||||
|
|
||||||
|
if textEntryFieldModel?.clearTextOnTap ?? false {
|
||||||
|
text = ""
|
||||||
|
}
|
||||||
|
|
||||||
textField.becomeFirstResponder()
|
textField.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,8 @@
|
|||||||
public var textAlignment: NSTextAlignment = .left
|
public var textAlignment: NSTextAlignment = .left
|
||||||
public var keyboardOverride: String?
|
public var keyboardOverride: String?
|
||||||
public var type: EntryType?
|
public var type: EntryType?
|
||||||
|
public var clearTextOnTap: Bool = false
|
||||||
|
public var displayFormat: String?
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
@ -98,6 +100,8 @@
|
|||||||
case disabledTextColor
|
case disabledTextColor
|
||||||
case keyboardOverride
|
case keyboardOverride
|
||||||
case type
|
case type
|
||||||
|
case clearTextOnTap
|
||||||
|
case displayFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -109,9 +113,14 @@
|
|||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder)
|
placeholder = try typeContainer.decodeIfPresent(String.self, forKey: .placeholder)
|
||||||
|
displayFormat = try typeContainer.decodeIfPresent(String.self, forKey: .displayFormat)
|
||||||
keyboardOverride = try typeContainer.decodeIfPresent(String.self, forKey: .keyboardOverride)
|
keyboardOverride = try typeContainer.decodeIfPresent(String.self, forKey: .keyboardOverride)
|
||||||
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
|
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
|
||||||
|
|
||||||
|
if let clearTextOnTap = try typeContainer.decodeIfPresent(Bool.self, forKey: .clearTextOnTap) {
|
||||||
|
self.clearTextOnTap = clearTextOnTap
|
||||||
|
}
|
||||||
|
|
||||||
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) {
|
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTextColor) {
|
||||||
self.enabledTextColor = enabledTextColor
|
self.enabledTextColor = enabledTextColor
|
||||||
}
|
}
|
||||||
@ -131,8 +140,10 @@
|
|||||||
try container.encodeIfPresent(placeholder, forKey: .placeholder)
|
try container.encodeIfPresent(placeholder, forKey: .placeholder)
|
||||||
try container.encodeIfPresent(textAlignment, forKey: .textAlignment)
|
try container.encodeIfPresent(textAlignment, forKey: .textAlignment)
|
||||||
try container.encodeIfPresent(type, forKey: .type)
|
try container.encodeIfPresent(type, forKey: .type)
|
||||||
|
try container.encodeIfPresent(displayFormat, forKey: .displayFormat)
|
||||||
try container.encodeIfPresent(keyboardOverride, forKey: .keyboardOverride)
|
try container.encodeIfPresent(keyboardOverride, forKey: .keyboardOverride)
|
||||||
try container.encode(enabledTextColor, forKey: .enabledTextColor)
|
try container.encode(enabledTextColor, forKey: .enabledTextColor)
|
||||||
try container.encode(disabledTextColor, forKey: .disabledTextColor)
|
try container.encode(disabledTextColor, forKey: .disabledTextColor)
|
||||||
|
try container.encode(clearTextOnTap, forKey: .clearTextOnTap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,7 @@ import Foundation
|
|||||||
MoleculeObjectMapping.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self)
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self)
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self)
|
||||||
|
MoleculeObjectMapping.shared()?.register(viewClass: MultiItemDropdownEntryField.self, viewModelClass: MultiItemDropdownEntryFieldModel.self)
|
||||||
|
|
||||||
// MARK:- Selectors
|
// MARK:- Selectors
|
||||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
|
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user