Row.swift 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Row.swift
  2. // Eureka ( https://github.com/xmartlabs/Eureka )
  3. //
  4. // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com )
  5. //
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. import Foundation
  25. open class RowOf<T>: BaseRow where T: Equatable {
  26. private var _value: T? {
  27. didSet {
  28. guard _value != oldValue else { return }
  29. guard let form = section?.form else { return }
  30. if let delegate = form.delegate {
  31. delegate.valueHasBeenChanged(for: self, oldValue: oldValue, newValue: value)
  32. callbackOnChange?()
  33. }
  34. guard let t = tag else { return }
  35. form.tagToValues[t] = (value != nil ? value! : NSNull())
  36. if let rowObservers = form.rowObservers[t]?[.hidden] {
  37. for rowObserver in rowObservers {
  38. (rowObserver as? Hidable)?.evaluateHidden()
  39. }
  40. }
  41. if let rowObservers = form.rowObservers[t]?[.disabled] {
  42. for rowObserver in rowObservers {
  43. (rowObserver as? Disableable)?.evaluateDisabled()
  44. }
  45. }
  46. }
  47. }
  48. /// The typed value of this row.
  49. open var value: T? {
  50. set (newValue) {
  51. _value = newValue
  52. guard let _ = section?.form else { return }
  53. wasChanged = true
  54. if validationOptions.contains(.validatesOnChange) || (wasBlurred && validationOptions.contains(.validatesOnChangeAfterBlurred)) || (!isValid && validationOptions != .validatesOnDemand) {
  55. validate()
  56. }
  57. }
  58. get {
  59. return _value
  60. }
  61. }
  62. /// The reset value of this row. Sets the value property to the value of this row on the resetValue method call.
  63. open var resetValue: T?
  64. /// The untyped value of this row.
  65. public override var baseValue: Any? {
  66. get { return value }
  67. set { value = newValue as? T }
  68. }
  69. /// Block variable used to get the String that should be displayed for the value of this row.
  70. public var displayValueFor: ((T?) -> String?)? = {
  71. return $0.map { String(describing: $0) }
  72. }
  73. public required init(tag: String?) {
  74. super.init(tag: tag)
  75. }
  76. public internal(set) var rules: [ValidationRuleHelper<T>] = []
  77. @discardableResult
  78. public override func validate(quietly: Bool = false) -> [ValidationError] {
  79. var vErrors = [ValidationError]()
  80. #if swift(>=4.1)
  81. vErrors = rules.compactMap { $0.validateFn(value) }
  82. #else
  83. vErrors = rules.flatMap { $0.validateFn(value) }
  84. #endif
  85. if (!quietly) {
  86. validationErrors = vErrors
  87. }
  88. return vErrors
  89. }
  90. /// Resets the value of the row. Setting it's value to it's reset value.
  91. public func resetRowValue() {
  92. value = resetValue
  93. }
  94. /// Add a Validation rule for the Row
  95. /// - Parameter rule: RuleType object to add
  96. public func add<Rule: RuleType>(rule: Rule) where T == Rule.RowValueType {
  97. let validFn: ((T?) -> ValidationError?) = { (val: T?) in
  98. return rule.isValid(value: val)
  99. }
  100. rules.append(ValidationRuleHelper(validateFn: validFn, rule: rule))
  101. }
  102. /// Add a Validation rule set for the Row
  103. /// - Parameter ruleSet: RuleSet<T> set of rules to add
  104. public func add(ruleSet: RuleSet<T>) {
  105. rules.append(contentsOf: ruleSet.rules)
  106. }
  107. public func remove(ruleWithIdentifier identifier: String) {
  108. if let index = rules.firstIndex(where: { (validationRuleHelper) -> Bool in
  109. return validationRuleHelper.rule.id == identifier
  110. }) {
  111. rules.remove(at: index)
  112. }
  113. }
  114. public func removeAllRules() {
  115. validationErrors.removeAll()
  116. rules.removeAll()
  117. }
  118. }
  119. /// Generic class that represents an Eureka row.
  120. open class Row<Cell: CellType>: RowOf<Cell.Value>, TypedRowType where Cell: BaseCell {
  121. /// Responsible for creating the cell for this row.
  122. public var cellProvider = CellProvider<Cell>()
  123. /// The type of the cell associated to this row.
  124. public let cellType: Cell.Type! = Cell.self
  125. private var _cell: Cell! {
  126. didSet {
  127. RowDefaults.cellSetup["\(type(of: self))"]?(_cell, self)
  128. (callbackCellSetup as? ((Cell) -> Void))?(_cell)
  129. }
  130. }
  131. /// The cell associated to this row.
  132. public var cell: Cell! {
  133. return _cell ?? {
  134. let result = cellProvider.makeCell(style: self.cellStyle)
  135. result.row = self
  136. result.setup()
  137. _cell = result
  138. return _cell
  139. }()
  140. }
  141. /// The untyped cell associated to this row
  142. public override var baseCell: BaseCell { return cell }
  143. public required init(tag: String?) {
  144. super.init(tag: tag)
  145. }
  146. /**
  147. Method that reloads the cell
  148. */
  149. override open func updateCell() {
  150. super.updateCell()
  151. cell.update()
  152. customUpdateCell()
  153. RowDefaults.cellUpdate["\(type(of: self))"]?(cell, self)
  154. callbackCellUpdate?()
  155. }
  156. /**
  157. Method called when the cell belonging to this row was selected. Must call the corresponding method in its cell.
  158. */
  159. open override func didSelect() {
  160. super.didSelect()
  161. if !isDisabled {
  162. cell?.didSelect()
  163. }
  164. customDidSelect()
  165. callbackCellOnSelection?()
  166. }
  167. /**
  168. Will be called inside `didSelect` method of the row. Can be used to customize row selection from the definition of the row.
  169. */
  170. open func customDidSelect() {}
  171. /**
  172. Will be called inside `updateCell` method of the row. Can be used to customize reloading a row from its definition.
  173. */
  174. open func customUpdateCell() {}
  175. }