New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Styling Embedded <a> tags whilst making them clickable #346
Comments
Just a quick update - I have tried the following class HTMLStyler: XMLStyler {
var body = StringStyle(
.font(UIFont(titillium: weight, size: 14)),
.color(.red),
.lineSpacing(-3),
.paragraphSpacingAfter(14)
)
var bodyLink = StringStyle(
.xmlStyler(LinkStyler())
)
func style(forElement name: String, attributes: [String: String], currentStyle: StringStyle) -> StringStyle? {
switch name {
case "strong":
let bolder = body.byAdding(
.xmlRules([
.style("em", body.byAdding(.font(UIFont(boldFont: .boldItalic, size: 14))))
.style("a", bodyLink)
])
)
return bolder
case "a":
guard let href = attributes["href"],
let url = URL(string: href) else {
return body
}
return body.byAdding(.link(url))
default:
return body
}
}
class LinkStyler: XMLStyler {
func style(forElement name: String, attributes: [String: String], currentStyle: StringStyle) -> StringStyle? {
switch name {
case "a":
guard let href = attributes["href"],
let url = URL(string: href) else {
return currentStyle
}
return currentStyle.byAdding(.link(url))
default:
return currentStyle
}
}
func prefix(forElement name: String, attributes: [String: String]) -> Composable? {
return nil
}
func suffix(forElement name: String) -> Composable? {
return nil
} Which feels more like what I was looking for, however alternatively if was to manually call this within the xmlRules: switch name {
case "strong":
let bolder = body.byAdding(
.xmlRules([
.style("a", LinkStyler().style(forElement: name, attributes: attributes, currentStyle: body)!)
])
)
The |
Great question, @russnettle. I'd love to make this easier to handle in BonMot, possibly without needing a custom styler. I'm not sure when I'll have a chance to dig into your question more, but I definitely want to improve this. Hopefully I can get back to you soon on this. |
Thanks @ZevEisenberg appreciate it - I am currently looking to have to write reg ex to parse the html and close / reopen any styling tags around link before it hits the styler. I wondered if I was just missing something in BonMot that would get around this ? |
This should be possible, but we may need to improve the custom styler API so that you can combine attributes as you encounter nested styles. I'm not sure if we support that correctly, but I won't know for sure without looking into it. I'd also love to support this natively, so you don't need to write a custom styler to support it. If this is something you're interested in contributing to, and you have the free time, a great starting point would be to implement a failing test case that demonstrates the behavior you desire. This could be either a demonstration of a custom styler that doesn't combine nested attributes correctly, or a hypothetical update to BonMot itself that supports parsing HTML href tags. I'm not sure which of those I'd prefer, but would love to discuss pros and cons. |
@russnettle I think this should work if in your very first example instead of doing |
In addition, I noticed you're returning XMLRules from your XMLStyler – if you're overriding I believe if you also just return a new string style, it will automatically append to current style. For example, this code works for me: func style(forElement name: String, attributes: [String: String], currentStyle: StringStyle) -> StringStyle? {
switch name {
case "i", "em":
let f = currentStyle.font ?? TextStyles.defaultFont
guard f.fontName != BuenosAires.bold.rawValue else {
return StringStyle(.font(BuenosAires.boldItalic, f.pointSize))
}
return [.font(BuenosAires.italic, f.pointSize)]
case "b", "strong":
let f = currentStyle.font ?? TextStyles.defaultFont
guard f.fontName != BuenosAires.italic.rawValue else {
return StringStyle(.font(BuenosAires.boldItalic, f.pointSize))
}
return StringStyle(.font(BuenosAires.bold, f.pointSize))
case "a":
guard let href = attributes["href"], let url = URL(string: href, relativeTo: Server.current.url) else { return nil }
return StringStyle(.link(url))
default:
return nil
}
} Or to use your example, I believe this should also work. class HTMLStyler: XMLStyler {
var body = StringStyle(
.font(UIFont(titillium: weight, size: 14)),
.color(.red),
.lineSpacing(-3),
.paragraphSpacingAfter(14)
)
func style(forElement name: String, attributes: [String: String], currentStyle: StringStyle) -> StringStyle? {
switch name {
case "strong":
return StringStyle(.font(UIFont(boldFont: .boldItalic, size: 14)))
case "a":
guard let href = attributes["href"],
let url = URL(string: href) else {
return nil
}
return StringStyle(.link(url))
default:
return body
}
}
|
@Imperiopolis hey - thanks for clarifying - I will take a look - however from what I have already seen , if an |
@russnettle link tags do work nested for me. I think the key thing for you to try and have them work for you also would be to not return See my above example for exactly what I mean. |
Thanks @Imperiopolis I will give this a try 😃 |
Hey @Imperiopolis removing the |
Hey - I wonder if someone can help clarify if this is possible...
I am using HTML tags to style my text with a custom XMLStyler and this is working fine for something similar to:
<strong>Some text</strong><a href="https://www.website.com>link</a>"
however the html I am styling is coming through with links embedded within tags such as
<strong>Some text <a href="https://www.website.com>link</a></strong>"
I am able to add styles to the embedded link, however the link is not tappable.
My styler looks like :
The problem I have is that the strong tag is picked up for the styling and returns the style before the 'a' tag, which means the .link(url) is not attached
Is there a way to get around this? maybe triggering a new styler somehow in the xml rules for the parent tag?
I have been stuck on this for a while and the only way I can think to get around it if it doesn't work is to manually parse the string and close off the HTML tag prior to styling - which I would really like to avoid
Thanks so much - great framework that does everything else that I need
The text was updated successfully, but these errors were encountered: