swift-html
                                
                                
                                
                                    swift-html copied to clipboard
                            
                            
                            
                        Attribute Value + Manipulate Children
Get attribute value with key
func value(_ key: String) -> String?
This would make finding an attribute value very compact and convenient
Add [Tag] to children with TagBuilder parameter
public func insert(at i: Int? = nil, if condition: Bool = true, @TagBuilder children: () -> [Tag]) -> Self
public func append(_ condition: Bool = true, @TagBuilder children: () -> [Tag]) -> Self
One more option when declaring a Tag. Right now it's either Tag(...) or Tag {...} This way is both Tag(...).insert{...}
Also, it would allow you to write func() calls on a Tag before declaring children. For example, instead of...
Div {
     // ... a huge hierarchy making me lose track of parent's closing bracket
}
.func()
.anotherFunc()
.anotherFunc()
You could put the func() calls next to the tag declaration. And then attributes are listed closer to the parent.
Div()
     .func()
     .anotherFunc()
     .anotherFunc()
     .append {
          // ... a huge hierarchy that seems better placed in code
     }
• Remove children at index
public func remove(at i: Int, if condition: Bool = true) -> Self
If children can be added, it seems only natural to also remove
Sorry, could you give me a brief explanation about this PR? I can see what the functions are doing, but I'd like to know a bit more about the reasons why we should have them... thank you.
Many apologies.
I attached a lengthy explanation in the PR request notes. Especially for inserting and appending children.
Do you need more detail? Are my notes confusing as to why I think they are important?
Thanks.
Yeah, it was a bit confusing, because of the strange syntax format, I fixed your comment, now it's more readable. :)
Anyway, I like this idea, maybe the naming should be insertChildren, appendChildren, but I'm not sure just yet.
Same thing applies for the remove -> removeChild ?
Also a suggestion for the value function -> attributeValue(for: "key")
Please give me a day or two to think about this. :)
Sorry about that.
Didn’t realize there were tags for swift code.
Now I know!
Thanks for your cogitation...
BG
On Mar 18, 2022, at 1:05 PM, Tibor Bödecs @.***> wrote:
Yeah, it was a bit confusing, because of the strange syntax format, I fixed your comment, now it's more readable. :)
Anyway, I like this idea, maybe the naming should be insertChildren, appendChildren, but I'm not sure just yet. Same thing applies for the remove -> removeChild ?
Also a suggestion for the value function -> attributeValue(for: "key")
Please give me a day or two to think about this. :)
— Reply to this email directly, view it on GitHub https://github.com/BinaryBirds/swift-html/pull/20#issuecomment-1072610769, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANDZYQC4GO55X5P5I4J5IH3VASZT7ANCNFSM5RB6AXXA. You are receiving this because you authored the thread.
One quick thought on the naming conventions...
I'm from the camp that thinks Swift function names should be minimalistic.
That unnecessary labeling or declaratives should be avoided.
And to let the supplied variables play a part in the function declaration.
For example...
func value(_ key: String) -> String?
... reads like this ...
node.value("class")
... is lighter and less redundant than ...
node.attributeValue("class")
The value of the supplied variable "class" makes the attribute part of the func() name less necessary. And reads less obtrusively when the code is littered with them.
I see it a lot in init()s ...
init(true)
init("Some string")
init(myInt)
... versus ...
initBool(false)
init(bool: false)
initString("Some string")
init(string: "Some string")
initInt(myInt)
init(int: myInt)
And I see it in your Node class...
mutating func upsert(_ attribute: Attribute)
mutating func delete(_ attribute: Attribute)
... instead of ...
mutating func upsertAttribute(_ attribute: Attribute)
mutating func deleteAttribute(_ attribute: Attribute)
But perhaps a better internal parameter name would be a good compromise...
func value(_ attributeKey: String) -> String?
And in the case of the children func()s... insert and append seem perfectly clear when followed by brackets with child tags.
tag.append {
     childTag
     childTag
     childTag
}
While...
tag.insertChildren {
     childTag
     childTag
     childTag
}
... reads a little like unnecessary labeling. Like stating the obvious. It's clear what's being appended.
The one func() that may benefit from extra clarity is...
tag.removeChildren(at: 5)
... instead of ...
tag.remove(at: 5)
That's just my two cents worth.
Happy to call them whatever you like.
Sorry. Must have closed this pull request by accident while I was mucking around with my patches.
I was thinking this PR and I think I need a better understanding to evaluate it properly. Could you give me an example use case when you need to dynamically manipulate the hierarchy? 🤔
Off the top of my head, I can't think of a NEED to dynamically manipulate the hierarchy.
I'm just proposing a more flexible way to initialize a Tag. To move all the functions that normally follow the child hierarchy, up to the parent Tag declaration. For example, right now the parent functions are all at the bottom...
Tag(a, b, c) {
     // children...
}
.func(d)
.func(e)
.func(f)
I would like to do this...
Tag(a, b, c)
.func(d)
.func(e)
.func(f)
.append {
     // children...
}
The only way I see to accomplish that is being able to manipulate the children. That's it.
So perhaps my proposal went too far by suggesting total manipulation... inserting children at an index, deleting children, etc.
Your question makes me realize that kind of access is probably unnecessary. Tags are normally used in a declarative way.
So maybe all I'm really looking for is a SET function of some kind, a way to DEFER declaring the children.
Tag(a, b, c)
.func(d)
.func(e)
.func(f)
.children {
     // children...
}
One added benefit of consolidating all the parent functions under the parent Tag is the ability to—in certain circumstances—eliminate init function parameters.
For example, I found myself making lots of custom tags with non-essential init parameters, like how to style the tag. And sometimes there were a lot, wrapping on multiple lines with verbose labels. Trying to parse the parenthesis and braces got really hard to read.
Tag(a: Value, 
        b: Value, 
        cReallyLongLabel: Value, 
        dAnotherReallyLongLabel: Value,
        eEvenLongerLabelNameBecauseYouKnow: Value) {
        Child(a: Value, 
               b: Value, 
               cReallyLongLabel: Value, 
               dAnotherReallyLongLabel: Value,
               eEvenLongerLabelNameBecauseYouKnow: Value) {
               Child(a: Value, 
                         b: Value, 
                         cReallyLongLabel: Value, 
                         dAnotherReallyLongLabel: Value,
                         eEvenLongerLabelNameBecauseYouKnow: Value) {
                       /// etc.
               }
     }
}
I could put them into functions... But again, all the important init details are visually divorced from the parent declaration.
Tag() {
     Tag() {
          Tag() {
               // etc...
          }
          .a(Value)
          .b(Value)
          .cReallyLongLabel(Value)
          .dAnotherReallyLongLabel(Value)
          .eEvenLongerLabelNameBecauseYouKnow(Value)
     }
     .a(Value)
     .b(Value)
     .cReallyLongLabel(Value)
     .dAnotherReallyLongLabel(Value)
     .eEvenLongerLabelNameBecauseYouKnow(Value)
}
.a(Value)
.b(Value)
.cReallyLongLabel(Value)
.dAnotherReallyLongLabel(Value)
.eEvenLongerLabelNameBecauseYouKnow(Value)
Being able to defer setting the children would make that much more readable.
Tag()
.a(Value)
.b(Value)
.cReallyLongLabel(Value)
.dAnotherReallyLongLabel(Value)
.eEvenLongerLabelNameBecauseYouKnow(Value)
.children {
     Tag()
     .a(Value)
     .b(Value)
     .cReallyLongLabel(Value)
     .dAnotherReallyLongLabel(Value)
     .eEvenLongerLabelNameBecauseYouKnow(Value) 
     .children {
          Tag()
          .a(Value)
          .b(Value)
          .cReallyLongLabel(Value)
          .dAnotherReallyLongLabel(Value)
          .eEvenLongerLabelNameBecauseYouKnow(Value) 
          .children {
               // etc.
          }
     }
}
I updated the code and tests accordingly.