Skip to content

Commit

Permalink
cool new stuff, including using OrderedDict instead of Dict
Browse files Browse the repository at this point in the history
  • Loading branch information
joshday committed Jun 14, 2023
1 parent 280d7f3 commit 9a025d7
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 46 deletions.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.5.0"
[deps]
DefaultApplication = "3f0dd361-4fe0-5fc6-8523-80b14ec94d85"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Scratch = "6c6a2e73-6563-6170-7368-637461726353"

Expand Down
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,33 +160,31 @@ end

## 📄 Writing CSS with `Cobweb.CSS`

You can create `Cobweb.CSS` from any `AbstractDict`:
- `selector => AbstractDict (property => value)`.
- We like using [`EasyConfig.Config`](https://github.com/joshday/EasyConfig.jl) for this.
You can create `Cobweb.CSS` from any nested `AbstractDict`, e.g. `selector => (property => value)`.
- We like using [`EasyConfig.Config`](https://github.com/joshday/EasyConfig.jl) to simplify the syntax.

```julia
using EasyConfig
using Cobweb: h
css = Config()
css."p"."font-family" = "Arial"
css."p.upper"."text-transform"= "uppercase"
css."p.blue".color = "blue"
style = Config()
style.p."font-family" = "Arial"
style."p.upper"."text-transform" = "uppercase"
style."p.blue".color = "blue"
css = Cobweb.CSS(style)
# p {
# font-family: Arial;
# font-family: Arial;
# }
# p.upper {
# text-transform: uppercase;
# text-transform: uppercase;
# }
# p.blue {
# color: blue;
# color: blue;
# }
page = h.html(
h.head(Cobweb.CSS(css)),
h.head(css),
h.body(
h.p("this is uppercased and blue in an Arial font.", class="upper blue")
)
Expand Down
68 changes: 35 additions & 33 deletions src/Cobweb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Cobweb

using DefaultApplication: DefaultApplication
using Scratch: @get_scratch!
using Random
using OrderedCollections: OrderedDict

export Page, Tab

Expand All @@ -22,37 +22,43 @@ Should not often be used directly. See `?Cobweb.h`.
"""
struct Node
tag::String
attrs::Dict{String,String}
attrs::OrderedDict{String,String}
children::Vector
function Node(tag::AbstractString, attrs::AbstractDict, children::AbstractVector)
new(string(tag), OrderedDict(string(k) => string(v) for (k,v) in pairs(attrs)), collect(children))
end
end
tag(o::Node) = getfield(o, :tag)
attrs(o::Node) = getfield(o, :attrs)
children(o::Node) = getfield(o, :children)

attrs(kw::Base.Pairs) = OrderedDict(string(k) => string(v) for (k,v) in kw)

function Base.:(==)(a::Node, b::Node)
tag(a) == tag(b) &&
attrs(a) == attrs(b) &&
length(children(a)) == length(children(b)) &&
all(ac == bc for (ac,bc) in zip(children(a), children(b)))
end

# append classes
function Base.getproperty(node::Node, class::String)
d = attrs(node)
d["class"] = haskey(d, "class") ? (d["class"] * ' ' * class) : class
node
end
(o::Node)(x...; kw...) = Node(tag(o), merge(attrs(o), attrs(kw)), vcat(children(o), x...))

Base.getproperty(node::Node, name::Symbol) = getfield(node, :attrs)[string(name)]
Base.setproperty!(node::Node, name::Symbol, x) = getfield(node, :attrs)[string(name)] = string(x)
Base.:(==)(a::Node, b::Node) = all(f(a) == f(b) for f in (tag, attrs, children))

Base.getindex(node::Node, i::Integer) = children(node)[i]
Base.setindex!(node::Node, x, i::Integer) = setindex!(children(node), x, i)

get_attrs(kw) = Dict(string(k) => string(v) for (k,v) in kw)

(node::Node)(x...; kw...) = Node(tag(node), merge(attrs(node), get_attrs(kw)), vcat(children(node), x...))
# append classes
Base.getproperty(o::Node, class::String) = o(class = lstrip(get(o, :class, "") * " " * class))

# methods that pass through to attrs(o)
Base.propertynames(o::Node) = Symbol.(keys(o))
Base.getproperty(o::Node, name::Symbol) = attrs(o)[string(name)]
Base.setproperty!(o::Node, name::Symbol, x) = attrs(o)[string(name)] = string(x)
Base.get(o::Node, name, val) = get(attrs(o), string(name), string(val))
Base.get!(o::Node, name, val) = get!(attrs(o), string(name), string(val))
Base.haskey(o::Node, name) = haskey(attrs(o), string(name))
Base.keys(o::Node) = keys(attrs(o))

# methods that pass through to children(o)
Base.lastindex(o::Node) = lastindex(children(o))
Base.getindex(o::Node, i::Union{Integer, AbstractVector{<:Integer}, Colon}) = children(o)[i]
Base.setindex!(o::Node, x, i::Union{Integer, AbstractVector{<:Integer}, Colon}) = setindex!(children(o), x, i)
Base.length(o::Node) = length(children(o))
Base.iterate(o::Node) = iterate(children(o))
Base.iterate(o::Node, state) = iterate(children(o), state)
Base.push!(o::Node, x) = push!(children(o), x)
Base.append!(o::Node, x) = append!(children(o), x)

#-----------------------------------------------------------------------------# h
"""
Expand All @@ -70,9 +76,9 @@ Create an html node with the given `tag`, `children`, and `kw` attributes.
h.div."myclass"("content")
# <div class="myclass">content</div>
"""
h(tag, children...; kw...) = Node(tag, get_attrs(kw), collect(children))
h(tag, children...; kw...) = Node(tag, attrs(kw), collect(children))

h(tag, attrs::Dict, children...) = Node(tag, attrs, collect(children))
h(tag, attrs::AbstractDict, children...) = Node(tag, attrs, collect(children))

Base.getproperty(::typeof(h), tag::Symbol) = h(string(tag))
Base.propertynames(::typeof(h)) = HTML5_TAGS
Expand Down Expand Up @@ -129,7 +135,7 @@ Base.show(io::IO, ::MIME"text/html", j::Javascript) = print(io, "<script>", j.x,

#-----------------------------------------------------------------------------# CSS
"""
CSS(dictionary)
CSS(::AbstractDict)
Write CSS with a nested dictionary with keys (`selector => (property => value)`).
Expand All @@ -143,9 +149,9 @@ Write CSS with a nested dictionary with keys (`selector => (property => value)`)
))
"""
struct CSS
content::Dict{String, Dict{String,String}}
content::OrderedDict{String, OrderedDict{String,String}}
function CSS(o::AbstractDict)
new(Dict(string(k) => Dict(string(k2) => string(v2) for (k2,v2) in pairs(v)) for (k,v) in pairs(o)))
new(OrderedDict(string(k) => OrderedDict(string(k2) => string(v2) for (k2,v2) in pairs(v)) for (k,v) in pairs(o)))
end
end
function Base.show(io::IO, o::CSS)
Expand All @@ -158,11 +164,7 @@ function Base.show(io::IO, o::CSS)
end
end
Base.show(io::IO, ::MIME"text/css", o::CSS) = print(io, o)
function Base.show(io::IO, ::MIME"text/html", o::CSS)
println(io, "<style>")
print(io, o)
println(io, "</style>")
end
Base.show(io::IO, ::MIME"text/html", o::CSS) = show(io, h.style(repr("text/css", o)))
save(file::String, o::CSS) = save(o, file)
save(o::CSS, file::String) = open(io -> show(io, x), touch(file), "w")

Expand Down
8 changes: 8 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ n2 = h("div", "hi")
n[1] = "new"
@test n[1] == "new"
end
#-----------------------------------------------------------------------------# indexing
@testset "get/setindex" begin
o = h.div("hi")
@test o[1] == "hi"
@test only(o) == "hi"
@test o[:] == ["hi"]
@test collect(o) == ["hi"]
end
#-----------------------------------------------------------------------------# HTML
@testset "HTML" begin
@test repr(n1) == "<div>hi</div>"
Expand Down

2 comments on commit 9a025d7

@joshday
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/85596

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.5.0 -m "<description of version>" 9a025d70a85c283424f4ef0c63c520fce6bedd93
git push origin v0.5.0

Please sign in to comment.