[SOLVED] Escaping backslashes from URL with Hugo

In my img shortcode I am trying to preload onmouseover a larger img for a modal:

onmouseover="this.style.backgroundImage='{{ if or (.Get "href") (.Get "src") }}{{ with .Get "href" }}url('{{ . | absURL }}'){{else}}none{{ end }}{{ end }}';"

The URL is rendered by Hugo like so:

onmouseover="this.style.backgroundImage='url('"http://localhost:1313/images/1.jpg"')';"

And it’s a broken URL because of the extra single quotes inside the url of the background image.

Is there a way to prevent these extra quotes from rendering? Or if I have to use replace how should I go about it?

EDIT
Tried htmlEscape with not much luck.
Also if I manually remove the single quotes from the shortcode then the img url is rendered in the form of

http:\/\/localhost:1313\/images\/1.jpg

I’m out of ideas…

EDIT 2
Trying every suggestion from this thread https://discuss.gohugo.io/t/safejs-being-ignored/2433/3

It’s still the same situation. Either a broken URL with the / pattern or a broken URL with extra quotes…

1 Like

I was able to remove the double quotes that Go adds automatically to the URL with safeJS like this:

onmouseover="this.style.backgroundImage='{{ if or (.Get "href") 
(.Get "src") }}{{ with .Get "href" }}url('{{ . | absURL | safeJS 
}}'){{else}}none{{ end }}{{ end }}';"

But as I discovered the URL is still broken. It gets rendered like this

onmouseover="this.style.backgroundImage='url('http://localhost:1313/images/1.jpg')';"

And the syntax of onmouseover does not want single quotes at all.

So my only option is to manually remove the single quotes from the shortcode.

But as I posted above I end up with

onmouseover="this.style.backgroundImage='{{ if or (.Get "href") 
(.Get "src") }}{{ with .Get "href" }}url({{ . | absURL 
}}){{else}}none{{ end }}{{ end }}';"

That gets rendered like so (that again doesn’t work)

onmouseover="this.style.backgroundImage='url('http:\/\/localhost:1313\/images\/1.jpg')';"

Is there a Hugo template function that will help me escape the backslashes and get a working URL?

PS. Also I have edited the topic’s title, to make the question clearer.

can you use replace to replace them with nothing?

I’ve tried replace many times.

If I use it inside the shortcode like this

onmouseover="this.style.backgroundImage='{{ if or (.Get "href") (.Get "src") }}{{ with .Get "href" }}url({{ replace . '\⁄' '⁄' | safeHTML }}){{else}}none{{ end }}{{ end }}';"

I get the error Failed to add template

If I use it in my single.html like this

{{ replace .Content "\/" "/" | safeHTML }}

I get Error while rendering "page": template: "theme/_default/single.html" is an incomplete or empty template

I tried variations of typing \/ and the html code equivalent of \⁄

And I’m failing spectacularly every time… Guess I have to think of a different way to preload these images onmousover and ontouchstart Spent way too much time banging my head with this already…

Thanks for your suggestion though.

EDIT
Another interesting discovery is that Hugo ignores the hex codes of back slash and forward slash

For example using the following in single.html

{{ replace .Content "%5C%2F" "%2F" | safeHTML }}

Produces no errors. But the backslash does not get replaced.

After banging my head for the past 12 hours. Here is the solution.

In the img shortcode it’s simply:

onmouseover="this.style.backgroundImage='{{ if or (.Get "href") (.Get "src") }}{{ with .Get "href" }}url({{ . }}){{else}}none{{ end }}{{ end }}';"

Then on single.html I am calling replace like this:

{{ replace .Content "\\/" "/" | safeHTML }}

Typing \\/ instead of \/ solved this, as incredible as it may sound.

I think that Go is very finicky though.

1 Like

Have you also considered doing this in CSS. At the risk of suggesting something entirely out of scope for your use case:

<head>
...
{{ with .Params.href }}
<style>
#page-title-urlized .whatever-class:hover {
    background-image: url('/images/{{.}}');
}
</style>
{{ end }}
</head>

Note 1: Not tested
Note 2: Disregard entirely if this is too disimilar from your intended result :smile:

I had to do this with inline JS because as far as I know there is no template variable in Hugo that produces a valid id for an element.

So there was no way for me to target the hover state for each element separately with proper CSS.

I think we are kind of saying the same thing but if have to the parameters you’re passing into the shortcode. You could embed the styles with the markup, but I can see why both solutions are getting a little sloppy. I also don’t know how many times you plan on calling this shortcode in a page, but if it’s a truly large number of times, I can see why you would want a unique ID…

Otherwise, I find utilizing one of the passed params works A-okay for adding an id attribute to an HTML element. Glad you got it up and running.

1 Like

To clarify I have something between 10-30 images per page.

For every image onmouseover and ontouchstart I preload the higher resolution version with this.style.backgroundImage

I am using a medium.com-style vanilla JS modal and when it’s opened there is a transform involved.

I needed to preload the higher resolution on the fly, because otherwise the user had to wait for the bigger image to load and it felt sluggish.

Now with the above trick opening the modal feels pretty slick even on mobile -at least on Android-.

I did all this directly in the img shortcode. And there isn’t a big performance penalty while generating the site. I noticed something like a 10ms increase in build time. And I’m more than fine with that.

The alternative would be for me to rewrite the JS modal, so that when it’s opened it shows the low-res while the high-res loads (but I had no appetite to do that).

1 Like

Got it. This sounds like it’s going to have some pretty cool results. Please feel free to share once published.

And please disregard my previous suggestions since JS now makes the most sense :smile:

1 Like