mbutterick / pollen-users

please use https://forums.matthewbutterick.com/c/typesetting/ instead
https://forums.matthewbutterick.com/c/typesetting/
52 stars 0 forks source link

Ignoring certain elements in decode-paragraphs #22

Open zachmandeville opened 4 years ago

zachmandeville commented 4 years ago

Hello!

I am making a pollen site that includes a form, which is organized into a series of fieldsets.

I would like to write the form like so:

 ◊fieldset[]{
 ◊legend{About You}
 ◊text-input[#:for "Name"]{}
 ◊text-input[#:for "Email"]{}
 ◊text-input[#:for "Emergency Contact"]{Who should we call (name and number)? }}

(the text input will make a label and input based on #:for, with any text in the curly braces added as helper text)

The issue I'm having is that, when this renders, everything inside of fieldset gets wrapped in a <p> tag, and so the legend is not added correctly and it loses semantic clarity. I can remove the linebreaks in my page and solve the issue, but then the pollen file is hard to read.

I have decode-paragraphs added in the style given in the pollen tutorial, and love it for the other pages in this site:

 (define (root . elements)
-     (txexpr 'root empty (decode-elements elements
                                           #:txexpr-elements-proc decode-paragraphs
                                           #:string-proc (compose1 smart-quotes smart-dashes))))

I think it is causing the <p> tag wrapping on the form, though.

Is it possible to have it pass over elements like fieldset, so I can get both the pollen file and html output I want?

Thank you!

zachmandeville commented 4 years ago

alternately: is there a recommended way to write a fieldset tag function so it's not wrapping things in <p> tags? If I could do it with a tag function, I'd want a fieldset structured like so:

 ◊fieldset[#:legend "About You"]{
 ◊text-input[#:for "Name"]{}
 ◊text-input[#:for "Email"]{}
 ◊text-input[#:for "Emergency Contact"]{Who should we call (name and number)? }}

Currently, I have my functions defined as so:

(define  (get-attr attributes keyword)
  ;; given a list of attributes, and a keyword of specific attribute
  ;; return the value of this attribute.
  (define attribute (car (filter (λ (x) (eq? (car x) keyword)) attributes)))
  (list-ref attribute 1))

(define-tag-function (text-input attrs note)
;; create three sibling elements: label, p.form-note, input[type=text].
;; keyword for is used for the label text and input id.
;; all other keywords fed as attributes to input.
;; If note given, it is used for a <p> tag, otherwise <p> is not created.
  (define label (get-attr attrs 'for))
  (define id (string-downcase(string-replace label " " "-")))
  (define attributes (filter (λ (x) (not(eq? (car x) 'for))) attrs))
  `(@
    (label ((for ,id)) ,label)
    ,(when (not (null? note)) `(p ((class "form-note")),@note))
    (input ((type "text") (id ,id) ,@attributes))))

(define-tag-function (fieldset attrs elems)
;; creates fieldset element, with label keyword used to generate label element.
;; should be able to handle any input tags included in the elems.
  (define legend (get-attr attrs 'legend))
  `(fieldset (legend ,legend) ,@elems))

For the fieldset, if I don't include the @elems it generates the proper html:

<fieldset>
  <label>about me</label>
</fieldset>

if I do include ,@elems it wraps everything in fieldset in a p tag, including that explicitly defined legend:

<fieldset>
  <p>
     <legend>about me</legend>
     <label for="name">name</label>
     <input type='text' id='name'>
  </p>
</fieldset>

There must be something I'm doing wrong, but I'm baffled.

Thank you!

mbutterick commented 4 years ago

Is it possible to have it pass over elements like fieldset, so I can get both the pollen file and html output I want?

Try the #:exclude-tags option of decode-elements.

Also keep in mind that by default, Pollen treats fieldset as a block tag, so it gets some extra semantics that an ordinary tag function would not.

zachmandeville commented 4 years ago

Ah, this worked perfectly. Thank you!