Button to create Google Calendar event based on the current tiddler

Detailed and comprehensive. Kudos @vilc !

1 Like

Looking for making it compatible with FOOS “NextCloud” : Calendar integration — Nextcloud latest Developer Manual latest documentation

1 Like

I added a revised version of your button to TW-Tweaks (a personal tiddlywiki tweaks).
I also changed the details of event to include the tiddler text!
It has a new icon!

Go to GitHub,
From docs, download index.htmlI will fix the demo page

I made a couple of changes on my version too. The event description will contain a “See tiddler” stable link (works even if tiddler is renamed, as long as the created field remains the same, as discussed here: Is there a way to create a link [permalink] to a tiddler that doesn’t break if the tiddler name changes?) to the tiddler, as well as wikified html of the tiddler’s text.

The enormous filter expression that constructs the event URL is difficult to edit now, as it contains a lot of uri-encoded strings, this is an area for further improvement, if the button should be easy to customize.

Just for information, as it has been pointed out in another thread, the situation where a <button> element contains an interactive element like <a> is against HTML specs. However, this is probably the only way to achieve the desired effect using wikitext without resorting to JS.

My button in TID format:

caption: {{$:/core/images/new-journal-button|1em|G}} add to calendar
description: Add to calendar
tags: $:/tags/ViewToolbar $:/wilk/tweaks/AddToCalendar
title: $:/wilk/buttons/add-to-calendar

\whitespace trim

\procedure .addToCalendarActions()
<$action-sendmessage $message="tm-add-tag" $param="In calendar"/>
\end

<$wikify name="wikifiedText" text={{!!text}} output="html">
<$fieldmangler>
<$button tooltip={{$:/wilk/buttons/add-to-calendar!!description}} class=<<tv-config-toolbar-class>> actions=<<.addToCalendarActions>> >
	<a href={{{
		[[https://calendar.google.com/calendar/r/eventedit]]
		=[[?text=]]
			=[<currentTiddler>encodeuricomponent[]]
		=[[&details=]]
			=[[%3Ca%20href%3D%22]]
			=[{$:/info/url/full}encodeuricomponent[]]
			=[[%23%3A%5Bcreated%5B]]
			=[{!!created}]
			=[[%5D%5D%2520%5Bfield:title%5B]]
			=[<currentTiddler>encodeuricomponent[]encodeuricomponent[]]
			=[[%5D%5D]]
			=[[%22%3ESee%20tiddler%3C%2Fa%3E]]
			=[[%0A%3Chr%3E]]
			=[<wikifiedText>encodeuricomponent[]]
		=[[&dates=]append<now YYYY0MM0DD>append[/]append<now YYYY0MM0DD>]
		+[join[]]
	}}} target="_blank">
		<$list filter="[<tv-config-toolbar-icons>match[yes]]">{{$:/core/images/new-journal-button|1em|G}}</$list>
		<$list filter="[<tv-config-toolbar-text>match[yes]]"><span class=tc-btn-text>Add to calendar</span></$list>
	</a>
</$button>
</$fieldmangler>
</$wikify>

Some screenshots to demonstrate:

image

After clicking the button you get:

1 Like

See this post: How to Control the Generated href via Wikilink - #16 by pmario

@vilc below is a version of your code that avoids the need to nest a link inside a button, and avoids the performance hit of wikify until the button is clicked. I have skipped the implementation of the permalink but that should not be difficult to add by modifying the get.details function.

\whitespace trim

\procedure linkTemplate() $(get.calendar.base.URI)$?text=$(get.encoded.title)$&details=$(get.details)$&dates=$(get.dates)$
\function get.calendar.base.URI() https://calendar.google.com/calendar/u/0/r/eventedit
\function get.encoded.title() [<currentTiddler>encodeuricomponent[]]
\function get.details() [<wikifiedText>encodeuricomponent[]]
\function get.dates() [<now YYYY0MM0DD>addsuffix[/]addsuffix<now YYYY0MM0DD>]
\function get.calendar.link() [<linkTemplate>substitute[]]

\procedure addToCalendarActions()
<$action-listops $tiddler=<<currentTiddler>> $tags="[[In calendar]]"/>
<$wikify name="wikifiedText" text={{!!text}} output="html">
	<$action-sendmessage $message="tm-open-external-window" $param=<<get.calendar.link>> />
</$wikify>
\end addToCalendarActions

<$button tooltip={{$:/wilk/buttons/add-to-calendar!!description}} class=<<tv-config-toolbar-class>> actions=<<addToCalendarActions>> >
	<%if [<tv-config-toolbar-icons>match[yes]] %>
		{{$:/core/images/new-journal-button|1em|G}}
	<%endif%>
	<%if [<tv-config-toolbar-text>match[yes]] %>
		<span class=tc-btn-text>Add to calendar</span>
	<%endif%>
</$button>

3 Likes

This is great, thank you. It didn’t occur to me that in my version the wikification would happen every time the button is displayed.

I have discovered one issue of the current wikification method. The internal links are represented as <a href="#HelloThere">. When manually selecting and copying rendered tiddler, these links are (I assume) converted by the browser to the full form e.g. https://tiddlywiki.com/#HelloThere, and so they work outside of this wiki and point back to it.
When the wikify html output is directly used on a different site, e.g. in Google Calendar, the #HelloThere link gets interpreted by the browser as https://calendar.google.com/calendar/u/0/r#HelloThere, instead of pointing to the wiki it was taken from.

Does anyone have any idea to overcome this, other than running a search replace href="#href="https://url.of.current.wiki/# on the wikify output?

Have a look at https://tiddlywiki.com/#tv-filter-export-link%20Variable

1 Like

Thanks again. Adding

\procedure tv-filter-export-link() [encodeuricomponent[]encodeuricomponent[]addprefix[#]addprefix{$:/info/url/full}]

to the button solves the issue.

Hi Saq,
Can we use here a function instead of macro? This is because the content is filter expression.

So, instead of

\define tv-filter-export-link() [encodeuricomponent[]encodeuricomponent[]addsuffix[.html]]

Use

\function tv-filter-export-link() [encodeuricomponent[]encodeuricomponent[]addsuffix[.html]]

The core interprets tv-filter-export-link as a variable and the value of that variable is then invoked as a filter. As such, a procedure seems most appropriate, and assigning a function may not work correctly.

Thank you for your clarification!

Hey all, sorry for the late contribution, in case this has already been solved, but the following modification to @saqimtiaz’s procedures opens the edit event within the Google Calendar app on android, if it’s installed (or on browser otherwise). It may work on iOS as well, can we get someone to confirm?

\whitespace trim

\procedure linkTemplate() https://www.google.com/calendar/render?action=TEMPLATE&text=$(get.encoded.title)$&details=$(get.details)$&dates=$(get.dates)$
\function get.encoded.title() [<currentTiddler>encodeuricomponent[]]
\function get.details() [<wikifiedText>encodeuricomponent[]]
\function get.dates() [<now [YYYY0MM0DD]>addsuffix[T000000Z/]addsuffix<now [YYYY0MM0DD]>addsuffix[T235959Z]]
\function get.calendar.link() [<linkTemplate>substitute[]]

\procedure addToCalendarActions()
<$action-listops $tiddler=<<currentTiddler>> $tags="[[In calendar]]"/>
<$wikify name="wikifiedText" text={{!!text}} output="html">
	<$action-sendmessage $message="tm-open-external-window" $param=<<get.calendar.link>> />
</$wikify>
\end addToCalendarActions

<$button tooltip={{$:/wilk/buttons/add-to-calendar!!description}} class=<<tv-config-toolbar-class>> actions=<<addToCalendarActions>> >
	<%if [<tv-config-toolbar-icons>match[yes]] %>
		{{$:/core/images/new-journal-button|1em|G}}
	<%endif%>
	<%if [<tv-config-toolbar-text>match[yes]] %>
		<span class=tc-btn-text>Add to calendar</span>
	<%endif%>
</$button>

Thanks for the find, @vilc!

1 Like

And, if you’re a streams user and use it anything like I do, the following modification will, rather, set the title of the calendar event to the text of the currentTiddler and set its details to the contents of its stream-list:

\procedure linkTemplate() https://www.google.com/calendar/render?action=TEMPLATE&text=$(get.encoded.title)$&details=$(get.details)$&dates=$(get.dates)$
\function get.encoded.title() [<thisTiddler>get[text]encodeuricomponent[]]
\function get.dates() [<calendarDate>split[-]join[]addsuffix[/]append<calendarDate>split[-]join[]add[1]]
\function get.calendar.link() [<linkTemplate>substitute[]]
\function get.details() [<combinedText>encodeuricomponent[]]

\procedure addToCalendarActions()
<$action-listops $tiddler=<<thisTiddler>> $tags="[[In calendar]]"/>

<$vars thisTiddler=<<currentTiddler>>>
<$let 
    streamList={{{ [<thisTiddler>get[stream-list]] }}}
    calendarDate={{{ [<thisTiddler>get[calendar]] :else[<now [UTC]YYYY0MM0DD>] }}}
>
    <$set name="combinedText" value={{{ [enlist<streamList>get[text]join[

]] }}}>
        <$action-sendmessage $message="tm-open-external-window" $param=<<get.calendar.link>> />
    </$set>
</$let>
</$vars>
\end

Only problem I’m having is getting the stream-list contents wikified – anybody have any ideas?

Figured it out! Here is the code I’m currently using for the button, which is reflective of my workflow involving the streams plugin

\procedure linkTemplate() https://www.google.com/calendar/render?action=TEMPLATE&text=$(get.encoded.title)$&details=$(get.details)$&dates=$(get.dates)$&allday=true

\function get.encoded.title() [<plainTitle>encodeuricomponent[]]
\function get.dates() [<calendarDate>split[-]join[]addsuffix[/]append<calendarDate>split[-]join[]]
\function get.calendar.link() [<linkTemplate>substitute[]]
\function get.details() [<wikifiedText>encodeuricomponent[]]

\procedure addToCalendarActions()
<$action-listops $tiddler=<<thisTiddler>> $tags="[[In calendar]]"/>

<$vars thisTiddler=<<currentTiddler>>>
<$let 
    streamList={{{ [<thisTiddler>get[stream-list]] }}}
    calendarDate={{{ [<thisTiddler>get[calendar]] :else[<now [UTC]YYYY0MM0DD>] }}}
>
    <$wikify name="plainTitle" text={{{ [<thisTiddler>get[text]] }}} type="text/vnd.tiddlywiki">
        <$wikify name="wikifiedText" text={{{ [enlist<streamList>get[text]join[

]] }}} output="html">
            <$action-sendmessage $message="tm-open-external-window" $param=<<get.calendar.link>> />
        </$wikify>
    </$wikify>
</$let>
</$vars>
\end

It takes the text of the current tiddler as the title (and wikifies it as text/vnd.tiddlywiki" first so that it will remove reference brackets), and uses the text of the stream-list items as the details.

It also will set the date by default to the current date, but if you have a “calendar” value in the tiddler, it will use that date instead (I personally am using this with the datepicker)

image

I interact with this through through view conditions I have set up in the streams-row-body for items tagged “TODO” – the calendar button creates and opens the URI and the arrow opens the datepicker

image


The last problem I’m having is that, on the mobile app, it’s setting the end day as one day prior to the start day. This is pretty minor and doesn’t happen on the browser for some reason - - but would be very interested to figure out why it’s happening and how to resolve it if anyone has any suggestions.

1 Like

I have made a similar button a while ago, AFAIK it work properly on mobile: share

Here’s the wikitext I’m using:

<span title="Click to modify the event"><$macrocall
$name="details" 
label="""
{{$:/img/google agenda|10pt}}
<$let
utc-time="[split[:]join[]addsuffix[00000]]"
utc-date="[split[-]join[]]"
start-time={{!!start-time}}
start-date={{!!start-date}}
end-time={{{[{!!end-time}!is[blank]else<start-time>]}}}
end-date={{{[{!!end-date}!is[blank]else<start-date>]}}}
start={{{[<start-date>subfilter<utc-date>][<start-time>subfilter<utc-time>]+[join[T]]}}}
end={{{[<end-date>subfilter<utc-date>][<end-time>subfilter<utc-time>]+[join[T]]}}}
name={{!!name}}
description={{!!description}}
location={{!!location}}
source={{{[{$:/info/url/full}] [{!!title}format:titlelist[]] +[join[#:]]}}}
href={{{
="https://calendar.google.com/calendar/render?action=TEMPLATE"
="&text="=[<name>encodeuricomponent[]]
="&dates="=[<start>]="/"=[<end>]
="&details="
=[<description>encodeuricomponent[]]
=[[<hr><a href="]encodeuricomponent[]]
=[<source>encodeuricomponent[]]
=[[">🔗 Event page</a>]encodeuricomponent[]]
="&location="=[<location>encodeuricomponent[]]
="&sprop=website:"=[<source>encodeuricomponent[]]
="&sprop=name:"=[{$:/SiteTitle}encodeuricomponent[]]
+[join[]]
}}}
display-date-format="[UTC]DD  mmm YYYY at 0hh:0mm"
display-date={{{
[<start-date>subfilter<utc-date>] 
[<start-time>subfilter<utc-time>]
+[join[]format:date<display-date-format>lowercase[]] 
}}}
>
<a href=<<href>> >{{!!name}}, <<display-date>></a>
</$let>
<$list filter="[{!!description}!is[blank]]" variable="ignore">: {{!!description}}</$list>
"""
src="""
<p style="display:flex;justify-content:space-between;list-style:none;">
<span>Start:
<$edit-text type="date" field="start-date"/>
<$edit-text type="time"  field="start-time"/>
</span>
<span>End:
<$edit-text type="date" field="end-date" default={{!!start-date}}/>
<$edit-text type="time"  field="end-time" default={{!!start-time}}/>
</span>
</p>
<$edit field="name" placeholder="Name of the event" class="tc-edit-texteditor tc-edit-texteditor-body"/>
<$edit field="location" placeholder="Location" class="tc-edit-texteditor tc-edit-texteditor-body"/>
<<editor field:"description"  placeholder:"Description" tag:"textarea">>
"""
srcClass="alert border-secondary py-0" labelClass="badge badge-light"
/>

Why did you delete, @telumire? I find your agenda code very cool, I’m deep inside another project currently, but am enthusiastic about checking it out more tomorrow. It looks like it’s working very well :slight_smile: