How to get whitespace between html tags - html

Using Elm's Html module, the output do not have any whitespace between html tags. But for inline displayed tags, whitespace has a function and makes the browser display empty space between them.
div []
[ strong [] [ text "Key:" ]
, span [] [ text "value" ]
, text "(extra)"
]
Results in:
<div><strong>Key:</strong><span>value</span>(extra)</div>
Shown in a browser as: Key:value(extra)
Desired result
The desired html must have some kind of whitespace:
<div>
<strong>Key:</strong>
<span>value</span>
(extra)
</div>
Shown in browser as: Key: value (extra)

You could just put whitespace between the elements manually:
div []
[ strong [] [ text "Key:" ]
, text " "
, span [] [ text "value" ]
, text " "
, text "(extra)"
]
Or if you want something more generic you can easily write a function to do so using List.intersperse, e.g.:
withSpacing : List (Html msg) -> List (Html msg)
withSpacing =
List.intersperse (text " ")
main : Html msg
main =
div []
(withSpacing
[ strong [] [ text "Key:" ]
, span [] [ text "value" ]
, text "(extra)"
]
)
Or with even more convenience, based on the reasonable assumption that you'll be applying it to a function that takes a list of child elements to produce a single element:
withSpacing : (List (Html msg) -> Html msg) -> List (Html msg) -> Html msg
withSpacing element =
List.intersperse (text " ") >> element
main : Html msg
main =
withSpacing (div [])
[ strong [] [ text "Key:" ]
, span [] [ text "value" ]
, text "(extra)"
]

You can make a wrapper for Html tags as follows:
type alias HtmlTag msg =
List (Html.Attribute msg) -> List (Html msg) -> Html msg
interspaced : HtmlTag msg -> HtmlTag msg
interspaced fn =
\attr content -> fn attr (content |> List.intersperse (text " "))
main : Html msg
main =
interspaced div []
[ strong [] [ text "Key:" ]
, span [] [ text "value" ]
, text "(extra)"
]

Related

UniqueDecodeError from urllib2 output from webpage with no non-unicode characters

I am trying to read data off an api webpage using urllib2 in Python2.7. I am using the following lines to read the page:
url = 'https://api.edamam.com/api/nutrition-data?app_id=<my_app_id>&app_key=<my_app_key>&ingr=1cheeseburger'
json_obj = urllib2.urlopen(url)
data = json.load(json_obj)
These lines give me this error (the error is on the last line in the above code):
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb5 in position 0: invalid start byte
I understand that this error means that there are non-unicode characters in json_obj but I am not sure why this is the case, because the same url opens in a browser and the first few lines on the webpage looks like the following:
{
"uri" : "http://www.edamam.com/ontologies/edamam.owl#recipe_2a58ff3e1fec41d79da72f0be446baaa
"calories" : 312,
"totalWeight" : 119.0,
"dietLabels" : [ "BALANCED" ],
"healthLabels" : [ "PEANUT_FREE", "TREE_NUT_FREE", "ALCOHOL_FREE" ],
"cautions" : [ ],
"totalNutrients" : {
"ENERC_KCAL" : {
"label" : "Energy",
"quantity" : 312.96999999999997,
"unit" : "kcal"
},
As you can see, there are no non-unicode characters on this webpage, so I don't really follow what is going on.

Mdl: Material Icon in input field

I am looking into a way to get the following (taken from the material website):
I have managed to do get an icon in an input field with Bootstrap using input-group. But I cannot find a good and clear way on how to do this with mdl.
I am using elm but a html/css solution is fine.
I solved it with some css stuff.
passwordIconStyle : Attribute Msg
passwordIconStyle =
style
[ ("position", "absolute")
, ("top", "18px")
, ("right", "5px")
, ("cursor", "pointer")
]
passwordField : Model -> Html Msg
passwordField model =
div [ style [ ("position", "relative") ] ]
[ Textfield.render Mdl [1] model.mdl
[ Textfield.label "Password"
, Textfield.floatingLabel
, Textfield.password
, Textfield.value model.password
, Textfield.error model.passwordError
|> Options.when (not <| isEmpty model.passwordError)
, Options.onInput UpdatePassword
, Options.css "padding-right" "40px"
]
[]
, i [ passwordIconStyle ]
[
visibility Color.gray 25
]
]
result:
I've done an this small example. I hope it can help you.
import Material as Mdl
import Material.Textfield as Textfield
import Html exposing (..)
type alias Model =
{ mdl :
Mdl.Model
}
model : Model
model =
{ mdl =
Mdl.model
-- Boilerplate: model store for any and all Mdl components you use.
}
type Msg
= Mdl (Mdl.Msg Msg)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
-- Boilerplate: Mdl action handler.
Mdl msg_ ->
Mdl.update Mdl msg_ model
view : Model -> Html Msg
view model =
div []
[ Textfield.render Mdl
[ 2 ]
model.mdl
[ Textfield.label "Floating label"
, Textfield.floatingLabel
, Textfield.text_
]
[]
, Textfield.render Mdl
[ 5 ]
model.mdl
[ Textfield.label "Enter password"
, Textfield.floatingLabel
, Textfield.password
]
[]
]
main : Program Never Model Msg
main =
Html.program
{ view = view
, update = update
, subscriptions = \_ -> Sub.none
, init = ( model, Cmd.none )
}
Remember that you have to add to your index.html links to the css of mdl.

automatic label resizing in Rebol3 Saphir

I tried to improve the Tip Calculator example a bit, so that "Total: " doesn't disappear when you hit enter on the tip field:
REBOL [title: "Tip Calculator"]
view [
f: field "49.99"
hpanel [
t: field "20" on-action [
set-face x rejoin ["Total: " round/to to money! ((to-decimal get-face f) * ((to-decimal get-face t) * .01 + 1)) $.01 ]
]
title "%"
]
x: title "Total: " facets [ auto-size true ]
]
However, the auto-size doesn't seem to help the fact that x stays too skinny after calculation. This works:
x: title "Total: " 150x20
...as does this:
x: title "Total: "
...but how can I get it to resize automatically?
As title seems to descend from text, which is defined as auto-size: false, it would be the most easy solution to replace title with a style defined with auto-size: true e.g info
x: info "Total: "
Otherwise you would have to redefine your own title style descending from a autosizing style.

Ragged list or data frame to JSON

I am trying to create a ragged list in R that corresponds to the D3 tree structure of flare.json. My data is in a data.frame:
path <- data.frame(P1=c("direct","direct","organic","direct"),
P2=c("direct","direct","end","end"),
P3=c("direct","organic","",""),
P4=c("end","end","",""), size=c(5,12,23,45))
path
P1 P2 P3 P4 size
1 direct direct direct end 5
2 direct direct organic end 12
3 organic end 23
4 direct end 45
but it could also be a list or reshaped if necessary:
path <- list()
path[[1]] <- list(name=c("direct","direct","direct","end"),size=5)
path[[2]] <- list(name=c("direct","direct","organic","end"), size=12)
path[[3]] <- list(name=c("organic", "end"), size=23)
path[[4]] <- list(name=c("direct", "end"), size=45)
The desired output is:
rl <- list()
rl <- list(name="root", children=list())
rl$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[[1]]$children[1] <- list(list(name="direct", children=list()))
rl$children[[1]]$children[[1]]$children[[1]]$children[1] <- list(list(name="end", size=5))
rl$children[[1]]$children[[1]]$children[2] <- list(list(name="organic", children=list()))
rl$children[[1]]$children[[1]]$children[[2]]$children[1] <- list(list(name="end", size=12))
rl$children[[1]]$children[2] <- list(list(name="end", size=23))
rl$children[2] = list(list(name="organic", children=list()))
rl$children[[2]]$children[1] <- list(list(name="end", size=45))
So when I print to json it's:
require(RJSONIO)
cat(toJSON(rl, pretty=T))
{
"name" : "root",
"children" : [
{
"name" : "direct",
"children" : [
{
"name" : "direct",
"children" : [
{
"name" : "direct",
"children" : [
{
"name" : "end",
"size" : 5
}
]
},
{
"name" : "organic",
"children" : [
{
"name" : "end",
"size" : 12
}
]
}
]
},
{
"name" : "end",
"size" : 23
}
]
},
{
"name" : "organic",
"children" : [
{
"name" : "end",
"size" : 45
}
]
}
]
}
I am having a hard time wrapping my head around the recursive steps that are necessary to create this list structure in R. In JS I can pretty easily move around the nodes and at each node determine whether to add a new node or keep moving down the tree by using push as needed, eg: new = {"name": node, "children": []}; or new = {"name": node, "size": size}; as in this example. I tried to split the data.frame as in this example:
makeList<-function(x){
if(ncol(x)>2){
listSplit<-split(x,x[1],drop=T)
lapply(names(listSplit),function(y){list(name=y,children=makeList(listSplit[[y]]))})
} else {
lapply(seq(nrow(x[1])),function(y){list(name=x[,1][y],size=x[,2][y])})
}
}
jsonOut<-toJSON(list(name="root",children=makeList(path)))
but it gives me an error
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
The function given in the linked Q&A is essentially what you need, however it was failing on your data set because of the null values for some rows in the later columns. Instead of just blindly repeating the recursion until you run out of columns, you need to check for your "end" value, and use that to switch to making leaves:
makeList<-function(x){
listSplit<-split(x[-1],x[1], drop=TRUE);
lapply(names(listSplit),function(y){
if (y == "end") {
l <- list();
rows = listSplit[[y]];
for(i in 1:nrow(rows) ) {
l <- c(l, list(name=y, size=rows[i,"size"] ) );
}
l;
}
else {
list(name=y,children=makeList(listSplit[[y]]))
}
});
}
I believe this does what you want, though it has some limitations. In particular, it is assumed that every branch in your network is unique (i.e. there can't be two rows in your data frame that are equal for every column other than size):
df.split <- function(p.df) {
p.lst.tmp <- unname(split(p.df, p.df[, 1]))
p.lst <- lapply(
p.lst.tmp,
function(x) {
if(ncol(x) == 2L && nrow(x) == 1L) {
return(list(name=x[1, 1], size=unname(x[, 2])))
} else if (isTRUE(is.na(unname(x[ ,2])))) {
return(list(name=x[1, 1], size=unname(x[, ncol(x)])))
}
list(name=x[1, 1], children=df.split(x[, -1, drop=F]))
}
)
p.lst
}
all.equal(rl, df.split(path)[[1]])
# [1] TRUE
Though note you had the organic size switched, so I had to fix your rl to get this result (rl has it as 45, but your path as 23). Also, I modified your path data.frame slightly:
path <- data.frame(
root=rep("root", 4),
P1=c("direct","direct","organic","direct"),
P2=c("direct","direct","end","end"),
P3=c("direct","organic",NA,NA),
P4=c("end","end",NA,NA),
size=c(5,12,23,45),
stringsAsFactors=F
)
WARNING: I haven't tested this with other structures, so it's possible it will hit corner cases that you'll need to debug.

Using RJSONIO and AsIs class

I am writing some helper functions to convert my R variables to JSON. I've come across this problem: I would like my values to be represented as JSON arrays, this can be done using the AsIs class according to the RJSONIO documentation.
x = "HELLO"
toJSON(list(x = I(x)), collapse="")
"{ \"x\": [ \"HELLO\" ] }"
But say we have a list
y = list(a = "HELLO", b = "WORLD")
toJSON(list(y = I(y)), collapse="")
"{ \"y\": {\n \"a\": \"HELLO\",\n\"b\": \"WORLD\" \n} }"
The value found in y -> a is NOT represented as an array. Ideally I would have
"{ \"y\": [{\n \"a\": \"HELLO\",\n\"b\": \"WORLD\" \n}] }"
Note the square brackets. Also I would like to get rid of all "\n"s, but collapse does not eliminate the line breaks in nested JSON. Any ideas?
try writing as
y = list(list(a = "HELLO", b = "WORLD"))
test<-toJSON(list(y = I(y)), collapse="")
when you write to file it appears as:
{ "y": [
{
"a": "HELLO",
"b": "WORLD"
}
] }
I guess you could remove the \n as
test<-gsub("\n","",test)
or use RJSON package
> rjson::toJSON(list(y = I(y)))
[1] "{\"y\":[{\"a\":\"HELLO\",\"b\":\"WORLD\"}]}"
The reason
> names(list(a = "HELLO", b = "WORLD"))
[1] "a" "b"
> names(list(list(a = "HELLO", b = "WORLD")))
NULL
examining the rjson::toJSON you will find this snippet of code
if (!is.null(names(x)))
return(toJSON(as.list(x)))
str = "["
so it would appear to need an unnamed list to treat it as a JSON array. Maybe RJSONIO is similar.