@sylumer - Sorry, I was referring to the original script.
The script would create a new draft from a list of templates. My question is, can it be modified to populate with an existing draft.
Eg. I open Drafts and start typing up notes for a meeting I’m in. I then want to run an Action/Script that would take that note I just wrote, allow me to choose a template (like in the script mentioned in the original post) and create a new drafts with said template and notes content.
That comes back to my note at the end of my post above as to how that action produces the list. It is looking for a particular tag on a draft, so all you need to do is update the tag list for the draft to include it. You could do that manually with a few taps, or by creating an action to add the tag and update the draft.
Drafts can have tags. Not template tags, but actual tags. That is what the list in the action uses to determine what drafts to put in the template list.
I guess I wasn’t very clear. I know about the draft tag, “template”, that you highlighted. That’s what I’ve already done.
I don’t need help to add additional drafts/notes to the list of selectable templates.
What I needed help with was getting the content of the current, open draft (at the time I click on the Action) and having that populate the template that I choose.
Currently, the “Creating New Drafts with Template” action doesn’t allow for that.
Anyway, I tried modifying the code, and it now works as I described above. I’ll paste the modification here, in case anyone is interested (or could suggest a better method):
before the: let f = () => {
add a new line: let cont = draft.content;
in between these two lines: d.content = d.processTemplate(lines.join('\n')); d.update();
add a new line: d.content = d.content.replace("[[content]]", cont);
In the actual templates, you’ll have to include the [[content]] tag to where you want the draft content to go.
I saved this as a separate Action for when I want to populate a templated draft using my current note.
In the original Action, I added a line to remove the [[content]] tag from the templates for when I just want a blank template.
I might have got the wrong end of the stick here, but if I put Textexpander snippets “<<>>” with angled brackets in the template, when running the action “New draft with template,” I select the template from those available in the prompt and then the new draft that opens has any Textexpander snippets within expanded.
UPDATE - 2020/11/01 The current version of this action has been updated with new features, such as cursor placement, as of Nov. 1, 2020. You may need to reinstall the action from the directory if you have a previous version installed.
You could use a personal automation in Shortcuts on i*OS to create a new draft each day with the content you require.
On macOS, there are many ways you could schedule the creation of a new draft using scheduled scripting (AppleScript, creating a new file in Drafts’ import folder, etc.)
Thanks for the tip! I would love to quickly load a boilerplate template and immediately fill in some variables using a prompt.
Would it be possible to modify this action to load up a template and immediately parse it with the mustache prompt action without having to run the 2 actions separately?
I tried removing ‘d.processTemplate’ from the script when creating a new template and then have the mustache prompt action run immediately after but it seems that it needs to first reference the draft just created by the New Drafts from Template Action and I’m not really sure how to do that.
Thanks for the quick reply. I understand that the draft created in the first action references d. But I get lost trying to see where the draft is referenced in the second action (mustache prompt). I’m in my infancy with JS so please excuse my ignorance. In the following code if I wanted to refer to the subsequent draft references what would they replace?
function mustachePrompt(text, dateFormat) {
dateFormat = (dateFormat === undefined) ? "%Y-%m-%d" : dateFormat
const variableRegex = /{{(?:(date|bool):)?(#|^)?(\w+)\??([+|-]\d+[d|w|m])?}}/g
const variableMatches = text.matchAll(variableRegex)
variables = {}
for (match of variableMatches) {
let instance = new Object()
instance.string = match[0]
instance.type = match[1]
instance.modifier = match[2]
instance.name = match[3]
instance.offset = match[4]
if (!variables.hasOwnProperty(instance.name)) {
let variable = new Object()
variable.type = instance.type
variable.modifier = instance.modifier
variable.instances = [instance]
variables[instance.name] = variable
} else {
variables[instance.name].instances.push(instance)
if (!variables[instance.name].type) {
variables[instance.name].type = instance.type
}
if (!variables[instance.name].modifier) {
variables[instance.name].modifier = instance.modifier
}
}
}
//alert(JSON.stringify(variables))
let p = Prompt.create()
for (name in variables) {
let variable = variables[name]
if (!variable.type) {
p.addTextField(name, name, "")
} else if (variable.type == "date") {
p.addDatePicker(name, name, new Date(), {mode: "date"})
} else if (variable.type == "bool") {
p.addSwitch(name, name, false)
}
}
p.addButton("OK")
data = {}
let cancel = true
if (Object.keys(variables).length !== 0) {
cancel = !p.show()
}
if (!cancel) {
for (key in p.fieldValues) {
let fieldValue = p.fieldValues[key]
if (fieldValue instanceof Date) {
data[key] = strftime(fieldValue, dateFormat)
} else if (typeof fieldValue == "string") {
if (fieldValue.includes(",") && variables[key].modifier == "#") {
data[key] = fieldValue.split(",").map(s => s.trim())
} else {
data[key] = fieldValue
}
} else {
data[key] = fieldValue
}
for (instance of variables[key].instances) {
if (!instance.type && !instance.offset) {
continue
}
if (instance.offset) {
text = text.replace(instance.string, instance.string.replace(instance.type + ":", "").replace(instance.offset, snakify(instance.offset)))
data[key + snakify(instance.offset)] = offsetDate(fieldValue, instance.offset, dateFormat)
} else {
text = text.replace(instance.string, instance.string.replace(instance.type + ":", ""))
}
}
}
//alert(JSON.stringify(data, 2))
let template = MustacheTemplate.createWithTemplate(text)
let result = template.render(data)
return result
} else {
context.cancel()
}
}
function offsetDate(date, string, dateFormat) {
let d = new Date(date)
let offsetRegex = /(\+|-)(\d+)(d|w|m)/
let match = string.match(offsetRegex)
let multiplier = (match[1] == "+" ? 1 : -1)
if (match[3] == "d") {
d.setDate(d.getDate() + multiplier * parseInt(match[2]))
} else if (match[3] == "w") {
d.setDate(d.getDate() + multiplier * 7 * parseInt(match[2]))
} else if (match[3] == "m") {
d = addMonths(d, multiplier * parseInt(match[2]))
}
return strftime(d, dateFormat)
}
function addMonths(date, months) {
var d = date.getDate();
date.setMonth(date.getMonth() + +months);
if (date.getDate() != d) {
date.setDate(0);
}
return date;
}
function snakify(offset) {
return offset.replace("+", "_offset_forward_").replace("-", "_offset_backwards_")
}
Thanks @sylumer
I have been playing around with things in the scripts, in particular, step 3 of the mustache prompts but still struggle to see how to have the mustache prompt reference and process the selected template.
I see that step 3 looks for the template tag “mustache” so my assumption would be that I need to somehow take the draft from the first action defined as d and assign a template tag of mustache to it? Is that a correct assumption? If so, then it looks like the template tag is assigned in step two of the mustache prompt. I have tried different variations of using d in steps 2 and 3 to no avail? Evidently, I need a deeper crash course into javascript.
Okay, so having taken a deeper look I don’t think it would have fully worked previously as two separate actions without some tinkering due to the ordering of the (Drafts) template processing.
It strips out the new draft creation in the new from template, and passes the selected draft template to the mustache processing. That I have amended to process the passed in draft rather than the current draft, but to also apply Drafts template processing after the mustache template processing - which is what gave me issues when I tried them as two separate, but consecutive actions.
This therefore has no intermediate or additional drafts. You select the template and it builds the output as a new draft. The template must be a valid mustache template as per the original mustache action.
Give it a whirl. Nothing new in it. Just joined them up and shuffled a few things and took out some processing that was no longer required.