juliaweb / hyperscript.jl Goto Github PK
View Code? Open in Web Editor NEWHyperscript: A lightweight DOM representation for Julia
License: Other
Hyperscript: A lightweight DOM representation for Julia
License: Other
Hyperscript doesn't build on nightly. The reason is https://github.com/yurivish/Hyperscript.jl/blob/7731aecafd06e9366020ebee0d6674527fe3d7d6/src/Hyperscript.jl#L117
Here's why: 1.6 has a new TOML parser that includes this line. The issue is that Union{} <: Hyperscript.AbstractNode
, because Union{}
is a subtype of every other type, and hence instead of creating an array with eltype Union{}
it tries (during package loading!) to call Union{}(xs...)
, which obviously fails. CC @KristofferC.
I am pretty sure this method counts as type-piracy (even if you own YourType
, you do not own Vector{YourType}
), so I guess the question is, can it be eliminated?
Even though the correct HTML5 thing to do is to use valueless boolean attributes or to not add them at all (i.e. <input type=checkbox checked />
versus <input type=checkbox />
), this becomes a bit awkward when generating them programmatically. In particular, if one wants to add observables to Hyperscript to add interactivity (see SimonDanisch/Bonito.jl#35 for instance), things become a bit awkward.
From what I understand, HTML5 actually disallows using "true"
or "false"
as values for boolean attributes (see here). Could it be possible to support passing checked = false
to mean that the attribute is actually not set, and checked = true
to set it?
I confess I'm not sure what the attribute should be set to with checked = true
, but I imagine anything that conforms to HTML5 would be fine (empty string, or name of the attribute, or maybe even valueless).
When calling savehtml()
it adds an extra layer of <html></html>
on top of what is already there.
julia> using Hyperscript
julia> doc1 = m("html", m("h1", "Hello"))
<html><h1>Hello</h1></html>
julia> savehtml("/tmp/doc1.html", doc1) ## html html
56
shell> cat /tmp/doc1.html
<!doctype html>
<html><html><h1>Hello</h1></html></html>
I would expect the content of the file written by savehtml
to be the same as printed, except for an added doctype.
(@v1.6) pkg> status Hyperscript
Status `~/.julia/environments/v1.6/Project.toml`
[47d2ed2b] Hyperscript v0.0.4
julia> versioninfo()
Julia Version 1.6.1
Commit 6aaedecc44 (2021-04-23 05:59 UTC)
Platform Info:
OS: Linux (x86_64-pc-linux-gnu)
CPU: Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, skylake)
The tag name "0.1" is not of the appropriate SemVer form (vX.Y.Z).
cc: @yurivish
How do I add, for example, a controls
attribute to a video tag?
<video controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
Your browser does not support the video tag.
</video>
This is awesome! I look forward to play with it more! One of my favorite features is that you can use objects from other packages inside of it, and it will call the repr(MIME"text/html"(), x)
function - this makes it super useful for composing UI. I think that Pluto.jl + Hyperscript.jl + https://pluto-on-binder.glitch.me/ has amazing potential
Just a quick question: I was thinking about the option to turn this into a HTML templating library for Julia - like https://github.com/developit/htm or https://github.com/observablehq/stdlib#html. Have you experimented with this?
Would it be useful? The current syntax is already quite easy and concise, but maybe it would be easier for people who know HTML, or if you want to copy paste some HTML.
I'm having a problem with HyperScript.jl.
This function
function pretty_stitches(image_stitches, flip_right_to_left::Bool)
# image_stitches should be the top_image_stitches or bottom_image_stitches
# of a TabletWeavingPattern.
stitch_width = 5
stitch_length = 10
stitch_diameter = 1
uses = []
function use(row, col, color, slant)
push!(uses,
m("use",
href = slant == '/' ? "#stitch1" : "#stitch2",
x="$(col * stitch_width)mm",
y="$(row * stitch_length)mm",
width="$(stitch_width)mm",
height="$(stitch_length)mm",
style="stroke: none; fill: $(color)"))
end
for (rownum, row) in enumerate(image_stitches)
for (colnum, stitch) in enumerate(row)
(color, slant) = stitch
use(rownum, colnum, color, slant)
end
end
println(length(uses))
m("svg",
viewBox="0 0 $(stitch_width * length(image_stitches[1])) $(stitch_length * length(image_stitches))",
m("g",
m("symbol", id="stitch1",
preserveAspectRatio="xMinYMin",
viewBox="0 0 $(stitch_width) $(stitch_length)",
refX="0", refY="0",
svg_stitch(stitch_width, stitch_length, stitch_diameter, '/';)),
m("symbol", id="stitch2",
preserveAspectRatio="xMinYMin",
viewBox="0 0 $(stitch_width) $(stitch_length)",
refX="0", refY="0",
svg_stitch(stitch_width, stitch_length, stitch_diameter, '\\';)),
uses...)
)
end
(you can focus on the Hyperscript calls to generate SVG at the end) produces this SVG:
<svg viewBox="0 0 80 1360">
<g>
<symbol refX="0" viewBox="0 0 5 10" refY="0" id="stitch1" preserveAspectRatio="xMinYMin">
<g>
<path style="stroke-width: 1px; vector-effect: non-scaling-stroke" d="M 0.9569057743101286 9.703069233026724 L 4.956905774310129 0.7030692330267239 A 0.5 0.5 0 0 0 4.043094225" ⋯ 259507 bytes ⋯ "B{N0f8}(1.0,0.0,0.0)" width="5mm" y="1360mm" />
<use height="10mm" href="#stitch1" x="75mm" style="stroke: none; fill: RGB{N0f8}(1.0,0.0,0.0)" width="5mm" y="1360mm" />
<use height="10mm" href="#stitch1" x="80mm" style="stroke: none; fill: RGB{N0f8}(1.0,0.0,0.0)" width="5mm" y="1360mm" />
</g>
</svg>
(which has been stringified and reformatted for readability).
Note that it also genrates the printed output
`uses` has 2176 elements.
The call
string(svg_stitch(5, 10, 1, '/';))
returns
"<path style="stroke-width: 1px; vector-effect: non-scaling-stroke" d="M 0.9569057743101286 9.703069233026724 L 4.956905774310129 0.7030692330267239 A 0.5 0.5 0 0 0 4.043094225689871 0.29693076697327614 L 0.04309422568987137 9.296930766973276 A 0.5 0.5 0 0 0 0.9569057743101286 9.703069233026724" />"
or more readably
<g>
<path style="stroke-width: 1px; vector-effect: non-scaling-stroke"
d="M 0.9569057743101286 9.703069233026724 L 4.956905774310129 0.7030692330267239 A 0.5 0.5 0 0 0 4.043094225689871 0.29693076697327614 L 0.04309422568987137 9.296930766973276 A 0.5 0.5 0 0 0 0.9569057743101286 9.703069233026724" />
</g>
That is what the content of each of the symbols should look like.
Why do the close tags in the output of pretty_stitches
not balance?
Where is the second symbol
element?
Why are the use
elements nested within the symbol's group rather
than after the symbol?
Why are there only two use
elements when there should be 2176?
Why do the attributes of an element appear in a different order in the SVG than in the source code? Maybe use OrderedDict?
Perhaps I'm misusing the m
function? My use is consistent with the examplesin the README file, but not with its function signature.
I prefer the do
syntax that the NativeSVG
package allows for, but that package is apparently no longer maintained.
Is there any benchmark for using Hyperscript compared to EzXML (libxml2) for example?
I have made a package called AcuteML that defines a couple of XML utilities for manipulating DOM:
https://github.com/aminya/AcuteML.jl/tree/master/src/xmlutils
I wanna know if Hyperscript offers more performance or other advantages over other packages.
I think only accepting Array
in
https://github.com/yurivish/Hyperscript.jl/blob/1fc13cc7cb78ec1f93c1919b80e1a1ad27a9948e/src/Hyperscript.jl#L133
is too strict.
It leads to the following surprising behavior:
julia> using Hyperscript
julia> let children = [1, 2, 3] # Array
m("div", children)
end
<div>123</div>
julia> using StaticArrays
julia> let children = @SVector Int[1, 2, 3] # not Array, but AbstractArray
m("div", children)
end
<div>[1, 2, 3]</div>
It'd be great if Hyperscript could work out-of-the-box with HTTP.jl
and this does not appear to be the case.
julia> using HTTP
julia> using Hyperscript
julia> @tags html body
julia> HTTP.Response(200, html(body("Hello")))
ERROR: MethodError: no method matching length(::Hyperscript.Node{Hyperscript.HTMLSVG})
Closest candidates are:
length(::Cmd) at process.jl:639
length(::Base.Iterators.Flatten{Tuple{}}) at iterators.jl:1061
length(::BitSet) at bitset.jl:365
...
Stacktrace:
[1] _array_for(::Type{Pair{SubString{String},SubString{String}}}, ::Hyperscript.Node{Hyperscript.HTMLSVG}, ::Base.HasLength) at ./array.jl:677
[2] mkheaders(::Hyperscript.Node{Hyperscript.HTMLSVG}) at /home/cce/.julia/packages/HTTP/IAI92/src/Messages.jl:205
[3] HTTP.Messages.Response(::Int64, ::Hyperscript.Node{Hyperscript.HTMLSVG}; body::Array{UInt8,1}, request::Nothing) at /home/cce/.julia/packages/HTTP/IAI92/src/Messages.jl:114
[4] HTTP.Messages.Response(::Int64, ::Hyperscript.Node{Hyperscript.HTMLSVG}) at /home/cce/.julia/packages/HTTP/IAI92/src/Messages.jl:111
[5] top-level scope at REPL[11]:1
"As a rule of thumb, the single-line show method should print a valid Julia expression for creating the shown object." One suggestion is to use PrettyPrinting.jl to replicate the code tree you'd need to re-generate the object. Alternatively, perhaps there is a function that would take the rendered output and re-construct the node? e.g. Node("<span>hello</span>")
might be the show
for span("hello")
, then this Node
constructor could return the same object as would be created by @tags; span("hello")
? I'm asking this because when I show
Hyperscript objects within a larger structure, I get something that isn't a valid constructor, and hence it violates the rule of thumb above.
This works:
m("input"; :type => "text")
This doesn't:
m("input", :type => "text")
In the last one, it's treating the Pair as content. It'd be nice to support the second one. If it's only allowed after a semicolon, then if you use it with a node with content, it's even clunkier because the optional arguments have to come at the end:
m("div", "My content"; :type => "something")
I think it's pretty safe to intercept Pair{Symbol, T}
and treat it as an argument. I can't think of a use where someone wants to fill in content with that.
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
Hi @yurivish, how do you feel about adding a do-block syntax (similar to markaby)? That would allow one to write the following:
using Hyperscript
@tags div em a
# What I'm proposing:
div.header() do
a(href="https://github.com/yurivish/Hyperscript.jl") do
em("Hyperscript.jl")
end
end
instead of
# Current equivalent:
div.header(a(href="https://github.com/yurivish/Hyperscript.jl", em("Hyperscript.jl")))
or, equivalently,
# Indented current equivalent:
div.header(
a(href="https://github.com/yurivish/Hyperscript.jl",
em("Hyperscript.jl")
)
)
That could increase readability in general. Of course, nothing would break; it would only be an alternative way of writing things.
If you like it, I could make a PR 😀
EDIT: a single line is all that's required to make the example above work:
julia> (x::Hyperscript.Node)(f::Function, args...; props...) = x(args..., f(); props...)
julia> div.header() do
a(href="https://github.com/yurivish/Hyperscript.jl") do
em("Hyperscript.jl")
end
end
<div class="header"><a href="https://github.com/yurivish/Hyperscript.jl"><em>Hyperscript.jl</em></a></div>
using Images
img = load("my dog.jpg")
@assert Base.showable(MIME"image/jpeg"(), img)
m("div", x)
Gives me
<div>
Images.Image{blablalba} blablab
</div>
Hyperscript.jl could check Base.showable
for MIME types like images and audio, and base64-encode the result. This would give
<div>
<img src="data:image/jpeg;base64,blablablalblkdjflgj42i9832d..." />
</div>
Do you think that this fits within the scope of the project?
I'm not sure if this is a Julia bug or if my system is messed up. The following syntax is causing an error. It works in the REPL but not with include
. Package tests work fine.
shell> cat bug.jl
div."a"("hello")
julia> include("bug.jl")
ERROR: LoadError: syntax: malformed expression
Stacktrace:
[1] include at ./boot.jl:314 [inlined]
[2] include_relative(::Module, ::String) at ./loading.jl:1067
[3] include(::Module, ::String) at ./sysimg.jl:29
[4] include(::String) at ./sysimg.jl:68
[5] top-level scope
in expression starting at /home/tshort/FS/appfiles/julia/MDPad/bug.jl:1
julia> div."a"("hello")
<div class="a">hello</div>
The PrettyPrinting.jl library uses a constraint system to find an optimal display of flow based upon the width of the user's screen. This could be used so that constructed fragments could be shown in a format suitable for display in regression tests.
Heyo,
today I wanted to add some Custom CSS properties to my code and noticed that I wasn't able to produce the leading double hyphen, e.g., --outline-color
with a camelCased attribute name. Any Ideas how to get this to work?
I saw mention of auto prefixing certain CSS attributes in the future-enhancements
section at the bottom of Hyperscript.jl
. Would this fall into this category?
Cheers
I guess something is missed in REQUIRE
? I got this when I try Pkg.add
ERROR: Hyperscript can't be installed because it has no versions that support 0.6.3 of julia. You may need to update METADATA by running `Pkg.update()`
It'd be nice to have an option to pretty-print the html renders and indent to reflect level.
In some cases, it'd be nice to be able to use Symbols instead of Strings for some values, especially ones that are names. Here's ana example:
julia> m("div", id = :hi, "hello")
<div id=":hi">hello</div>
Right now, this symbol is rendered as ":hi"
rather than "hi"
. The sprint(show, ...)
construct causes this. Would it be possible to use print
instead to get rid of the colon? Or, could we have some other way to do that?
Great package, by the way! I really like the div.someclass
and div."some-class"
syntax.
The last release, 0.0.4
, was on Nov 10, 2020, and there have been 14 commits by 7 contributors since then:
Can we release 0.0.5? @SimonDanisch We need #29 for improving Pluto support in JSServe.
Running
using Hyperscript
m("div")
raises the following error on the current version in the package registry:
ERROR: MethodError: no method matching validateattrs(::Hyperscript.Validate{true}, ::String, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}})
Closest candidates are:
validateattrs(::Hyperscript.Validate, ::Any, ::NamedTuple) at ~/.julia/packages/Hyperscript/qO5ub/src/Hyperscript.jl:80
validateattrs(::Hyperscript.NoValidate, ::Any, ::NamedTuple) at ~/.julia/packages/Hyperscript/qO5ub/src/Hyperscript.jl:94
Stacktrace:
[1] Hyperscript.Node(::Hyperscript.Validate{true}, ::String, ::Tuple{}, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at ~/.julia/packages/Hyperscript/qO5ub/src/Hyperscript.jl:111
[2] #m#7(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::String) at ~/.julia/packages/Hyperscript/qO5ub/src/Hyperscript.jl:174
[3] m(::String) at ~/.julia/packages/Hyperscript/qO5ub/src/Hyperscript.jl:174
[4] top-level scope at none:0
I need to output un-encoded strings that include raw HTML. This is easy enough to implement externally:
struct Raw
str::String
end
Base.show(io::IO, m::MIME"text/html", rawstr::Raw) = print(io, rawstr.str)
Example:
julia> m("div", Raw("<span>hi</span>"))
<div><span>hi</span></div>
Is there any interest in having this in Hyperscript?
I don't know how to add a Comment Tag, like:
<-- some comment in HTML -->
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.