Skip to content

Commit

Permalink
Merge pull request #3 from algunion/htmx
Browse files Browse the repository at this point in the history
utility functions
  • Loading branch information
algunion committed Jun 25, 2023
2 parents 696f003 + f2d145e commit c789175
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 3 deletions.
4 changes: 4 additions & 0 deletions src/HTMLForge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export HTMLElement,
hasattr,
getattr,
setattr!,
findfirst,
getbyid,
applyif!,
parsehtml,
postorder,
preorder,
Expand All @@ -24,6 +27,7 @@ export HTMLElement,
include("htmltypes.jl")
include("manipulation.jl")
include("comparison.jl")
include("htmx.jl")
include("io.jl")
include("conversion.jl")

Expand Down
2 changes: 2 additions & 0 deletions src/htmltypes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ end
struct InvalidHTMLException <: Exception
msg::AbstractString
end


19 changes: 19 additions & 0 deletions src/htmx.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const HTMX_ATTRS = [:trigger, :target, :post, :get, :put, :patch, :delete, :swap, :indicator, :sync, :preserve, :include, :params, :encoding, :confirm, :disinherit, :boost, :select, :pushurl, :selectoob, :swapoob, :historyelt]
const HIPHENATED = Dict(:pushurl => Symbol("push-url"), :selectoob => Symbol("select-oob"), :swapoob => Symbol("swap-oob"), :historyelt => Symbol("history-elt"))

_hyphenate(x::Symbol) = haskey(HIPHENATED, x) ? HIPHENATED[x] : x

function hx(el::HTMLElement; kw...)
hxattrs = Dict("hx-$(_hyphenate(Symbol(k)))" => string(v) for (k,v) in kw)
HTMLElement{tag(el)}(el.children, el.parent, merge(attrs(el), hxattrs))
end

Base.propertynames(::Type{hx}) = HTMX_ATTRS
function Base.getproperty(::Type{hx}, name::Symbol)
if name in HTMX_ATTRS
_hyphenate(name)
else
error("hx does not have property $name")
end
end

21 changes: 20 additions & 1 deletion src/manipulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ hasattr(elem::HTMLElement, name) = name in keys(attrs(elem))


AbstractTrees.children(elem::HTMLElement) = elem.children
AbstractTrees.children(elem::HTMLText) = ()
AbstractTrees.children(::HTMLText) = ()

# TODO there is a naming conflict here if you want to use both packages
# (see https://github.com/JuliaWeb/Gumbo.jl/issues/31)
Expand All @@ -33,6 +33,25 @@ Base.setindex!(elem::HTMLElement,i,val) = setindex!(elem.children,i,val)

Base.push!(elem::HTMLElement,val) = push!(elem.children, val)

findfirst(f::Function, doc::HTMLDocument) :: Union{HTMLElement, Nothing} = findfirst(f, doc.root)
function findfirst(f::Function, elem::HTMLElement) :: Union{HTMLElement, Nothing}
for el in AbstractTrees.StatelessBFS(elem)
el isa HTMLElement && f(el) && return el
end
return nothing
end

# more utility functions
getbyid(doc::HTMLDocument, id::AbstractString) = getbyid(doc.root, id) :: Union{HTMLElement, Nothing}
getbyid(elem::HTMLElement, id::AbstractString) = findfirst(x -> hasattr(x, "id") && getattr(x, "id") == id, elem) :: Union{HTMLElement, Nothing}

applyif!(condition::Function, f!::Function, doc::HTMLDocument) = applyif!(condition, f!, doc.root)
function applyif!(condition::Function, f!::Function, elem::HTMLElement)
for el in AbstractTrees.StatelessBFS(elem)
el isa HTMLElement && condition(el) && f!(el)
end
end


# text

Expand Down
14 changes: 13 additions & 1 deletion test/basics.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# tests of basic utilities for working with HTML

import HTMLForge: HTMLNode, NullNode
import HTMLForge: HTMLNode, NullNode, findfirst

# convenience constructor works
@test HTMLElement(:body) == HTMLElement{:body}(HTMLNode[],
Expand All @@ -17,3 +17,15 @@ let
@test getattr(elem, "bar", "qux") == "qux"
@test getattr(() -> "qux", elem, "bar") == "qux"
end

@testset "HTML manipulation" begin
doc = open("$testdir/fixtures/attrs_test.html") do attrstest
read(attrstest, String) |> parsehtml
end
@test doc.root |> tag == :HTML
@test findfirst(x -> hasattr(x, "id") && getattr(x, "id") == "myid", doc.root) |> tag == :p
@test getbyid(doc.root, "myid") |> tag == :p
applyif!(x -> x |> tag == :div, x -> setattr!(x, "class", "wide"), doc.root)
@test findfirst(x -> hasattr(x, "class") && getattr(x, "class") == "wide", doc.root) |> tag == :div
println(doc)
end
14 changes: 14 additions & 0 deletions test/fixtures/attrs_test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<HTML>
<head></head>
<body>
<p class="repo-description"></p>
<blockquote class="search_headline">
<p id="fooid">
Foo
</p>
</blockquote>
<p id="myid"></p>
<div></div>
<div></div>
</body>
</HTML>
2 changes: 1 addition & 1 deletion test/parsing.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# basic test that parsing works correctly

testdir = dirname(@__FILE__)


@test_throws HTMLForge.InvalidHTMLException parsehtml("", strict=true)

Expand Down
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Test
using HTMLForge

testdir = dirname(@__FILE__)

include("basics.jl")
include("comparison.jl")
include("parsing.jl")
Expand Down

0 comments on commit c789175

Please sign in to comment.