mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
Image builders support
commit_hash:13f6ef6aa582c24314dac2d1f087dfcefabdd017
This commit is contained in:
@@ -21050,6 +21050,7 @@
|
||||
"client/ios/DivKit/Extensions/DivSwitchExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivSwitchExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTabsExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTabsExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTextExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTextExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTextImageBuilderExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTextImageBuilderExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTextRangeBuilderExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTextRangeBuilderExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTooltipExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTooltipExtensions.swift",
|
||||
"client/ios/DivKit/Extensions/DivTransformExtensions.swift":"divkit/public/client/ios/DivKit/Extensions/DivTransformExtensions.swift",
|
||||
@@ -23276,6 +23277,7 @@
|
||||
"client/ios/Tests/reference_snapshots/div-text/image-background_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/image-background_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/image-reverse-indexing_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/image-reverse-indexing_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/image-tint-mode_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/image-tint-mode_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/image_builder_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/image_builder_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/images_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/images_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/line-height/multi-line-text-with-image_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/line-height/multi-line-text-with-image_414@3x.png",
|
||||
"client/ios/Tests/reference_snapshots/div-text/line-height/multi-line-text-with-text-size-ranges_414@3x.png":"divkit/public/client/ios/Tests/reference_snapshots/div-text/line-height/multi-line-text-with-text-size-ranges_414@3x.png",
|
||||
@@ -29641,6 +29643,7 @@
|
||||
"test_data/snapshot_test_data/div-text/image-background.json":"divkit/public/test_data/snapshot_test_data/div-text/image-background.json",
|
||||
"test_data/snapshot_test_data/div-text/image-reverse-indexing.json":"divkit/public/test_data/snapshot_test_data/div-text/image-reverse-indexing.json",
|
||||
"test_data/snapshot_test_data/div-text/image-tint-mode.json":"divkit/public/test_data/snapshot_test_data/div-text/image-tint-mode.json",
|
||||
"test_data/snapshot_test_data/div-text/image_builder.json":"divkit/public/test_data/snapshot_test_data/div-text/image_builder.json",
|
||||
"test_data/snapshot_test_data/div-text/images.json":"divkit/public/test_data/snapshot_test_data/div-text/images.json",
|
||||
"test_data/snapshot_test_data/div-text/images_hyphenation.json":"divkit/public/test_data/snapshot_test_data/div-text/images_hyphenation.json",
|
||||
"test_data/snapshot_test_data/div-text/line-height/multi-line-text-with-image.json":"divkit/public/test_data/snapshot_test_data/div-text/line-height/multi-line-text-with-image.json",
|
||||
|
||||
@@ -109,8 +109,7 @@ extension DivText: DivBlockModeling {
|
||||
}
|
||||
|
||||
let images = makeInlineImages(
|
||||
context: context,
|
||||
images: self.images,
|
||||
images: makeImages(self.images, imageBuilder: imageBuilder, context: context),
|
||||
text: attributedString
|
||||
)
|
||||
|
||||
@@ -124,8 +123,7 @@ extension DivText: DivBlockModeling {
|
||||
)
|
||||
}
|
||||
let truncationImages = makeInlineImages(
|
||||
context: context,
|
||||
images: ellipsis?.images,
|
||||
images: makeImages(ellipsis?.images, imageBuilder: nil, context: context),
|
||||
text: truncationToken
|
||||
)
|
||||
|
||||
@@ -183,17 +181,17 @@ extension DivText: DivBlockModeling {
|
||||
}
|
||||
|
||||
private func makeInlineImages(
|
||||
context: DivBlockModelingContext,
|
||||
images: [Image]?,
|
||||
images: [(Image, DivBlockModelingContext)],
|
||||
text: NSAttributedString?
|
||||
) -> [TextBlock.InlineImage] {
|
||||
guard let text else {
|
||||
return []
|
||||
}
|
||||
return (images ?? []).compactMap {
|
||||
$0.makeImage(
|
||||
context: context,
|
||||
textLength: CFAttributedStringGetLength(text)
|
||||
let textLength = CFAttributedStringGetLength(text)
|
||||
return images.compactMap { image, imageContext in
|
||||
image.makeImage(
|
||||
context: imageContext,
|
||||
textLength: textLength
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import Foundation
|
||||
import LayoutKit
|
||||
import VGSL
|
||||
|
||||
extension DivText {
|
||||
func makeImages(
|
||||
_ images: [Image]?,
|
||||
imageBuilder: ImageBuilder?,
|
||||
context: DivBlockModelingContext
|
||||
) -> [(Image, DivBlockModelingContext)] {
|
||||
if let imageBuilder {
|
||||
return imageBuilder.makeImages(context: context)
|
||||
}
|
||||
return (images ?? []).map { ($0, context) }
|
||||
}
|
||||
}
|
||||
|
||||
extension DivText.ImageBuilder {
|
||||
func makeImages(
|
||||
context: DivBlockModelingContext
|
||||
) -> [(DivText.Image, DivBlockModelingContext)] {
|
||||
let items = resolveData(context.expressionResolver) ?? []
|
||||
return items.enumerated().compactMap { index, item -> (
|
||||
DivText.Image,
|
||||
DivBlockModelingContext
|
||||
)? in
|
||||
let itemDict = item as? DivDictionary ?? [:]
|
||||
let itemContext = context.modifying(
|
||||
pathSuffix: String(index),
|
||||
prototypeParams: PrototypeParams(
|
||||
index: index,
|
||||
variableName: dataElementName,
|
||||
value: itemDict
|
||||
)
|
||||
)
|
||||
itemContext.variablesStorage.initializeIfNeeded(path: itemContext.path, variables: [
|
||||
DivVariableName(rawValue: dataElementName): .dict(itemDict),
|
||||
"index": .integer(index),
|
||||
])
|
||||
guard let prototype = prototypes.first(where: {
|
||||
$0.resolveSelector(itemContext.expressionResolver)
|
||||
}) else {
|
||||
return nil
|
||||
}
|
||||
return (prototype.image, itemContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +167,61 @@ public final class DivText: DivBase, @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ImageBuilder: @unchecked Sendable {
|
||||
public final class Prototype: Sendable {
|
||||
public let image: Image
|
||||
public let selector: Expression<Bool> // default value: true
|
||||
|
||||
public func resolveSelector(_ resolver: ExpressionResolver) -> Bool {
|
||||
resolver.resolveNumeric(selector) ?? true
|
||||
}
|
||||
|
||||
public convenience init(dictionary: [String: Any], context: ParsingContext) throws {
|
||||
self.init(
|
||||
image: try dictionary.getField("image", transform: { (dict: [String: Any]) in try DivText.Image(dictionary: dict, context: context) }, context: context),
|
||||
selector: try dictionary.getOptionalExpressionField("selector", context: context)
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
image: Image,
|
||||
selector: Expression<Bool>? = nil
|
||||
) {
|
||||
self.image = image
|
||||
self.selector = selector ?? .value(true)
|
||||
}
|
||||
}
|
||||
|
||||
public let data: Expression<[Any]>
|
||||
public let dataElementName: String // default value: it
|
||||
public let prototypes: [Prototype] // at least 1 elements
|
||||
|
||||
public func resolveData(_ resolver: ExpressionResolver) -> [Any]? {
|
||||
resolver.resolveArray(data)
|
||||
}
|
||||
|
||||
static let prototypesValidator: AnyArrayValueValidator<DivText.ImageBuilder.Prototype> =
|
||||
makeArrayValidator(minItems: 1)
|
||||
|
||||
public convenience init(dictionary: [String: Any], context: ParsingContext) throws {
|
||||
self.init(
|
||||
data: try dictionary.getExpressionField("data", context: context),
|
||||
dataElementName: try dictionary.getOptionalField("data_element_name", context: context),
|
||||
prototypes: try dictionary.getArray("prototypes", transform: { (dict: [String: Any]) in try? DivText.ImageBuilder.Prototype(dictionary: dict, context: context) }, validator: Self.prototypesValidator, context: context)
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
data: Expression<[Any]>,
|
||||
dataElementName: String? = nil,
|
||||
prototypes: [Prototype]
|
||||
) {
|
||||
self.data = data
|
||||
self.dataElementName = dataElementName ?? "it"
|
||||
self.prototypes = prototypes
|
||||
}
|
||||
}
|
||||
|
||||
public final class Range: @unchecked Sendable {
|
||||
public let actions: [DivAction]?
|
||||
public let alignmentVertical: Expression<DivTextAlignmentVertical>?
|
||||
@@ -440,6 +495,7 @@ public final class DivText: DivBase, @unchecked Sendable {
|
||||
public let hoverEndActions: [DivAction]?
|
||||
public let hoverStartActions: [DivAction]?
|
||||
public let id: String?
|
||||
public let imageBuilder: ImageBuilder?
|
||||
public let images: [Image]?
|
||||
public let layoutProvider: DivLayoutProvider?
|
||||
public let letterSpacing: Expression<Double> // default value: 0
|
||||
@@ -661,6 +717,7 @@ public final class DivText: DivBase, @unchecked Sendable {
|
||||
hoverEndActions: try dictionary.getOptionalArray("hover_end_actions", transform: { (dict: [String: Any]) in try? DivAction(dictionary: dict, context: context) }),
|
||||
hoverStartActions: try dictionary.getOptionalArray("hover_start_actions", transform: { (dict: [String: Any]) in try? DivAction(dictionary: dict, context: context) }),
|
||||
id: try dictionary.getOptionalField("id", context: context),
|
||||
imageBuilder: try dictionary.getOptionalField("image_builder", transform: { (dict: [String: Any]) in try DivText.ImageBuilder(dictionary: dict, context: context) }),
|
||||
images: try dictionary.getOptionalArray("images", transform: { (dict: [String: Any]) in try? DivText.Image(dictionary: dict, context: context) }),
|
||||
layoutProvider: try dictionary.getOptionalField("layout_provider", transform: { (dict: [String: Any]) in try DivLayoutProvider(dictionary: dict, context: context) }),
|
||||
letterSpacing: try dictionary.getOptionalExpressionField("letter_spacing", context: context),
|
||||
@@ -736,6 +793,7 @@ public final class DivText: DivBase, @unchecked Sendable {
|
||||
hoverEndActions: [DivAction]? = nil,
|
||||
hoverStartActions: [DivAction]? = nil,
|
||||
id: String? = nil,
|
||||
imageBuilder: ImageBuilder? = nil,
|
||||
images: [Image]? = nil,
|
||||
layoutProvider: DivLayoutProvider? = nil,
|
||||
letterSpacing: Expression<Double>? = nil,
|
||||
@@ -808,6 +866,7 @@ public final class DivText: DivBase, @unchecked Sendable {
|
||||
self.hoverEndActions = hoverEndActions
|
||||
self.hoverStartActions = hoverStartActions
|
||||
self.id = id
|
||||
self.imageBuilder = imageBuilder
|
||||
self.images = images
|
||||
self.layoutProvider = layoutProvider
|
||||
self.letterSpacing = letterSpacing ?? .value(0)
|
||||
@@ -926,97 +985,98 @@ extension DivText: Equatable {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.imageBuilder == rhs.imageBuilder,
|
||||
lhs.images == rhs.images,
|
||||
lhs.layoutProvider == rhs.layoutProvider,
|
||||
lhs.letterSpacing == rhs.letterSpacing
|
||||
lhs.layoutProvider == rhs.layoutProvider
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.letterSpacing == rhs.letterSpacing,
|
||||
lhs.lineHeight == rhs.lineHeight,
|
||||
lhs.longtapActions == rhs.longtapActions,
|
||||
lhs.margins == rhs.margins
|
||||
lhs.longtapActions == rhs.longtapActions
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.margins == rhs.margins,
|
||||
lhs.maxLines == rhs.maxLines,
|
||||
lhs.minHiddenLines == rhs.minHiddenLines,
|
||||
lhs.paddings == rhs.paddings
|
||||
lhs.minHiddenLines == rhs.minHiddenLines
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.paddings == rhs.paddings,
|
||||
lhs.pressEndActions == rhs.pressEndActions,
|
||||
lhs.pressStartActions == rhs.pressStartActions,
|
||||
lhs.rangeBuilder == rhs.rangeBuilder
|
||||
lhs.pressStartActions == rhs.pressStartActions
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.rangeBuilder == rhs.rangeBuilder,
|
||||
lhs.ranges == rhs.ranges,
|
||||
lhs.reuseId == rhs.reuseId,
|
||||
lhs.rowSpan == rhs.rowSpan
|
||||
lhs.reuseId == rhs.reuseId
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.rowSpan == rhs.rowSpan,
|
||||
lhs.selectable == rhs.selectable,
|
||||
lhs.selectedActions == rhs.selectedActions,
|
||||
lhs.strike == rhs.strike
|
||||
lhs.selectedActions == rhs.selectedActions
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.strike == rhs.strike,
|
||||
lhs.text == rhs.text,
|
||||
lhs.textAlignmentHorizontal == rhs.textAlignmentHorizontal,
|
||||
lhs.textAlignmentVertical == rhs.textAlignmentVertical
|
||||
lhs.textAlignmentHorizontal == rhs.textAlignmentHorizontal
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.textAlignmentVertical == rhs.textAlignmentVertical,
|
||||
lhs.textColor == rhs.textColor,
|
||||
lhs.textGradient == rhs.textGradient,
|
||||
lhs.textShadow == rhs.textShadow
|
||||
lhs.textGradient == rhs.textGradient
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.textShadow == rhs.textShadow,
|
||||
lhs.tightenWidth == rhs.tightenWidth,
|
||||
lhs.tooltips == rhs.tooltips,
|
||||
lhs.transform == rhs.transform
|
||||
lhs.tooltips == rhs.tooltips
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.transform == rhs.transform,
|
||||
lhs.transformations == rhs.transformations,
|
||||
lhs.transitionChange == rhs.transitionChange,
|
||||
lhs.transitionIn == rhs.transitionIn
|
||||
lhs.transitionChange == rhs.transitionChange
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.transitionIn == rhs.transitionIn,
|
||||
lhs.transitionOut == rhs.transitionOut,
|
||||
lhs.transitionTriggers == rhs.transitionTriggers,
|
||||
lhs.truncate == rhs.truncate
|
||||
lhs.transitionTriggers == rhs.transitionTriggers
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.truncate == rhs.truncate,
|
||||
lhs.underline == rhs.underline,
|
||||
lhs.variableTriggers == rhs.variableTriggers,
|
||||
lhs.variables == rhs.variables
|
||||
lhs.variableTriggers == rhs.variableTriggers
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.variables == rhs.variables,
|
||||
lhs.visibility == rhs.visibility,
|
||||
lhs.visibilityAction == rhs.visibilityAction,
|
||||
lhs.visibilityActions == rhs.visibilityActions
|
||||
lhs.visibilityAction == rhs.visibilityAction
|
||||
else {
|
||||
return false
|
||||
}
|
||||
guard
|
||||
lhs.visibilityActions == rhs.visibilityActions,
|
||||
lhs.width == rhs.width
|
||||
else {
|
||||
return false
|
||||
@@ -1062,6 +1122,7 @@ extension DivText: Serializable {
|
||||
result["hover_end_actions"] = hoverEndActions?.map { $0.toDictionary() }
|
||||
result["hover_start_actions"] = hoverStartActions?.map { $0.toDictionary() }
|
||||
result["id"] = id
|
||||
result["image_builder"] = imageBuilder?.toDictionary()
|
||||
result["images"] = images?.map { $0.toDictionary() }
|
||||
result["layout_provider"] = layoutProvider?.toDictionary()
|
||||
result["letter_spacing"] = letterSpacing.toValidSerializationValue()
|
||||
@@ -1106,6 +1167,21 @@ extension DivText: Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
// WARNING: this == is incomplete because of [String: Any] in class fields
|
||||
extension DivText.ImageBuilder: Equatable {
|
||||
public static func ==(lhs: DivText.ImageBuilder, rhs: DivText.ImageBuilder) -> Bool {
|
||||
guard
|
||||
lhs.dataElementName == rhs.dataElementName,
|
||||
lhs.prototypes == rhs.prototypes
|
||||
else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
// WARNING: this == is incomplete because of [String: Any] in class fields
|
||||
extension DivText.Range: Equatable {
|
||||
@@ -1247,6 +1323,20 @@ extension DivText.Image: Equatable {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
extension DivText.ImageBuilder.Prototype: Equatable {
|
||||
public static func ==(lhs: DivText.ImageBuilder.Prototype, rhs: DivText.ImageBuilder.Prototype) -> Bool {
|
||||
guard
|
||||
lhs.image == rhs.image,
|
||||
lhs.selector == rhs.selector
|
||||
else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
extension DivText.RangeBuilder.Prototype: Equatable {
|
||||
public static func ==(lhs: DivText.RangeBuilder.Prototype, rhs: DivText.RangeBuilder.Prototype) -> Bool {
|
||||
@@ -1301,6 +1391,27 @@ extension DivText.Image: Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
extension DivText.ImageBuilder.Prototype: Serializable {
|
||||
@_optimize(size)
|
||||
public func toDictionary() -> [String: ValidSerializationValue] {
|
||||
var result: [String: ValidSerializationValue] = [:]
|
||||
result["image"] = image.toDictionary()
|
||||
result["selector"] = selector.toValidSerializationValue()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
extension DivText.ImageBuilder: Serializable {
|
||||
@_optimize(size)
|
||||
public func toDictionary() -> [String: ValidSerializationValue] {
|
||||
var result: [String: ValidSerializationValue] = [:]
|
||||
result["data"] = data.toValidSerializationValue()
|
||||
result["data_element_name"] = dataElementName
|
||||
result["prototypes"] = prototypes.map { $0.toDictionary() }
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
extension DivText.Range: Serializable {
|
||||
@_optimize(size)
|
||||
public func toDictionary() -> [String: ValidSerializationValue] {
|
||||
|
||||
@@ -159,6 +159,255 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ImageBuilderTemplate: TemplateValue, @unchecked Sendable {
|
||||
public final class PrototypeTemplate: TemplateValue, Sendable {
|
||||
public let image: Field<ImageTemplate>?
|
||||
public let selector: Field<Expression<Bool>>? // default value: true
|
||||
|
||||
public convenience init(dictionary: [String: Any], templateToType: [TemplateName: String]) throws {
|
||||
self.init(
|
||||
image: dictionary.getOptionalField("image", templateToType: templateToType),
|
||||
selector: dictionary.getOptionalExpressionField("selector")
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
image: Field<ImageTemplate>? = nil,
|
||||
selector: Field<Expression<Bool>>? = nil
|
||||
) {
|
||||
self.image = image
|
||||
self.selector = selector
|
||||
}
|
||||
|
||||
private static func resolveOnlyLinks(context: TemplatesContext, parent: PrototypeTemplate?) -> DeserializationResult<DivText.ImageBuilder.Prototype> {
|
||||
let imageValue = { parent?.image?.resolveValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let selectorValue = { parent?.selector?.resolveOptionalValue(context: context) ?? .noValue }()
|
||||
var errors = mergeErrors(
|
||||
imageValue.errorsOrWarnings?.map { .nestedObjectError(field: "image", error: $0) },
|
||||
selectorValue.errorsOrWarnings?.map { .nestedObjectError(field: "selector", error: $0) }
|
||||
)
|
||||
if case .noValue = imageValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "image"))
|
||||
}
|
||||
guard
|
||||
let imageNonNil = imageValue.value
|
||||
else {
|
||||
return .failure(NonEmptyArray(errors)!)
|
||||
}
|
||||
let result = DivText.ImageBuilder.Prototype(
|
||||
image: { imageNonNil }(),
|
||||
selector: { selectorValue.value }()
|
||||
)
|
||||
return errors.isEmpty ? .success(result) : .partialSuccess(result, warnings: NonEmptyArray(errors)!)
|
||||
}
|
||||
|
||||
public static func resolveValue(context: TemplatesContext, parent: PrototypeTemplate?, useOnlyLinks: Bool) -> DeserializationResult<DivText.ImageBuilder.Prototype> {
|
||||
if useOnlyLinks {
|
||||
return resolveOnlyLinks(context: context, parent: parent)
|
||||
}
|
||||
var imageValue: DeserializationResult<DivText.Image> = .noValue
|
||||
var selectorValue: DeserializationResult<Expression<Bool>> = { parent?.selector?.value() ?? .noValue }()
|
||||
_ = {
|
||||
// Each field is parsed in its own lambda to keep the stack size managable
|
||||
// Otherwise the compiler will allocate stack for each intermediate variable
|
||||
// upfront even when we don't actually visit a relevant branch
|
||||
for (key, __dictValue) in context.templateData {
|
||||
_ = {
|
||||
if key == "image" {
|
||||
imageValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageTemplate.self).merged(with: imageValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == "selector" {
|
||||
selectorValue = deserialize(__dictValue).merged(with: selectorValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.image?.link {
|
||||
imageValue = imageValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageTemplate.self) })
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.selector?.link {
|
||||
selectorValue = selectorValue.merged(with: { deserialize(__dictValue) })
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
if let parent = parent {
|
||||
_ = { imageValue = imageValue.merged(with: { parent.image?.resolveValue(context: context, useOnlyLinks: true) }) }()
|
||||
}
|
||||
var errors = mergeErrors(
|
||||
imageValue.errorsOrWarnings?.map { .nestedObjectError(field: "image", error: $0) },
|
||||
selectorValue.errorsOrWarnings?.map { .nestedObjectError(field: "selector", error: $0) }
|
||||
)
|
||||
if case .noValue = imageValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "image"))
|
||||
}
|
||||
guard
|
||||
let imageNonNil = imageValue.value
|
||||
else {
|
||||
return .failure(NonEmptyArray(errors)!)
|
||||
}
|
||||
let result = DivText.ImageBuilder.Prototype(
|
||||
image: { imageNonNil }(),
|
||||
selector: { selectorValue.value }()
|
||||
)
|
||||
return errors.isEmpty ? .success(result) : .partialSuccess(result, warnings: NonEmptyArray(errors)!)
|
||||
}
|
||||
|
||||
private func mergedWithParent(templates: [TemplateName: Any]) throws -> PrototypeTemplate {
|
||||
return self
|
||||
}
|
||||
|
||||
public func resolveParent(templates: [TemplateName: Any]) throws -> PrototypeTemplate {
|
||||
let merged = try mergedWithParent(templates: templates)
|
||||
|
||||
return PrototypeTemplate(
|
||||
image: try merged.image?.resolveParent(templates: templates),
|
||||
selector: merged.selector
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public let data: Field<Expression<[Any]>>?
|
||||
public let dataElementName: Field<String>? // default value: it
|
||||
public let prototypes: Field<[PrototypeTemplate]>? // at least 1 elements
|
||||
|
||||
public convenience init(dictionary: [String: Any], templateToType: [TemplateName: String]) throws {
|
||||
self.init(
|
||||
data: dictionary.getOptionalExpressionField("data"),
|
||||
dataElementName: dictionary.getOptionalField("data_element_name"),
|
||||
prototypes: dictionary.getOptionalArray("prototypes", templateToType: templateToType)
|
||||
)
|
||||
}
|
||||
|
||||
init(
|
||||
data: Field<Expression<[Any]>>? = nil,
|
||||
dataElementName: Field<String>? = nil,
|
||||
prototypes: Field<[PrototypeTemplate]>? = nil
|
||||
) {
|
||||
self.data = data
|
||||
self.dataElementName = dataElementName
|
||||
self.prototypes = prototypes
|
||||
}
|
||||
|
||||
private static func resolveOnlyLinks(context: TemplatesContext, parent: ImageBuilderTemplate?) -> DeserializationResult<DivText.ImageBuilder> {
|
||||
let dataValue = { parent?.data?.resolveValue(context: context) ?? .noValue }()
|
||||
let dataElementNameValue = { parent?.dataElementName?.resolveOptionalValue(context: context) ?? .noValue }()
|
||||
let prototypesValue = { parent?.prototypes?.resolveValue(context: context, validator: ResolvedValue.prototypesValidator, useOnlyLinks: true) ?? .noValue }()
|
||||
var errors = mergeErrors(
|
||||
dataValue.errorsOrWarnings?.map { .nestedObjectError(field: "data", error: $0) },
|
||||
dataElementNameValue.errorsOrWarnings?.map { .nestedObjectError(field: "data_element_name", error: $0) },
|
||||
prototypesValue.errorsOrWarnings?.map { .nestedObjectError(field: "prototypes", error: $0) }
|
||||
)
|
||||
if case .noValue = dataValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "data"))
|
||||
}
|
||||
if case .noValue = prototypesValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "prototypes"))
|
||||
}
|
||||
guard
|
||||
let dataNonNil = dataValue.value,
|
||||
let prototypesNonNil = prototypesValue.value
|
||||
else {
|
||||
return .failure(NonEmptyArray(errors)!)
|
||||
}
|
||||
let result = DivText.ImageBuilder(
|
||||
data: { dataNonNil }(),
|
||||
dataElementName: { dataElementNameValue.value }(),
|
||||
prototypes: { prototypesNonNil }()
|
||||
)
|
||||
return errors.isEmpty ? .success(result) : .partialSuccess(result, warnings: NonEmptyArray(errors)!)
|
||||
}
|
||||
|
||||
public static func resolveValue(context: TemplatesContext, parent: ImageBuilderTemplate?, useOnlyLinks: Bool) -> DeserializationResult<DivText.ImageBuilder> {
|
||||
if useOnlyLinks {
|
||||
return resolveOnlyLinks(context: context, parent: parent)
|
||||
}
|
||||
var dataValue: DeserializationResult<Expression<[Any]>> = { parent?.data?.value() ?? .noValue }()
|
||||
var dataElementNameValue: DeserializationResult<String> = { parent?.dataElementName?.value() ?? .noValue }()
|
||||
var prototypesValue: DeserializationResult<[DivText.ImageBuilder.Prototype]> = .noValue
|
||||
_ = {
|
||||
// Each field is parsed in its own lambda to keep the stack size managable
|
||||
// Otherwise the compiler will allocate stack for each intermediate variable
|
||||
// upfront even when we don't actually visit a relevant branch
|
||||
for (key, __dictValue) in context.templateData {
|
||||
_ = {
|
||||
if key == "data" {
|
||||
dataValue = deserialize(__dictValue).merged(with: dataValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == "data_element_name" {
|
||||
dataElementNameValue = deserialize(__dictValue).merged(with: dataElementNameValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == "prototypes" {
|
||||
prototypesValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, validator: ResolvedValue.prototypesValidator, type: DivTextTemplate.ImageBuilderTemplate.PrototypeTemplate.self).merged(with: prototypesValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.data?.link {
|
||||
dataValue = dataValue.merged(with: { deserialize(__dictValue) })
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.dataElementName?.link {
|
||||
dataElementNameValue = dataElementNameValue.merged(with: { deserialize(__dictValue) })
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.prototypes?.link {
|
||||
prototypesValue = prototypesValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, validator: ResolvedValue.prototypesValidator, type: DivTextTemplate.ImageBuilderTemplate.PrototypeTemplate.self) })
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
if let parent = parent {
|
||||
_ = { prototypesValue = prototypesValue.merged(with: { parent.prototypes?.resolveValue(context: context, validator: ResolvedValue.prototypesValidator, useOnlyLinks: true) }) }()
|
||||
}
|
||||
var errors = mergeErrors(
|
||||
dataValue.errorsOrWarnings?.map { .nestedObjectError(field: "data", error: $0) },
|
||||
dataElementNameValue.errorsOrWarnings?.map { .nestedObjectError(field: "data_element_name", error: $0) },
|
||||
prototypesValue.errorsOrWarnings?.map { .nestedObjectError(field: "prototypes", error: $0) }
|
||||
)
|
||||
if case .noValue = dataValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "data"))
|
||||
}
|
||||
if case .noValue = prototypesValue {
|
||||
errors.append(.requiredFieldIsMissing(field: "prototypes"))
|
||||
}
|
||||
guard
|
||||
let dataNonNil = dataValue.value,
|
||||
let prototypesNonNil = prototypesValue.value
|
||||
else {
|
||||
return .failure(NonEmptyArray(errors)!)
|
||||
}
|
||||
let result = DivText.ImageBuilder(
|
||||
data: { dataNonNil }(),
|
||||
dataElementName: { dataElementNameValue.value }(),
|
||||
prototypes: { prototypesNonNil }()
|
||||
)
|
||||
return errors.isEmpty ? .success(result) : .partialSuccess(result, warnings: NonEmptyArray(errors)!)
|
||||
}
|
||||
|
||||
private func mergedWithParent(templates: [TemplateName: Any]) throws -> ImageBuilderTemplate {
|
||||
return self
|
||||
}
|
||||
|
||||
public func resolveParent(templates: [TemplateName: Any]) throws -> ImageBuilderTemplate {
|
||||
let merged = try mergedWithParent(templates: templates)
|
||||
|
||||
return ImageBuilderTemplate(
|
||||
data: merged.data,
|
||||
dataElementName: merged.dataElementName,
|
||||
prototypes: try merged.prototypes?.resolveParent(templates: templates)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public final class ImageTemplate: TemplateValue, Sendable {
|
||||
public final class AccessibilityTemplate: TemplateValue, Sendable {
|
||||
public typealias Kind = DivText.Image.Accessibility.Kind
|
||||
@@ -1339,6 +1588,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
public let hoverEndActions: Field<[DivActionTemplate]>?
|
||||
public let hoverStartActions: Field<[DivActionTemplate]>?
|
||||
public let id: Field<String>?
|
||||
public let imageBuilder: Field<ImageBuilderTemplate>?
|
||||
public let images: Field<[ImageTemplate]>?
|
||||
public let layoutProvider: Field<DivLayoutProviderTemplate>?
|
||||
public let letterSpacing: Field<Expression<Double>>? // default value: 0
|
||||
@@ -1414,6 +1664,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: dictionary.getOptionalArray("hover_end_actions", templateToType: templateToType),
|
||||
hoverStartActions: dictionary.getOptionalArray("hover_start_actions", templateToType: templateToType),
|
||||
id: dictionary.getOptionalField("id"),
|
||||
imageBuilder: dictionary.getOptionalField("image_builder", templateToType: templateToType),
|
||||
images: dictionary.getOptionalArray("images", templateToType: templateToType),
|
||||
layoutProvider: dictionary.getOptionalField("layout_provider", templateToType: templateToType),
|
||||
letterSpacing: dictionary.getOptionalExpressionField("letter_spacing"),
|
||||
@@ -1490,6 +1741,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: Field<[DivActionTemplate]>? = nil,
|
||||
hoverStartActions: Field<[DivActionTemplate]>? = nil,
|
||||
id: Field<String>? = nil,
|
||||
imageBuilder: Field<ImageBuilderTemplate>? = nil,
|
||||
images: Field<[ImageTemplate]>? = nil,
|
||||
layoutProvider: Field<DivLayoutProviderTemplate>? = nil,
|
||||
letterSpacing: Field<Expression<Double>>? = nil,
|
||||
@@ -1563,6 +1815,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
self.hoverEndActions = hoverEndActions
|
||||
self.hoverStartActions = hoverStartActions
|
||||
self.id = id
|
||||
self.imageBuilder = imageBuilder
|
||||
self.images = images
|
||||
self.layoutProvider = layoutProvider
|
||||
self.letterSpacing = letterSpacing
|
||||
@@ -1637,6 +1890,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
let hoverEndActionsValue = { parent?.hoverEndActions?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let hoverStartActionsValue = { parent?.hoverStartActions?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let idValue = { parent?.id?.resolveOptionalValue(context: context) ?? .noValue }()
|
||||
let imageBuilderValue = { parent?.imageBuilder?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let imagesValue = { parent?.images?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let layoutProviderValue = { parent?.layoutProvider?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue }()
|
||||
let letterSpacingValue = { parent?.letterSpacing?.resolveOptionalValue(context: context) ?? .noValue }()
|
||||
@@ -1709,6 +1963,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "hover_end_actions", error: $0) },
|
||||
hoverStartActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "hover_start_actions", error: $0) },
|
||||
idValue.errorsOrWarnings?.map { .nestedObjectError(field: "id", error: $0) },
|
||||
imageBuilderValue.errorsOrWarnings?.map { .nestedObjectError(field: "image_builder", error: $0) },
|
||||
imagesValue.errorsOrWarnings?.map { .nestedObjectError(field: "images", error: $0) },
|
||||
layoutProviderValue.errorsOrWarnings?.map { .nestedObjectError(field: "layout_provider", error: $0) },
|
||||
letterSpacingValue.errorsOrWarnings?.map { .nestedObjectError(field: "letter_spacing", error: $0) },
|
||||
@@ -1790,6 +2045,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: { hoverEndActionsValue.value }(),
|
||||
hoverStartActions: { hoverStartActionsValue.value }(),
|
||||
id: { idValue.value }(),
|
||||
imageBuilder: { imageBuilderValue.value }(),
|
||||
images: { imagesValue.value }(),
|
||||
layoutProvider: { layoutProviderValue.value }(),
|
||||
letterSpacing: { letterSpacingValue.value }(),
|
||||
@@ -1869,6 +2125,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
var hoverEndActionsValue: DeserializationResult<[DivAction]> = .noValue
|
||||
var hoverStartActionsValue: DeserializationResult<[DivAction]> = .noValue
|
||||
var idValue: DeserializationResult<String> = { parent?.id?.value() ?? .noValue }()
|
||||
var imageBuilderValue: DeserializationResult<DivText.ImageBuilder> = .noValue
|
||||
var imagesValue: DeserializationResult<[DivText.Image]> = .noValue
|
||||
var layoutProviderValue: DeserializationResult<DivLayoutProvider> = .noValue
|
||||
var letterSpacingValue: DeserializationResult<Expression<Double>> = { parent?.letterSpacing?.value() ?? .noValue }()
|
||||
@@ -2069,6 +2326,11 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
idValue = deserialize(__dictValue).merged(with: idValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == "image_builder" {
|
||||
imageBuilderValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageBuilderTemplate.self).merged(with: imageBuilderValue)
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == "images" {
|
||||
imagesValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageTemplate.self).merged(with: imagesValue)
|
||||
@@ -2424,6 +2686,11 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
idValue = idValue.merged(with: { deserialize(__dictValue) })
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.imageBuilder?.link {
|
||||
imageBuilderValue = imageBuilderValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageBuilderTemplate.self) })
|
||||
}
|
||||
}()
|
||||
_ = {
|
||||
if key == parent?.images?.link {
|
||||
imagesValue = imagesValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivTextTemplate.ImageTemplate.self) })
|
||||
@@ -2643,6 +2910,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
_ = { heightValue = heightValue.merged(with: { parent.height?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { hoverEndActionsValue = hoverEndActionsValue.merged(with: { parent.hoverEndActions?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { hoverStartActionsValue = hoverStartActionsValue.merged(with: { parent.hoverStartActions?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { imageBuilderValue = imageBuilderValue.merged(with: { parent.imageBuilder?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { imagesValue = imagesValue.merged(with: { parent.images?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { layoutProviderValue = layoutProviderValue.merged(with: { parent.layoutProvider?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
_ = { longtapActionsValue = longtapActionsValue.merged(with: { parent.longtapActions?.resolveOptionalValue(context: context, useOnlyLinks: true) }) }()
|
||||
@@ -2699,6 +2967,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "hover_end_actions", error: $0) },
|
||||
hoverStartActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "hover_start_actions", error: $0) },
|
||||
idValue.errorsOrWarnings?.map { .nestedObjectError(field: "id", error: $0) },
|
||||
imageBuilderValue.errorsOrWarnings?.map { .nestedObjectError(field: "image_builder", error: $0) },
|
||||
imagesValue.errorsOrWarnings?.map { .nestedObjectError(field: "images", error: $0) },
|
||||
layoutProviderValue.errorsOrWarnings?.map { .nestedObjectError(field: "layout_provider", error: $0) },
|
||||
letterSpacingValue.errorsOrWarnings?.map { .nestedObjectError(field: "letter_spacing", error: $0) },
|
||||
@@ -2780,6 +3049,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: { hoverEndActionsValue.value }(),
|
||||
hoverStartActions: { hoverStartActionsValue.value }(),
|
||||
id: { idValue.value }(),
|
||||
imageBuilder: { imageBuilderValue.value }(),
|
||||
images: { imagesValue.value }(),
|
||||
layoutProvider: { layoutProviderValue.value }(),
|
||||
letterSpacing: { letterSpacingValue.value }(),
|
||||
@@ -2864,6 +3134,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: hoverEndActions ?? mergedParent.hoverEndActions,
|
||||
hoverStartActions: hoverStartActions ?? mergedParent.hoverStartActions,
|
||||
id: id ?? mergedParent.id,
|
||||
imageBuilder: imageBuilder ?? mergedParent.imageBuilder,
|
||||
images: images ?? mergedParent.images,
|
||||
layoutProvider: layoutProvider ?? mergedParent.layoutProvider,
|
||||
letterSpacing: letterSpacing ?? mergedParent.letterSpacing,
|
||||
@@ -2943,6 +3214,7 @@ public final class DivTextTemplate: TemplateValue, @unchecked Sendable {
|
||||
hoverEndActions: merged.hoverEndActions?.tryResolveParent(templates: templates),
|
||||
hoverStartActions: merged.hoverStartActions?.tryResolveParent(templates: templates),
|
||||
id: merged.id,
|
||||
imageBuilder: merged.imageBuilder?.tryResolveParent(templates: templates),
|
||||
images: merged.images?.tryResolveParent(templates: templates),
|
||||
layoutProvider: merged.layoutProvider?.tryResolveParent(templates: templates),
|
||||
letterSpacing: merged.letterSpacing,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -190,6 +190,48 @@
|
||||
],
|
||||
"$description": "translations.json#/div_text_range_builder"
|
||||
},
|
||||
"image_builder": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"$description": "translations.json#/div_text_image_builder_data"
|
||||
},
|
||||
"data_element_name": {
|
||||
"type": "string",
|
||||
"default_value": "it",
|
||||
"supports_expressions": false,
|
||||
"$description": "translations.json#/div_text_image_builder_data_element_name"
|
||||
},
|
||||
"prototypes": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"selector": {
|
||||
"$ref": "common.json#/boolean_int",
|
||||
"default_value": "true",
|
||||
"$description": "translations.json#/div_text_image_builder_prototype_selector"
|
||||
},
|
||||
"image": {
|
||||
"$ref": "#/definitions/image",
|
||||
"$description": "translations.json#/div_text_image_builder_prototype_image"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
"$description": "translations.json#/div_text_image_builder_prototypes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"data",
|
||||
"prototypes"
|
||||
],
|
||||
"$description": "translations.json#/div_text_image_builder"
|
||||
},
|
||||
"image": {
|
||||
"type": "object",
|
||||
"platforms": [
|
||||
@@ -470,6 +512,12 @@
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"image_builder": {
|
||||
"$ref": "#/definitions/image_builder",
|
||||
"platforms": [
|
||||
"ios"
|
||||
]
|
||||
},
|
||||
"ellipsis": {
|
||||
"$ref": "#/definitions/ellipsis"
|
||||
},
|
||||
|
||||
@@ -2551,6 +2551,30 @@
|
||||
"en": "A condition that is used to select the prototype for the next character range. If there is more than 1 true condition, the earlier prototype is selected. If none of the conditions are met, the element from `data` is skipped.",
|
||||
"ru": "Условие, которое используется для выбора прототипа для очередного диапазона символов. В случае, если будет больше 1 истинного условия, будет выбран прототип, который находится раньше. Если не выполнено ни одно условие, элемент из `data` будет пропущен."
|
||||
},
|
||||
"div_text_image_builder": {
|
||||
"en": "Sets inline images dynamically using `data` and `prototypes`.",
|
||||
"ru": "Задает встроенные изображения динамически при помощи `data` и `prototypes`."
|
||||
},
|
||||
"div_text_image_builder_data": {
|
||||
"en": "Data that will be used to create inline images.",
|
||||
"ru": "Данные, которые будут использоваться для создания встроенных изображений."
|
||||
},
|
||||
"div_text_image_builder_data_element_name": {
|
||||
"en": "Name for accessing the next `data` element in the prototype. Working with this element is the same as with dictionaries.",
|
||||
"ru": "Имя для обращения к очередному элементу `data` в прототипе. Работа с этим элементом ведется так же, как со словарями."
|
||||
},
|
||||
"div_text_image_builder_prototypes": {
|
||||
"en": "Array of `image` elements from which the inline images will be created.",
|
||||
"ru": "Массив `image`, из которых будут созданы встроенные изображения."
|
||||
},
|
||||
"div_text_image_builder_prototype_image": {
|
||||
"en": "`image` from which the inline image will be created. In `image`, you can use expressions using data from `data`. To access the next `data` element, you need to use the same name as in `data_element_name`.",
|
||||
"ru": "`image`, из которого будет создано встроенное изображение. В `image` можно использовать выражения с использованием данных из `data`. Для обращения к очередному элементу `data` нужно использовать такое же имя, как и в `data_element_name`."
|
||||
},
|
||||
"div_text_image_builder_prototype_selector": {
|
||||
"en": "A condition that is used to select the prototype for the next inline image. If there is more than 1 true condition, the earlier prototype is selected. If none of the conditions are met, the element from `data` is skipped.",
|
||||
"ru": "Условие, которое используется для выбора прототипа для очередного встроенного изображения. В случае, если будет больше 1 истинного условия, будет выбран прототип, который находится раньше. Если не выполнено ни одно условие, элемент из `data` будет пропущен."
|
||||
},
|
||||
"div_text_range_actions": {
|
||||
"en": "Action when clicking on text.",
|
||||
"ru": "Действие при нажатии на текст."
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"description": "Text with image_builder: inline images generated from a data array, with selector-based prototype choice.",
|
||||
"platforms": [
|
||||
"ios"
|
||||
],
|
||||
"card": {
|
||||
"log_id": "snapshot_test_card",
|
||||
"states": [
|
||||
{
|
||||
"state_id": 0,
|
||||
"div": {
|
||||
"type": "container",
|
||||
"width": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"background": [
|
||||
{
|
||||
"type": "solid",
|
||||
"color": "#FFF"
|
||||
}
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"variables": [
|
||||
{
|
||||
"name": "source",
|
||||
"type": "array",
|
||||
"value": [
|
||||
{ "pos": 2, "kind": "chess" },
|
||||
{ "pos": 5, "kind": "star" },
|
||||
{ "pos": 8, "kind": "chess" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"type": "text",
|
||||
"text": "0123456789",
|
||||
"font_size": 20,
|
||||
"width": {
|
||||
"type": "wrap_content"
|
||||
},
|
||||
"image_builder": {
|
||||
"data": "@{source}",
|
||||
"data_element_name": "it",
|
||||
"prototypes": [
|
||||
{
|
||||
"selector": "@{getStringFromDict(it, 'kind') == 'star'}",
|
||||
"image": {
|
||||
"start": "@{getIntegerFromDict(it, 'pos')}",
|
||||
"url": "https://yastatic.net/s3/home/divkit/star.png",
|
||||
"width": { "type": "fixed", "value": 24 },
|
||||
"height": { "type": "fixed", "value": 24 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"image": {
|
||||
"start": "@{getIntegerFromDict(it, 'pos')}",
|
||||
"url": "https://yastatic.net/s3/home/divkit/chess.png",
|
||||
"width": { "type": "fixed", "value": 24 },
|
||||
"height": { "type": "fixed", "value": 18 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user