Skip to content
This repository has been archived by the owner on Sep 17, 2022. It is now read-only.

Representing hyperlinks in Pollen #27

Open
basus opened this issue Jan 24, 2020 · 15 comments
Open

Representing hyperlinks in Pollen #27

basus opened this issue Jan 24, 2020 · 15 comments

Comments

@basus
Copy link

basus commented Jan 24, 2020

I was wondering how people represent hyperlinks in Pollen. Currently I have the following tag functions for general links, and internal (same site) links:

(define (link url . text)
  `(a ((href ,url)) ,@text))

(define (internal url . text)
  (let ([url (string-append "/" url)])
    `(a ((href ,url)) ,@text)))

So I can write links as ◊link["https://link.url"]{Link Text}. It's a little suboptimal since I have to wrap the URL in quotes. I also don't handle alt text or such. Any other ideas for how to represent links?

@ergl
Copy link

ergl commented Jan 24, 2020

The only fancy thing is have an option for links that should open in a new tab:

(define (l addr #:ext [external #f] . contents)
  (define attrs (if external
                    `((href ,addr) (target "_blank") (rel "noopener") (class "external"))
                    `((href ,addr))))
  (if (empty? contents)
    `(a ,attrs ,addr)
    `(a ,attrs ,@contents)))

Ideally I'd like to avoid quoting the url part, but I haven't bothered too much with it

@oldmankit
Copy link

Extending what @ergl gives but for alt text:

(define (link url #:alt [alt #f] . text)
  (define attrs
    (if alt
       `((href ,url) (alt ,alt))
       `((href ,url) (alt ,@text)))) ; If no alt is given, use the text contents as alt

  (if (empty? text)
    `(a ,attrs ,url)
    `(a ,attrs ,@text)))

You could use this pattern for any properties you liked.

Personally speaking, when I started writing text in Pollen I thought it would be nice not to need quotation marks around the url of links because it somehow feels sub-optimal, but I got used to it very quickly. Now that I'm used to the syntax it would feel strange not to have them in there.

@mbutterick
Copy link
Owner

mbutterick commented Jan 25, 2020

If no alt is given, use the text contents as alt

Beware — despite the name, text is a list of X-expression elements. If it contains more than one item, or something other than a string (say, another tagged X-expression) your alt attribute will be invalid.

Since your attribute value needs to be a single string, you’d want to extract the strings within text and concatenate them, perhaps like so:

(apply string-append (findf*-txexpr (cons '@ text) string?))

@otherjoel
Copy link

In my current project, I specify all links reference-style, e.g.:

#lang pollen

If you need help, ◊link[1]{Google it}.

◊url[1]{https://google.com}

The implementation can be seen here. It’s probably more complicated than most people want, but hey, there are no quote marks around the urls. (Never thought about that before to be honest!) I just like not having inline URLs breaking up the prose.

Under this implementation, you can put the url tag for a given identifier anywhere in the document, even before it is referenced. If you create a link for an identifier that has no corresponding url, a "Missing reference: [link-id]" message will be substituted for the URL. Conversely, creating a url that is never referenced will produce no output and no warnings or errors.

@sorawee
Copy link

sorawee commented Jan 25, 2020

@otherjoel separating it into link and url is very clever! But personally I kinda dislike using number because it's not descriptive and consequently make it easy to get it wrong. I would personally write ◊link[google-web]{Google it} and where google-web is a Racket identifier. With this way, we get a check that our identifier is indeed defined for free! The disadvantage though is that the urls must be defined at the top. Perhaps there's a way to make url a macro that lifts itself up to the top?

@odanoburu
Copy link

I would personally write ◊link[google-web]{Google it} and where google-web is a Racket identifier.

me too! this is similar to the way most latex packages handle referencing. I would urge everyone to include something akin to the HTML "alt" attribute for accessibility (assuming your output target format can handle it properly)

With this way, we get a check that our identifier is indeed defined for free!

a side-question: what kind of error message would we get here? I've been thinking about validating/throwing errors in tag functions lately, and I wonder if it's possible to include the location of the error in the source file (i.e., the location of the tag in the source file, not of the location of the tag function in pollen.rkt). is this location information available to the tag function? if not, can it be made available?

@otherjoel
Copy link

@otherjoel separating it into link and url is very clever! But personally I kinda dislike using number because it's not descriptive and consequently make it easy to get it wrong.

I thought of that too 😎 Since I run the identifier through format, you can use any stringish value including a symbol:

◊link['google]{Google it}.

◊url['google]{https://google.com}

Your idea is interesting too. For this project I really like the simplicity/flexibility tradeoff I’ve already made though :-)

@otherjoel
Copy link

I've been thinking about validating/throwing errors in tag functions lately, and I wonder if it's possible to include the location of the error in the source file (i.e., the location of the tag in the source file, not of the location of the tag function in pollen.rkt). is this location information available to the tag function? if not, can it be made available?

This reminds me of something I was going to post here. I’ll start a separate discussion for it.

@sorawee
Copy link

sorawee commented Jan 25, 2020

One of the designs I still do not totally understand is how the content is passed in variadically (and this is actually due to Scribble). This limits us to only have one content block. It would be cool if we can have multiple content blocks like LaTeX: ◊link{https://google.com}{Google it} is equivalent to (link '("https://google.com") '("Google it")).

@mbutterick
Copy link
Owner

I suggested this long ago, to no avail.

@basus
Copy link
Author

basus commented Jan 25, 2020

Using Racket symbols instead of URLs enables something I've wanted from CMS' for a while: defining commonly used links outside of individual posts. So instead of 'google being defined in the same file, it could be defined in separate links.rkt file somewhere and inserted by the link function.

@otherjoel
Copy link

So instead of 'google being defined in the same file, it could be defined in separate links.rkt file

@basus Note that 'google is a symbol (note the preceding apostrophe), that is, a literal value; like the string "google" or the number 2, it is not definable, it just is what it is. Beautiful Racket has good explainers on the difference between symbols and identifiers (names for variables).

But you’re on the right track. If you don’t mind specifying each reference before it is used, you can use identifiers in place of strings for URLs, with no changes to your existing tag functions:

◊define[google]{https://google.com}

◊link[google]{let’s go searching}

Or if you want to define common links in a separate file as you were saying:

#lang racket/base  ; links.rkt

(provide (all-defined-out))

(define google "https://google.com")
#lang racket/base ; pollen.rkt

(require "links.rkt")
(provide (all-from-out "links.rkt"))

Now your Pollen sources can use the definition of google or anything else in links.rkt without defining it first.

@basus
Copy link
Author

basus commented Jan 27, 2020

Ahh ok, that's interesting. I am still a Racket newbie, so not entirely clear on the various different datatypes and their representations. This might be too much overhead for most uses, but we'll see.

@otherjoel
Copy link

Can you clarify what you mean by "overhead"? Computationally, it's practically nothing.

To make things even simpler, you could leave out the links.rkt file and just define the links in pollen.rkt. Anything provided there is automatically available in your Pollen sources.

@basus
Copy link
Author

basus commented Jan 28, 2020

I meant overhead for authors/users. I don't know if there are links I repeat often enough to make this approach worthwhile. Still cool to be able to do it though.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants