malcommac / SwiftRichString

👩‍🎨 Elegant Attributed String composition in Swift sauce
MIT License
3.1k stars 211 forks source link

StandardXMLAttributesResolver not recognizing links if custom style is provided for "a" tag #102

Closed stefanomondino closed 4 years ago

stefanomondino commented 4 years ago

Scenario:

we have a StyleGroup rendering some very basic html text. We have defined styles for most common tags, including a custom one for a. We're also using href informations through the .link attributed string key to trigger events on a TTTAttributedLabel.

Analysis:

We expected to find the .link attribute populated with the original href, but this doesn't work out of the box:

The root cause seems to be in the StandardXMLAttributesResolver implementation:

Workaround:

We were able to create a custom resolver by wrapping the standard one like this.

open class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {
    public func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String : String]?, fromStyle: StyleXML) {
        wrapper.styleForUnknownXMLTag(tag, to: &attributedString, attributes: attributes, fromStyle: fromStyle)
    }
    let wrapper: XMLDynamicAttributesResolver
    init(_ wrapper: XMLDynamicAttributesResolver) {
        self.wrapper = wrapper
    }
    public func applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle, fromStyle: StyleXML) {
        if xmlStyle.tag == "a" {
            self.styleForUnknownXMLTag("a", to: &attributedString, attributes: xmlStyle.xmlAttributes, fromStyle: fromStyle)
        }
        wrapper.applyDynamicAttributes(to: &attributedString, xmlStyle: xmlStyle, fromStyle: fromStyle)
    }
}

and by setting it like this in our group:

 let group = StyleGroup(base: myBaseStyle, ["a": heavy.byAdding {
                $0.color = Color.black
                $0.minimumLineHeight = 24.0
                $0.size = 14.0
                $0.underline = (.thick, Color.black)
            }])
            group.xmlAttributesResolver = MyXMLDynamicAttributesResolver(group.xmlAttributesResolver)

Proposed solutions:

1) inside the StandardXMLAttributesResolver, fallback to the default implementation for a tags 2) make StandardXMLAttributesResolver methods (and initializer!) open and not internal/public (that's why we had to wrap the resolver inside another class instead of subclassing it)

I can quickly put together a pull request if needed but I'd like to know which is the intended behavior

Ciao :)

malcommac commented 4 years ago

Absolutely right, we have discovered this issue few days ago. If you want to make a PR for both of the points I'll be happy to merge it. Thanks!

stefanomondino commented 4 years ago

I'm on it :)