Skip to content

Instantly share code, notes, and snippets.

@ewalk153
Last active September 23, 2021 01:29
Show Gist options
  • Select an option

  • Save ewalk153/2e2cb914c76b4dd1e66015f6d4ea2e26 to your computer and use it in GitHub Desktop.

Select an option

Save ewalk153/2e2cb914c76b4dd1e66015f6d4ea2e26 to your computer and use it in GitHub Desktop.
Add to calendar example with stimulus
<html>
<head>
<script src="https://unpkg.com/stimulus/dist/stimulus.umd.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<link
href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"
rel="stylesheet"
/>
<script>
class GcalLinkBuilder {
// TODO convert this to take in date objects instead of strings
constructor(
title,
location,
details,
startDate,
endDate,
isAllDay,
crm,
hasTimeZone
) {
this.title = title;
this.location = location;
this.details = details;
this.startDate = startDate;
this.endDate = endDate;
this.isAllDay = isAllDay;
this.crm = crm;
this.hasTimeZone = hasTimeZone;
}
// https://github.com/InteractionDesignFoundation/add-event-to-calendar-docs/blob/main/services/google.md
url() {
return `https://www.google.com/calendar/render?action=TEMPLATE&crm=${this.crm}&text=${this.title}&location=${this.location}&dates=${this.startDate}/${this.endDate}&details=${this.details}&sf=true&output=xml`;
}
}
(() => {
const application = Stimulus.Application.start();
application.register(
"toggle",
class extends Stimulus.Controller {
elementToggle(element) {
if (element.hasAttribute("hidden")) {
element.removeAttribute("hidden");
} else {
element.setAttribute("hidden", "");
}
}
toggle(event) {
event.preventDefault();
const TARGETS =
event.currentTarget.dataset.toggleTarget.split(",");
TARGETS.forEach((target) =>
document
.querySelectorAll(`[data-toggle-name="${target}"]`)
.forEach((target) => this.elementToggle(target))
);
}
}
);
application.register(
"gcal",
class extends Stimulus.Controller {
static get targets() {
return [
"output",
"title",
"location",
"startdate",
"starttime",
"enddate",
"endtime",
"description",
"timezone",
"allday",
];
}
initialize() {
this.defaultDates();
}
pad(n, width, z) {
z = z || "0";
n = n + "";
return n.length >= width
? n
: new Array(width - n.length + 1).join(z) + n;
}
linkURL() {
return new GcalLinkBuilder(
this.title(),
this.location(),
this.details(),
this.startDate(),
this.endDate(),
null,
"BUSY",
null
).url();
// return `https://www.google.com/calendar/render?action=TEMPLATE&crm=BUSY&text=${this.title()}&location=${this.location()}&dates=${this.startDate()}/${this.endDate()}&details=${this.details()}&sf=true&output=xml`;
}
// TODO replace date parsing with momentjs
defaultDates() {
const date = new Date();
const dateString = `${date.getFullYear()}-${this.pad(
date.getMonth() + 1,
2,
"0"
)}-${this.pad(date.getDate(), 2, "0")}`;
this.startdateTarget.value = dateString;
this.enddateTarget.value = dateString;
this.starttimeTarget.value = "12:00";
this.endtimeTarget.value = "13:00";
}
isAllDay() {
return this.alldayTarget.checked;
}
title() {
return encodeURIComponent(this.titleTarget.value);
}
location() {
return encodeURIComponent(this.locationTarget.value);
}
timezone() {
return this.timezoneTarget.value;
}
details() {
return encodeURIComponent(this.descriptionTarget.value);
}
// TODO replace date formatting with momentjs
buildDatetimeString(dateField, timeField, timezoneField) {
return encodeURIComponent(
`${dateField.replaceAll("-", "")}T${timeField.replaceAll(
":",
""
)}00`
);
}
// TODO replace date formatting with momentjs
buildDateString(dateField) {
return encodeURIComponent(`${dateField.replaceAll("-", "")}`);
}
// TODO replace date formatting with momentjs
buildEndDateString(dateField) {
const val = parseInt(dateField.replaceAll("-", ""), 10);
return encodeURIComponent(`${val + 1}`);
}
startDate() {
if (this.isAllDay()) {
return this.buildDateString(this.startdateTarget.value);
}
return this.buildDatetimeString(
this.startdateTarget.value,
this.starttimeTarget.value,
this.timezoneTarget.value
);
}
endDate() {
if (this.isAllDay()) {
return this.buildEndDateString(this.enddateTarget.value);
}
return this.buildDatetimeString(
this.enddateTarget.value,
this.endtimeTarget.value,
this.timezoneTarget.value
);
}
link(event) {
event.preventDefault();
this.outputTarget.value = this.linkURL();
this.outputTarget.select();
document.execCommand("copy");
}
}
);
})();
</script>
</head>
<body
class="
rounded-t-lg
overflow-hidden
border-t border-l border-r border-gray-400
px-3
py-10
bg-gray-200
flex
justify-center
"
>
<div data-controller="gcal" class="w-full max-w-lg">
<form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<h1
class="
text-2xl
font-bold
leading-7
text-gray-900
"
>
Sharable Google Cal Link Builder
</h1>
<div class="mb-4">
<label class="block text-gray-700 text-sm font-bold mb-2" for="title">
Title
</label>
<input
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
id="title"
type="text"
name="title"
data-gcal-target="title"
/>
</div>
<div class="mb-4">
<label
class="block text-gray-700 text-sm font-bold mb-2"
for="location"
>
Location
</label>
<input
id="location"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
type="text"
name="location"
data-gcal-target="location"
/>
</div>
<span data-controller="toggle">
<input
type="checkbox"
data-action="toggle#toggle"
data-toggle-target="starttimeblock,endtimeblock,timezone"
name="allday"
id="allday"
value="1"
data-gcal-target="allday"
/>
<label for="allday" class="text-gray-700 text-sm font-bold mb-2"
>all day?</label
>
<br />
<span data-toggle-name="timezone">
<div class="mb-4">
<label
class="block text-gray-700 text-sm font-bold mb-2"
for="timezone"
>
Timezone
</label>
<input
type="text"
name="timezone"
id="timezone"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
data-gcal-target="timezone"
value=""
/>
(leave blank to exclude timezone)
</div>
</span>
<div class="mb-4">
<label
class="block text-gray-700 text-sm font-bold mb-2"
for="startdate"
>
Start Date
</label>
<input
type="date"
id="startdate"
name="startdate"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
data-gcal-target="startdate"
/>
<span data-toggle-name="starttimeblock">
<input
type="time"
name="starttime"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
data-gcal-target="starttime"
/></span>
</div>
<div class="mb-4">
<label
class="block text-gray-700 text-sm font-bold mb-2"
for="enddate"
>
End Date
</label>
<input
type="date"
id="enddate"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
name="enddate"
data-gcal-target="enddate"
/>
<span data-toggle-name="endtimeblock">
<input
type="time"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
name="endtime"
data-gcal-target="endtime"
/></span>
</div>
</span>
<div class="mb-4">
<label
class="block text-gray-700 text-sm font-bold mb-2"
for="description"
>
Description
</label>
<textarea
id="description"
class="
shadow
appearance-none
border
w-full
px-3
py-2
text-gray-700
border
rounded
focus:outline-none
"
name="description"
data-gcal-target="description"
></textarea>
</div>
<br />
<button
class="
bg-blue-500
hover:bg-blue-700
text-white
font-bold
py-2
px-4
rounded
focus:outline-none focus:shadow-outline
"
data-action="click->gcal#link"
>
Generate Link
</button>
<br /><br />
<label class="block text-gray-700 text-sm font-bold mb-2" for="output">
Share this link
</label>
<input
id="output"
data-gcal-target="output"
class="
shadow
appearance-none
border
rounded
w-full
py-2
px-3
text-gray-700
leading-tight
focus:outline-none focus:shadow-outline
"
/>
</form>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment