#Content OR String inside link function

73 messages · Page 1 of 1 (latest)

trail ginkgo
#

I am creating a cover page. And you can set your email. But that email can be of type content or string. This is because you can use the custom function sensitive() which allows the user to censor information when a flag is set. This means that the content is SOMETIMES censored. But the string can be used in case the user does not want to censor anything at all.

So where is my code that I have tried so far:

if type(author.email) == content {
    link("mailto:" + author.email)
} else {
    link("mailto:" + author.email)[#author.email]
}

When its not content, it works fine. But I cant get the content working for the life of me.

#

I would love to just say, this content is now a string, and all things that are not characters you can ignore

#

This for example (not email but name) can look like 2 things:

#

And I want the same for the email.

#

this is the branch im working on right now

#

Email part is in the tempalte file on line 235

tender adder
#

if a part of the email is wrapped in some other content structure (sensitive), then you need to recursively go through the content (email) to just get the string of the email

#

it is required to link to the email

#

Though, do note that censoring the email would not really help in this way as link will still link to the correct email

trail ginkgo
#

ugh haha

#

well i do have access to the cencorded flag

#

how do you do the recursive thing?

#

because i could not do that if the flag is set, and not put anything on the doc

trail ginkgo
#

yeah i gave up on it

#

lol

vale dirge
#

the string parameter of link is where it links to, not what is displayed

trail ginkgo
#

In the sensitive func I replace the characters

#

so the link will be a link, but invalid

vale dirge
#

yeah but that doesnt make technical sense

#

you cant make a link to (square) (square)

#

if ya get me

#

like you cant tell someone "visit my website at https:// (black rectangle).com"

trail ginkgo
#

yeah

vale dirge
#

rather what you need to do is to remove the link call

trail ginkgo
#

but if you dont want to censored you dont put it in the func

#

or dont set the flag

vale dirge
#

let me see if i understand then

#

are you trying to make it so #censor[aaaa #link("mailto:...", body: [a]) bbb] will automatically delete (/ turn useless) links inside it?

trail ginkgo
#

if the censor flag is set yes. The censor func I made only changes the text if a flag is set.

vale dirge
#

okay

#

then that changes the perspective I had

#

haha

#

then what you need is something like

#
#let censor(x) = {
  show link: it => it.at("body", default: if type(it.target) == str { "x" * it.target.len() } else { "xxx" })
  // your other show rules to show black boxes
  x
}
#

just an example

#

you can also just show link: none

#

if you just want to get rid of it

trail valley
# trail ginkgo how do you do the recursive thing?

There is a snippet that lets you extract plain text from some content: https://sitandr.github.io/typst-examples-book/book/typstonomicon/extract_plain_text.html

I'm not sure how directly applicable it is (if you want to use it do check it; you're trying to ensure privacy so don't just trust it) but the important part is that it recurses over the kinds of contents it encounters, and accumulates the stuff it finds into a value (here, a string). What I'd do is probably adapt that so that instead of (or in addition to) returning plain text, it returns whether a sensitive value appears anywhere in the content.

trail ginkgo
#

yo thanks! :D

#

ill defo check it out

vale dirge
#

I think show rules would be much more reliable

#

But that snippet i guess can be interesting to use in other contexts

trail valley
vale dirge
vale dirge
#

Though you could have to adapt the code to only target links containing mailto

tender adder
#

well, that would only work if it was used as censor(link(...)), from their above example it seems like the usage is link(...censor(...)...)

trail valley
# vale dirge The idea is to use links for emails, and then you just use #show link: ...

ah ok, after playing around with it I think I see what you mean. Although I thought one goal was that if the link text (i.e. possibly sensitive content) was an email, the link destination would default to be just that. That's how it sounded over in quick-questions - and that, iiuc, would require walking the content.

PS: I the snippet should say it.dest instead of it.target, just something to watch out for @trail ginkgo

trail valley
tender adder
#

ah, right. I was thinking to still extract the link if there's arbitrary content, which is probably not needed here

trail ginkgo
#

I have come one step closer

#

My current problem is as follows:

I have a content object which does not contain the field text. It only has a function which is my sensitive function. If I just do it it works but I can not concatenate it with other strings.

#

I want to basically get the result of the function

#

not a reference to the function itself

#
// author: ntjess
#let stringify-by-func(it) = {
  let func = it.func()
  return if func in (parbreak, pagebreak, linebreak) {
    "\n"
  } else if func == smartquote {
    if it.double { "\"" } else { "'" } // "
  } else if it.fields() == (:) {
    // a fieldless element is either specially represented (and caught earlier) or doesn't have text
    ""
  } else {
    panic("Not sure how to handle type `" + repr(func) + "`")
  }
}

#let plain-text(it) = {
  return if type(it) == str {
    it
  } else if type(it) == content {
    let text_str = ""
    if it.has("children") {
      for child in it.children {
        if child.has("text") {
          text_str = text_str + child.text
        } else {
          text_str = text_str + "REDACTED"
        }
      }
    }
    text_str
  } else if it == [ ] {
    " "
  } else if it.has("children") {
    it.children.map(plain-text).join()
  } else if it.has("body") {
    plain-text(it.body)
  } else if it.has("text") {
    it.text
  } else {
    stringify-by-func(it)
  }
}
#
email: [#sensitive("some")\@mail.com],
#

well

#

that works half

#

now it only censors lol

#

gosh darnit haha

#

i need to get rid of that func ref somehow

#

BUT, all the other functionality works

#

Updated code

// author: ntjess
#let stringify-by-func(it) = {
  let func = it.func()
  return if func in (parbreak, pagebreak, linebreak) {
    "\n"
  } else if func == smartquote {
    if it.double { "\"" } else { "'" } // "
  } else if it.fields() == (:) {
    // a fieldless element is either specially represented (and caught earlier) or doesn't have text
    ""
  } else {
    panic("Not sure how to handle type `" + repr(func) + "`")
  }
}

#let plain-text(it) = {
  return if type(it) == str {
    it
  } else if type(it) == content {
    let text_str = ""
    if it.has("children") {
      for child in it.children {
        if child.has("text") {
          text_str = text_str + child.text
        } else {
          // The issue is here.
          // Somehow convert this to a string
          text_str = text_str + "REDACTED"
        }
      }
    }
    text_str
  } else if it == [ ] {
    " "
  } else if it.has("children") {
    it.children.map(plain-text).join()
  } else if it.has("body") {
    plain-text(it.body)
  } else if it.has("text") {
    it.text
  } else {
    stringify-by-func(it)
  }
}
#

so close yet so far

vale dirge
#

I.e.
#show regex("\S+@\S+"): none for example would remove all emails theoretically

#

In practice there’s a bug

#

Where you can’t match on symbols used by syntax

#

For example @ is used for ref

#

So that might not work