Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Customize HTML/XML rendering with tag attributes #77

Closed
theScud opened this issue May 31, 2019 · 1 comment
Closed

Customize HTML/XML rendering with tag attributes #77

theScud opened this issue May 31, 2019 · 1 comment
Assignees
Milestone

Comments

@theScud
Copy link

theScud commented May 31, 2019

Add configurable style attributes like color, font weight, etc. to allow for better customization:
<h1 color= "#RRGGBB">
Or
Add support for style sheets
<h1 style="color:blue;">This is a Blue Heading</h1>
Purpose :

  1. allows a more self-contained way to send styling info for HTML test
  2. provide more flexibility to render styles from an API response or to render HTML styled documents without many changes

Sample of proposed changes
https://github.com/malcommac/SwiftRichString/pull/76/files

malcommac added a commit that referenced this issue Dec 21, 2019
@malcommac malcommac self-assigned this Dec 21, 2019
@malcommac malcommac added this to the 3.1.0 milestone Dec 21, 2019
malcommac added a commit that referenced this issue Dec 21, 2019
malcommac added a commit that referenced this issue Dec 21, 2019
malcommac added a commit that referenced this issue Dec 21, 2019
@malcommac
Copy link
Owner

malcommac commented Dec 21, 2019

The next release will sports a new parser for tagged string which allows you to perform changes - both for style and content - based upon passed tag attributes and tags.
This is the documentation section.

Render XML tagged strings

SwiftRichString is also able to parse and render xml tagged strings to produce a valid NSAttributedString instance. This is particularly useful when you receive dynamic strings from remote services and you need to produce a rendered string easily.

In order to render an XML string you need to create a compisition of all styles you are planning to render in a single StyleGroup instance and apply it to your source string as just you made for a single Style.

For example:

// The base style is applied to the entire string
let baseStyle = Style {
	$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize * 1.15)
	$0.lineSpacing = 1
	$0.kerning = Kerning.adobe(-20)
}

let boldStyle = Style {
	$0.font = UIFont.boldSystemFont(ofSize: self.baseFontSize)
    $0.dynamicText = DynamicText {
    $0.style = .body
    $0.maximumSize = 35.0
    $0.traitCollection = UITraitCollection(userInterfaceIdiom: .phone)
    }
}
		
let italicStyle = Style {
	$0.font = UIFont.italicSystemFont(ofSize: self.baseFontSize)
}

// A group container includes all the style defined.
let groupStyle = StyleGroup.init(base: baseStyle, ["b" : boldStyle, "i": italicStyle])

// We can render our string
let bodyHTML = "Hello <b>world!</b>, my name is <i>Daniele</i>"
self.textView?.attributedText = bodyHTML.set(style: group)

Customize XML rendering: react to tag's attributes and unknown tags

You can also add custom attributes to your tags and render it as you prefer: you need to provide a croncrete implementation of XMLDynamicAttributesResolver protocol and assign it to the StyleGroup's .xmlAttributesResolver property.

The protocol will receive two kind of events:

  • applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle) is received when parser encounter an existing style with custom attributes. Style is applied and event is called so you can make further customizations.
  • func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String: String]?) is received when a unknown (not defined in StyleGroup's styles) tag is received. You can decide to ignore or perform customizations.

The following example is used to override text color for when used for any known tag:

// First define our own resolver for attributes
open class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {
    
    public func applyDynamicAttributes(to attributedString: inout AttributedString, xmlStyle: XMLDynamicStyle) {
        let finalStyleToApply = Style()
        xmlStyle.enumerateAttributes { key, value  in
            switch key {
                case "color": // color support
                    finalStyleToApply.color = Color(hexString: value)
                
                default:
                    break
            }
        }
        
        attributedString.add(style: finalStyleToApply)
    }
}

// Then set it to our's StyleGroup instance before rendering text.
let groupStyle = StyleGroup.init(base: baseStyle, ["b" : boldStyle, "i": italicStyle])
groupStyle.xmlAttributesResolver = MyXMLDynamicAttributesResolver()

The following example define the behaviour for a non known tag called rainbow.
Specifically it alter the string by setting a custom color for each letter of the source string.

open class MyXMLDynamicAttributesResolver: XMLDynamicAttributesResolver {

  public override func styleForUnknownXMLTag(_ tag: String, to attributedString: inout AttributedString, attributes: [String : String]?) {
        super.styleForUnknownXMLTag(tag, to: &attributedString, attributes: attributes)
        
        if tag == "rainbow" {
            let colors = UIColor.randomColors(attributedString.length)
            for i in 0..<attributedString.length {
                attributedString.add(style: Style({
                    $0.color = colors[i]
                }), range: NSMakeRange(i, 1))
            }
        }
        
    }
  }
}

You will receive all read tag attributes inside the attributes parameter.
You can alter attributes or the entire string received as inout parameter in attributedString property.

A default resolver is also provided by the library and used by default: StandardXMLAttributesResolver. It will support both color attribute in tags and <a href> tag with url linking.

let sourceHTML = "My <b color=\"#db13f2\">webpage</b> is really <b>cool</b>. Take a look <a href=\"http://danielemargutti.com\">here</a>"
        
let styleBase = Style({
    $0.font = UIFont.boldSystemFont(ofSize: 15)
})
        
let styleBold = Style({
    $0.font = UIFont.boldSystemFont(ofSize: 20)
    $0.color = UIColor.blue
})
        
let groupStyle = StyleGroup.init(base: styleBase, ["b" : styleBold])
self.textView?.attributedText = sourceHTML.set(style: groupStyle)

The result is this:

image_5

where the b tag's blue color was overriden by the color tag attributes and the link in 'here' is clickable.

@malcommac malcommac changed the title Support for style attributes from the HTML tag ? Customize HTML/XML rendering with tag attributes Dec 21, 2019
malcommac added a commit that referenced this issue Dec 21, 2019
# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

2 participants