add-to-calendar-button
Advanced tools
Comparing version 1.9.0 to 1.9.1
@@ -7,3 +7,8 @@ { | ||
}, | ||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:security/recommended", | ||
"prettier" | ||
], | ||
"parser": "@typescript-eslint/parser", | ||
@@ -25,4 +30,4 @@ "parserOptions": { | ||
"plugins": ["@typescript-eslint"], | ||
"ignorePatterns": ["*.min.*", "Gruntfile.js", "set-release.js"], | ||
"ignorePatterns": ["*.min.*", "Gruntfile.js", "set-release.js", "npm_dist/"], | ||
"rules": {} | ||
} |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
const atcbVersion = "1.9.0"; | ||
const atcbVersion = "1.9.1"; | ||
/* Creator: Jens Kuerschner (https://jenskuerschner.de) | ||
@@ -35,3 +35,3 @@ * Project: https://github.com/jekuer/add-to-calendar-button | ||
// skip already initialized ones | ||
if (atcButtons[i].classList.contains("atcb_initialized")) { | ||
if (atcButtons[parseInt(i)].classList.contains("atcb_initialized")) { | ||
continue; | ||
@@ -41,9 +41,10 @@ } | ||
// check if schema.org markup is present | ||
const schema = atcButtons[i].querySelector("script"); | ||
const schema = atcButtons[parseInt(i)].querySelector("script"); | ||
// get their JSON content first | ||
if (schema && schema.innerHTML) { | ||
// get schema.org event markup and flatten the event block | ||
// get schema.org event markup and flatten the event block, plus | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
schema.innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
); | ||
atcbConfig = atcb_parse_schema_json(atcbConfig); | ||
@@ -53,6 +54,7 @@ // set flag to not delete HTML content later | ||
} else { | ||
// get JSON from HTML block | ||
// get JSON from HTML block, but | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
atcButtons[i].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcButtons[parseInt(i)].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); | ||
// set flag to delete HTML content later | ||
@@ -70,3 +72,3 @@ atcbConfig.deleteJSON = true; | ||
// ... and generate the button on success | ||
atcb_generate(atcButtons[i], i + atcButtonsInitialized.length, atcbConfig); | ||
atcb_generate(atcButtons[parseInt(i)], i + atcButtonsInitialized.length, atcbConfig); | ||
} | ||
@@ -84,3 +86,3 @@ } | ||
if (key.charAt(0) !== "@") { | ||
atcbConfig[key] = atcbConfig.event[key]; | ||
atcbConfig[`${key}`] = atcbConfig.event[`${key}`]; | ||
} | ||
@@ -108,4 +110,4 @@ }); | ||
Object.keys(keyChanges).forEach((key) => { | ||
if (atcbConfig[keyChanges[key]] == null && atcbConfig[key] != null) { | ||
atcbConfig[keyChanges[key]] = atcbConfig[key]; | ||
if (atcbConfig[keyChanges[`${key}`]] == null && atcbConfig[`${key}`] != null) { | ||
atcbConfig[keyChanges[`${key}`]] = atcbConfig[`${key}`]; | ||
} | ||
@@ -125,3 +127,3 @@ }); | ||
// if no description or already decorated, return early | ||
if (!atcbConfig.description || atcbConfig.description_iCal) return atcbConfig; | ||
if (!atcbConfig.description || atcbConfig.descriptionHtmlFree) return atcbConfig; | ||
@@ -132,8 +134,6 @@ // make a copy of the given argument rather than mutating in place | ||
data.description = data.description.replace(/<br\s*\/?>/gi, "\n"); | ||
data.description_iCal = data.description.replace(/\[url\]/g, "").replace(/\[\/url\]/g, ""); | ||
data.description = decodeURIComponent( | ||
data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/g, | ||
encodeURIComponent('<a href="$1" target="_blank" rel="noopener">$1</a>') | ||
) | ||
data.descriptionHtmlFree = data.description.replace(/\[url\]/gi, "").replace(/\[\/url\]/gi, ""); | ||
data.description = data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/gi, | ||
'<a href="$1" target="_blank" rel="noopener">$1</a>' | ||
); | ||
@@ -153,3 +153,3 @@ return data; | ||
return requiredField.every(function (field) { | ||
if (data[field] == null || data[field] == "") { | ||
if (data[`${field}`] == null || data[`${field}`] == "") { | ||
console.error("add-to-calendar button generation failed: required setting missing [" + field + "]"); | ||
@@ -233,14 +233,14 @@ return false; | ||
!dates.every(function (date) { | ||
if (data[date].length !== 10) { | ||
if (data[`${date}`].length !== 10) { | ||
console.error("add-to-calendar button generation failed: date misspelled [-> YYYY-MM-DD]"); | ||
return false; | ||
} | ||
const dateParts = data[date].split("-"); | ||
const dateParts = data[`${date}`].split("-"); | ||
if (dateParts.length < 3 || dateParts.length > 3) { | ||
console.error( | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[date] + "]" | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[`${date}`] + "]" | ||
); | ||
return false; | ||
} | ||
newDate[date] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
newDate[`${date}`] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
return true; | ||
@@ -255,12 +255,16 @@ }) | ||
!times.every(function (time) { | ||
if (data[time] != null) { | ||
if (data[time].length !== 5) { | ||
if (data[`${time}`] != null) { | ||
if (data[`${time}`].length !== 5) { | ||
console.error("add-to-calendar button generation failed: time misspelled [-> HH:MM]"); | ||
return false; | ||
} | ||
const timeParts = data[time].split(":"); | ||
const timeParts = data[`${time}`].split(":"); | ||
// validate the time parts | ||
if (timeParts.length < 2 || timeParts.length > 2) { | ||
console.error( | ||
"add-to-calendar button generation failed: time misspelled [" + time + ": " + data[time] + "]" | ||
"add-to-calendar button generation failed: time misspelled [" + | ||
time + | ||
": " + | ||
data[`${time}`] + | ||
"]" | ||
); | ||
@@ -550,3 +554,3 @@ return false; | ||
// give keyboard focus to first item in list, if not blocked, because there is definitely no keyboard trigger. | ||
// Mintd that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
// Mind that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
if (keyboardTrigger) { | ||
@@ -600,2 +604,6 @@ list.firstChild.focus(); | ||
} | ||
let tmpDataDescription = ""; | ||
if (data.description != null && data.description != "") { | ||
tmpDataDescription = data.description; | ||
} | ||
if (data.location != null && data.location != "") { | ||
@@ -606,14 +614,16 @@ url += "&location=" + encodeURIComponent(data.location); | ||
// workaround to cover a bug, where, when using Google Calendar on an iPhone, the location is not recognized. So, for the moment, we simply add it to the description. | ||
if (data.description == null || data.description == "") { | ||
data.description = ""; | ||
} else { | ||
data.description += "%0A%0A"; | ||
if (tmpDataDescription != "") { | ||
tmpDataDescription += "<br><br>"; | ||
} | ||
data.description += "📍: " + data.location; | ||
tmpDataDescription += "📍: " + data.location; | ||
} | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&details=" + encodeURIComponent(data.description); | ||
if (tmpDataDescription != "") { | ||
url += "&details=" + encodeURIComponent(tmpDataDescription); | ||
} | ||
window.open(url, "_blank").focus(); | ||
tmpDataDescription += "hhh"; | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -638,6 +648,10 @@ | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&desc=" + encodeURIComponent(data.description); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Yahoo does not support html tags in a stable way | ||
url += "&desc=" + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -669,5 +683,8 @@ | ||
if (data.description != null && data.description != "") { | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "%0A")); | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "<br>")); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -694,7 +711,10 @@ | ||
} | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
// using description_iCal instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.description_iCal); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -723,5 +743,6 @@ | ||
); | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
ics_lines.push( | ||
"DESCRIPTION:" + data.description_iCal.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
"DESCRIPTION:" + | ||
data.descriptionHtmlFree.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
); | ||
@@ -753,2 +774,3 @@ } | ||
else if (!!window.ActiveXObject && document.execCommand) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
const _window = window.open(dlurl, "_blank"); | ||
@@ -842,2 +864,11 @@ _window.document.close(); | ||
function atcb_secure_url(url) { | ||
if (url.match(/((\.\.\/)|(\.\.\\)|(%2e%2e%2f)|(%252e%252e%252f)|(%2e%2e\/)|(%252e%252e\/)|(\.\.%2f)|(\.\.%252f)|(%2e%2e%5c)|(%252e%252e%255c)|(%2e%2e\\)|(%252e%252e\\)|(\.\.%5c)|(\.\.%255c)|(\.\.%c0%af)|(\.\.%25c0%25af)|(\.\.%c1%9c)|(\.\.%25c1%259c))/gi)) { | ||
console.error("Seems like the generated URL includes at least one security issue and got blocked. Please check the calendar button parameters!"); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
} | ||
if (isBrowser()) { | ||
@@ -844,0 +875,0 @@ // Global listener to ESC key to close dropdown |
@@ -1,2 +0,2 @@ | ||
const atcbVersion="1.9.0",isBrowser=new Function("try { return this===window; }catch(e){ return false; }"),isiOS=isBrowser()?new Function("if ((/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)){ return true; }else{ return false; }"):new Function("return false;");function atcb_init(){console.log("add-to-calendar button initialized (version "+atcbVersion+")"),console.log("See https://github.com/jekuer/add-to-calendar-button for details");const a=document.querySelectorAll(".atcb");if(0<a.length){var n=document.querySelectorAll(".atcb_initialized");for(let t=0;t<a.length;t++)if(!a[t].classList.contains("atcb_initialized")){let e;const c=a[t].querySelector("script");c&&c.innerHTML?(e=JSON.parse(c.innerHTML.replace(/(\r\n|\n|\r)/g,"").replace(/(<(?!br)([^>]+)>)/gi,"")),e=atcb_parse_schema_json(e),e.deleteJSON=!1):(e=JSON.parse(a[t].innerHTML.replace(/(\r\n|\n|\r)/g,"").replace(/(<(?!br)([^>]+)>)/gi,"")),e.deleteJSON=!0),e=atcb_patch_config(e),atcb_check_required(e)&&(e=atcb_decorate_data(e),atcb_validate(e)&&atcb_generate(a[t],t+n.length,e))}}}function atcb_parse_schema_json(t){try{Object.keys(t.event).forEach(e=>{"@"!==e.charAt(0)&&(t[e]=t.event[e])}),delete t.event}catch(e){console.error("add-to-calendar button problem: it seems like you use the schema.org style, but did not define it properly")}return t}function atcb_patch_config(t){const a={title:"name",dateStart:"startDate",dateEnd:"endDate",timeStart:"startTime",timeEnd:"endTime"};return Object.keys(a).forEach(e=>{null==t[a[e]]&&null!=t[e]&&(t[a[e]]=t[e])}),t}function atcb_decorate_data(e){if((e=atcb_date_cleanup(e)).startDate=atcb_date_calculation(e.startDate),e.endDate=atcb_date_calculation(e.endDate),!e.description||e.description_iCal)return e;const t=Object.assign({},e);return t.description=t.description.replace(/<br\s*\/?>/gi,"\n"),t.description_iCal=t.description.replace(/\[url\]/g,"").replace(/\[\/url\]/g,""),t.description=decodeURIComponent(t.description.replace(/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/g,encodeURIComponent('<a href="$1" target="_blank" rel="noopener">$1</a>'))),t}function atcb_check_required(t){if(null==t.options||t.options.length<1)return console.error("add-to-calendar button generation failed: no options set"),!1;return["name","startDate","endDate"].every(function(e){return null!=t[e]&&""!=t[e]||(console.error("add-to-calendar button generation failed: required setting missing ["+e+"]"),!1)})}function atcb_date_cleanup(n){return["start","end"].forEach(function(e){var t;if(null!=n[e+"Date"]&&(n[e+"Date"]=n[e+"Date"].replace(/\.\d{3}/,"").replace("Z",""),null!=(t=n[e+"Date"].split("T"))[1]&&(n[e+"Date"]=t[0],n[e+"Time"]=t[1])),null!=n[e+"Time"]&&8===n[e+"Time"].length){const a=n[e+"Time"];n[e+"Time"]=a.substring(0,a.length-3)}}),n}function atcb_date_calculation(e){const t=new Date;var a=t.getUTCMonth()+1+"-"+t.getUTCDate()+"-"+t.getUTCFullYear();const n=(e=e.replace(/today/gi,a)).split("+");a=n[0].split("-");let c=new Date(a[0],a[1]-1,a[2]);return a[0].length<4&&(c=new Date(a[2],a[0]-1,a[1])),null!=n[1]&&0<n[1]&&c.setDate(c.getDate()+parseInt(n[1])),c.getFullYear()+"-"+(c.getMonth()+1<10?"0":"")+(c.getMonth()+1)+"-"+(c.getDate()<10?"0":"")+c.getDate()}function atcb_validate(a){const t=["Apple","Google","iCal","Microsoft365","Outlook.com","MicrosoftTeams","Yahoo"];if(!a.options.every(function(e){e=e.split("|");return!!t.includes(e[0])||(console.error("add-to-calendar button generation failed: invalid option ["+e[0]+"]"),!1)}))return!1;const e=["startDate","endDate"],n=e;if(!e.every(function(e){if(10!==a[e].length)return console.error("add-to-calendar button generation failed: date misspelled [-> YYYY-MM-DD]"),!1;var t=a[e].split("-");return t.length<3||3<t.length?(console.error("add-to-calendar button generation failed: date misspelled ["+e+": "+a[e]+"]"),!1):(n[e]=new Date(t[0],t[1]-1,t[2]),!0)}))return!1;return!!["startTime","endTime"].every(function(e){if(null!=a[e]){if(5!==a[e].length)return console.error("add-to-calendar button generation failed: time misspelled [-> HH:MM]"),!1;var t=a[e].split(":");if(t.length<2||2<t.length)return console.error("add-to-calendar button generation failed: time misspelled ["+e+": "+a[e]+"]"),!1;if(23<t[0])return console.error("add-to-calendar button generation failed: time misspelled - hours number too high ["+e+": "+t[0]+"]"),!1;if(59<t[1])return console.error("add-to-calendar button generation failed: time misspelled - minutes number too high ["+e+": "+t[1]+"]"),!1;"startTime"==e&&(n.startDate=new Date(n.startDate.getTime()+36e5*t[0]+6e4*t[1])),"endTime"==e&&(n.endDate=new Date(n.endDate.getTime()+36e5*t[0]+6e4*t[1]))}return!0})&&(null!=a.startTime&&null==a.endTime||null==a.startTime&&null!=a.endTime?(console.error("add-to-calendar button generation failed: if you set a starting time, you also need to define an end time"),!1):!(n.endDate<n.startDate)||(console.error("add-to-calendar button generation failed: end date before start date"),!1))}function atcb_generate_label(e,t=!1,a){if(t){const n=document.createElement("span");n.classList.add("atcb_icon"),e.appendChild(n)}if(""!=a){const c=document.createElement("span");c.classList.add("atcb_text"),c.textContent=a,e.appendChild(c)}}function atcb_generate(e,t,a){a.deleteJSON&&(e.innerHTML="");const n=document.createElement("div"),c=(n.classList.add("atcb_button_wrapper"),e.appendChild(n),document.createElement("button"));c.id="atcb_button_"+t,c.classList.add("atcb_button"),c.setAttribute("type","button"),n.appendChild(c),atcb_generate_label(c,!0,a.label||"Add to Calendar"),c.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M81.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zm-3.65 76.03c1.83 0 3.32 1.49 3.32 3.32s-1.49 3.32-3.32 3.32l-12.95-.04-.04 12.93c0 1.83-1.49 3.32-3.32 3.32s-3.32-1.49-3.32-3.32l.04-12.94-12.93-.05c-1.83 0-3.32-1.49-3.32-3.32s1.49-3.32 3.32-3.32l12.94.04.04-12.93c0-1.83 1.49-3.32 3.32-3.32s3.32 1.49 3.32 3.32l-.04 12.95 12.94.04h0zM29.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zM6.4 45.32h110.08V21.47c0-.8-.33-1.53-.86-2.07-.53-.53-1.26-.86-2.07-.86H103c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h10.55c2.57 0 4.9 1.05 6.59 2.74s2.74 4.02 2.74 6.59v27.06 65.03c0 2.57-1.05 4.9-2.74 6.59s-4.02 2.74-6.59 2.74H9.33c-2.57 0-4.9-1.05-6.59-2.74-1.69-1.7-2.74-4.03-2.74-6.6V48.53 21.47c0-2.57 1.05-4.9 2.74-6.59s4.02-2.74 6.59-2.74H20.6c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H9.33c-.8 0-1.53.33-2.07.86-.53.53-.86 1.26-.86 2.07v23.85h0zm110.08 6.41H6.4v61.82c0 .8.33 1.53.86 2.07.53.53 1.26.86 2.07.86h104.22c.8 0 1.53-.33 2.07-.86.53-.53.86-1.26.86-2.07V51.73h0zM50.43 18.54c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h21.49c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H50.43h0z"/></svg>',"click"==a.trigger?c.addEventListener("mousedown",()=>atcb_toggle(a,c,!1,!0)):(c.addEventListener("touchstart",()=>atcb_toggle(a,c,!1,!0),{passive:!0}),c.addEventListener("mouseenter",()=>atcb_open(a,c,!1,!0))),c.addEventListener("keydown",function(e){"Enter"==e.key&&atcb_toggle(a,c,!0,!0)}),e.classList.remove("atcb"),e.classList.add("atcb_initialized"),a.inline?e.style.display="inline-block":e.style.display="block",console.log("add-to-calendar button #"+(t+1)+" created")}function atcb_generate_dropdown_list(n){const c=document.createElement("div");return c.classList.add("atcb_list"),n.options.forEach(function(e){var t=e.split("|");const a=document.createElement("div");switch(a.classList.add("atcb_list_item"),a.tabIndex=0,c.appendChild(a),t[0]){case"Apple":atcb_generate_label(a,!0,t[1]||"Apple"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" viewBox="0 0 640 640"><path d="M494.782 340.02c-.803-81.025 66.084-119.907 69.072-121.832-37.595-54.993-96.167-62.552-117.037-63.402-49.843-5.032-97.242 29.362-122.565 29.362-25.253 0-64.277-28.607-105.604-27.85-54.32.803-104.4 31.594-132.403 80.245C29.81 334.457 71.81 479.58 126.816 558.976c26.87 38.882 58.914 82.56 100.997 81 40.512-1.594 55.843-26.244 104.848-26.244 48.993 0 62.753 26.245 105.64 25.406 43.606-.803 71.232-39.638 97.925-78.65 30.887-45.12 43.548-88.75 44.316-90.994-.969-.437-85.029-32.634-85.879-129.439l.118-.035zM414.23 102.178C436.553 75.095 451.636 37.5 447.514-.024c-32.162 1.311-71.163 21.437-94.253 48.485-20.729 24.012-38.836 62.28-33.993 99.036 35.918 2.8 72.591-18.248 94.926-45.272l.036-.047z"/></svg>',a.addEventListener("click",function(){atcb_generate_ical(n),atcb_close()});break;case"Google":atcb_generate_label(a,!0,t[1]||"Google"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M93.78 29.1H29.1v64.68h64.68V29.1z" fill="#fff"/><path d="M93.78 122.88l29.1-29.1h-29.1v29.1z" fill="#f72a25"/><path d="M122.88 29.1h-29.1v64.68h29.1V29.1z" fill="#fbbc04"/><path d="M93.78 93.78H29.1v29.1h64.68v-29.1z" fill="#34a853"/><path d="M0 93.78v19.4c0 5.36 4.34 9.7 9.7 9.7h19.4v-29.1H0h0z" fill="#188038"/><path d="M122.88 29.1V9.7c0-5.36-4.34-9.7-9.7-9.7h-19.4v29.1h29.1 0z" fill="#1967d2"/><path d="M93.78 0H9.7C4.34 0 0 4.34 0 9.7v84.08h29.1V29.1h64.67V0h.01z" fill="#4285f4"/><path d="M42.37 79.27c-2.42-1.63-4.09-4.02-5-7.17l5.61-2.31c.51 1.94 1.4 3.44 2.67 4.51 1.26 1.07 2.8 1.59 4.59 1.59 1.84 0 3.41-.56 4.73-1.67 1.32-1.12 1.98-2.54 1.98-4.26 0-1.76-.7-3.2-2.09-4.32s-3.14-1.67-5.22-1.67H46.4v-5.55h2.91c1.79 0 3.31-.48 4.54-1.46 1.23-.97 1.84-2.3 1.84-3.99 0-1.5-.55-2.7-1.65-3.6s-2.49-1.35-4.18-1.35c-1.65 0-2.96.44-3.93 1.32s-1.7 2-2.12 3.24l-5.55-2.31c.74-2.09 2.09-3.93 4.07-5.52s4.51-2.39 7.58-2.39c2.27 0 4.32.44 6.13 1.32s3.23 2.1 4.26 3.65c1.03 1.56 1.54 3.31 1.54 5.25 0 1.98-.48 3.65-1.43 5.03-.95 1.37-2.13 2.43-3.52 3.16v.33c1.79.74 3.36 1.96 4.51 3.52 1.17 1.58 1.76 3.46 1.76 5.66s-.56 4.16-1.67 5.88c-1.12 1.72-2.66 3.08-4.62 4.07s-4.17 1.49-6.62 1.49c-2.84 0-5.46-.81-7.88-2.45h0 0zm34.46-27.84l-6.16 4.45-3.08-4.67 11.05-7.97h4.24v37.6h-6.05V51.43h0z" fill="#1a73e8"/></svg>',a.addEventListener("click",function(){atcb_generate_google(n),atcb_close()});break;case"iCal":atcb_generate_label(a,!0,t[1]||"iCal File"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M81.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zm-15.5 99.08c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zM15.85 67.09c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zm25.14 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H91.25h0zm-75.4 18.36c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zm25.14 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H91.25h0zm-75.4 18.36c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zM29.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zM6.4 45.32h110.07V21.47c0-.8-.33-1.53-.86-2.07-.53-.53-1.26-.86-2.07-.86H103c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h10.55c2.57 0 4.9 1.05 6.59 2.74s2.74 4.02 2.74 6.59v27.06 65.03c0 2.57-1.05 4.9-2.74 6.59s-4.02 2.74-6.59 2.74H9.33c-2.57 0-4.9-1.05-6.59-2.74-1.69-1.7-2.74-4.03-2.74-6.6V48.52 21.47c0-2.57 1.05-4.9 2.74-6.59s4.02-2.74 6.59-2.74H20.6c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H9.33c-.8 0-1.53.33-2.07.86-.53.53-.86 1.26-.86 2.07v23.85h0zm110.08 6.41H6.4v61.82c0 .8.33 1.53.86 2.07.53.53 1.26.86 2.07.86h104.22c.8 0 1.53-.33 2.07-.86.53-.53.86-1.26.86-2.07V51.73h0zM50.43 18.54c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h21.49c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H50.43h0z"/></svg>',a.addEventListener("click",function(){atcb_generate_ical(n),atcb_close()});break;case"MicrosoftTeams":atcb_generate_label(a,!0,t[1]||"Microsoft Teams"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 2228.833 2073.333"><g fill="#5059c9"><path d="M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h0-1.711c-199.901.028-361.975-162-362.004-361.901v-.052-571.409c.001-28.427 23.045-51.471 51.471-51.471h0z"/><circle cx="1943.75" cy="440.583" r="233.25"/></g><g fill="#7b83eb"><circle cx="1218.083" cy="336.917" r="336.917"/><path d="M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"/></g><path opacity=".1" d="M1244 777.5v838.145c-.258 38.435-23.549 72.964-59.09 87.598-11.316 4.787-23.478 7.254-35.765 7.257H667.613c-6.738-17.105-12.958-34.21-18.142-51.833-18.144-59.477-27.402-121.307-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52H1244z"/><path opacity=".2" d="M1192.167 777.5v889.978a91.84 91.84 0 0 1-7.257 35.765c-14.634 35.541-49.163 58.833-87.598 59.09H691.975c-8.812-17.105-17.105-34.21-24.362-51.833s-12.958-34.21-18.142-51.833a631.28 631.28 0 0 1-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.313z"/><path opacity=".2" d="M1192.167 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855h-447.84A631.28 631.28 0 0 1 622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.312z"/><path opacity=".2" d="M1140.333 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855H649.472A631.28 631.28 0 0 1 622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h423.478z"/><path opacity=".1" d="M1244 509.522v163.275c-8.812.518-17.105 1.037-25.917 1.037s-17.105-.518-25.917-1.037c-17.496-1.161-34.848-3.937-51.833-8.293a336.92 336.92 0 0 1-233.25-198.003 288.02 288.02 0 0 1-16.587-51.833h258.648c52.305.198 94.657 42.549 94.856 94.854z"/><use xlink:href="#C" opacity=".2"/><use xlink:href="#C" opacity=".2"/><path opacity=".2" d="M1140.333 561.355v103.148A336.92 336.92 0 0 1 907.083 466.5h138.395c52.305.199 94.656 42.551 94.855 94.855z"/><linearGradient id="A" gradientUnits="userSpaceOnUse" x1="198.099" y1="392.261" x2="942.234" y2="1681.073"><stop offset="0" stop-color="#5a62c3"/><stop offset=".5" stop-color="#4d55bd"/><stop offset="1" stop-color="#3940ab"/></linearGradient><path fill="url(#A)" d="M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"/><path fill="#fff" d="M820.211,828.193H630.241v517.297H509.211V828.193H320.123V727.844h500.088V828.193z"/><defs ><path id="C" d="M1192.167 561.355v111.442c-17.496-1.161-34.848-3.937-51.833-8.293a336.92 336.92 0 0 1-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"/></defs></svg>',a.addEventListener("click",function(){atcb_generate_teams(n),atcb_close()});break;case"Microsoft365":atcb_generate_label(a,!0,t[1]||"Microsoft 365"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 278050 333334" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd"><path fill="#ea3e23" d="M278050 305556l-29-16V28627L178807 0 448 66971l-448 87 22 200227 60865-23821V80555l117920-28193-17 239519L122 267285l178668 65976v73l99231-27462v-316z"/></svg>',a.addEventListener("click",function(){atcb_generate_microsoft(n,"365"),atcb_close()});break;case"Outlook.com":atcb_generate_label(a,!0,t[1]||"Outlook.com"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.129793726981 0 33.251996719421 32" width="2500" height="2397"><path d="M28.596 2H11.404A1.404 1.404 0 0 0 10 3.404V5l9.69 3L30 5V3.404A1.404 1.404 0 0 0 28.596 2z" fill="#0364b8"/><path d="M31.65 17.405A11.341 11.341 0 0 0 32 16a.666.666 0 0 0-.333-.576l-.013-.008-.004-.002L20.812 9.24a1.499 1.499 0 0 0-1.479-.083 1.49 1.49 0 0 0-.145.082L8.35 15.415l-.004.002-.012.007A.666.666 0 0 0 8 16a11.344 11.344 0 0 0 .35 1.405l11.492 8.405z" fill="#0a2767"/><path d="M24 5h-7l-2.021 3L17 11l7 6h6v-6z" fill="#28a8ea"/><path d="M10 5h7v6h-7z" fill="#0078d4"/><path d="M24 5h6v6h-6z" fill="#50d9ff"/><path d="M24 17l-7-6h-7v6l7 6 10.832 1.768z" fill="#0364b8"/><path d="M17 11h7v6h-7z" fill="#0078d4"/><path d="M10 17h7v6h-7z" fill="#064a8c"/><path d="M24 17h6v6h-6z" fill="#0078d4"/><path d="M20.19 25.218l-11.793-8.6.495-.87 10.909 6.212a.528.528 0 0 0 .42-.012l10.933-6.23.496.869z" fill="#0a2767" opacity=".5"/><path d="M31.667 16.577l-.014.008-.003.002-10.838 6.174a1.497 1.497 0 0 1-1.46.091l3.774 5.061 8.254 1.797v.004A1.498 1.498 0 0 0 32 28.5V16a.666.666 0 0 1-.333.577z" fill="#1490df"/><path d="M32 28.5v-.738l-9.983-5.688-1.205.687a1.497 1.497 0 0 1-1.46.091l3.774 5.061 8.254 1.797v.004A1.498 1.498 0 0 0 32 28.5z" opacity=".05"/><path d="M31.95 28.883L21.007 22.65l-.195.11a1.497 1.497 0 0 1-1.46.092l3.774 5.061 8.254 1.797v.004a1.501 1.501 0 0 0 .57-.83z" opacity=".1"/><path d="M8.35 16.59v-.01h-.01l-.03-.02A.65.65 0 0 1 8 16v12.5A1.498 1.498 0 0 0 9.5 30h21a1.503 1.503 0 0 0 .37-.05.637.637 0 0 0 .18-.06.142.142 0 0 0 .06-.02 1.048 1.048 0 0 0 .23-.13c.02-.01.03-.01.04-.03z" fill="#28a8ea"/><path d="M18 24.667V8.333A1.337 1.337 0 0 0 16.667 7H10.03v7.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v10h8.667A1.337 1.337 0 0 0 18 24.667z" opacity=".1"/><path d="M17 25.667V9.333A1.337 1.337 0 0 0 15.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v11h7.667A1.337 1.337 0 0 0 17 25.667z" opacity=".2"/><path d="M17 23.667V9.333A1.337 1.337 0 0 0 15.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v9h7.667A1.337 1.337 0 0 0 17 23.667z" opacity=".2"/><path d="M16 23.667V9.333A1.337 1.337 0 0 0 14.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v9h6.667A1.337 1.337 0 0 0 16 23.667z" opacity=".2"/><path d="M1.333 8h13.334A1.333 1.333 0 0 1 16 9.333v13.334A1.333 1.333 0 0 1 14.667 24H1.333A1.333 1.333 0 0 1 0 22.667V9.333A1.333 1.333 0 0 1 1.333 8z" fill="#0078d4"/><path d="M3.867 13.468a4.181 4.181 0 0 1 1.642-1.814A4.965 4.965 0 0 1 8.119 11a4.617 4.617 0 0 1 2.413.62 4.14 4.14 0 0 1 1.598 1.733 5.597 5.597 0 0 1 .56 2.55 5.901 5.901 0 0 1-.577 2.666 4.239 4.239 0 0 1-1.645 1.794A4.8 4.8 0 0 1 7.963 21a4.729 4.729 0 0 1-2.468-.627 4.204 4.204 0 0 1-1.618-1.736 5.459 5.459 0 0 1-.567-2.519 6.055 6.055 0 0 1 .557-2.65zm1.75 4.258a2.716 2.716 0 0 0 .923 1.194 2.411 2.411 0 0 0 1.443.435 2.533 2.533 0 0 0 1.541-.449 2.603 2.603 0 0 0 .897-1.197 4.626 4.626 0 0 0 .286-1.665 5.063 5.063 0 0 0-.27-1.686 2.669 2.669 0 0 0-.866-1.24 2.387 2.387 0 0 0-1.527-.473 2.493 2.493 0 0 0-1.477.439 2.741 2.741 0 0 0-.944 1.203 4.776 4.776 0 0 0-.007 3.44z" fill="#fff"/></svg>',a.addEventListener("click",function(){atcb_generate_microsoft(n,"outlook"),atcb_close()});break;case"Yahoo":atcb_generate_label(a,!0,t[1]||"Yahoo"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3386.34 3010.5" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd"><path d="M0 732.88h645.84l376.07 962.1 380.96-962.1h628.76l-946.8 2277.62H451.98l259.19-603.53L.02 732.88zm2763.84 768.75h-704.26L2684.65 0l701.69.03-622.5 1501.6zm-519.78 143.72c216.09 0 391.25 175.17 391.25 391.22 0 216.06-175.16 391.23-391.25 391.23-216.06 0-391.19-175.17-391.19-391.23 0-216.05 175.16-391.22 391.19-391.22z" fill="#5f01d1" fill-rule="nonzero"/></svg>',a.addEventListener("click",function(){atcb_generate_yahoo(n),atcb_close()})}a.addEventListener("keydown",function(e){"Enter"==e.key&&this.click()})}),c}function atcb_generate_bg_overlay(e){const t=document.createElement("div");t.classList.add("atcb_bgoverlay"),"modal"!==e.listStyle&&t.classList.add("atcb_animate_bg"),t.tabIndex=0,t.addEventListener("click",()=>atcb_close(!0));let a=!1;return t.addEventListener("touchstart",()=>a=!1,{passive:!0}),t.addEventListener("touchmove",()=>a=!0,{passive:!0}),t.addEventListener("touchend",function(){!1===a&&atcb_close(!0)},{passive:!0}),t.addEventListener("focus",()=>atcb_close(!1)),"click"!==e.trigger?t.addEventListener("mousemove",()=>atcb_close(!0)):t.classList.add("atcb_click"),t}function atcb_toggle(e,t,a=!0,n=!1){t.classList.contains("atcb_active")?atcb_close():atcb_open(e,t,a,n)}function atcb_open(e,t,a=!0,n=!1){if(!document.querySelector(".atcb_list")){const c=atcb_generate_dropdown_list(e);t?(t.classList.add("atcb_active"),"modal"===e.listStyle?(t.classList.add("atcb_modal_style"),c.classList.add("atcb_modal")):(t=t.getBoundingClientRect(),c.style.width=t.width+"px",c.style.top=t.bottom+window.scrollY-3+"px",c.style.left=t.left+"px",c.classList.add("atcb_dropdown"),n&&c.classList.add("atcb_generated_button"))):(e.listStyle="modal",c.classList.add("atcb_modal")),document.body.appendChild(c),document.body.appendChild(atcb_generate_bg_overlay(e)),a&&c.firstChild.focus()}}function atcb_close(e=!1){if(!e){let e=document.querySelector(".atcb_active");e&&e.focus()}Array.from(document.querySelectorAll(".atcb_active")).forEach(e=>{e.classList.remove("atcb_active")}),Array.from(document.querySelectorAll(".atcb_list")).concat(Array.from(document.querySelectorAll(".atcb_bgoverlay"))).forEach(e=>e.remove())}function atcb_action(e,t,a=!0){if(!atcb_check_required(e))throw new Error("data missing; see logs");if(!atcb_validate(e=atcb_decorate_data(e)))throw new Error("Invalid data; see logs");atcb_open(e,t,a)}function atcb_generate_google(e){let t="https://calendar.google.com/calendar/render?action=TEMPLATE";var a=atcb_generate_time(e,"clean","google");t+="&dates="+a.start+"%2F"+a.end,null!=e.name&&""!=e.name&&(t+="&text="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(t+="&location="+encodeURIComponent(e.location),isiOS()&&(null==e.description||""==e.description?e.description="":e.description+="%0A%0A",e.description+="📍: "+e.location)),null!=e.description&&""!=e.description&&(t+="&details="+encodeURIComponent(e.description)),window.open(t,"_blank").focus()}function atcb_generate_yahoo(e){let t="https://calendar.yahoo.com/?v=60";var a=atcb_generate_time(e,"clean");t+="&st="+a.start+"&et="+a.end,a.allday&&(t+="&dur=allday"),null!=e.name&&""!=e.name&&(t+="&title="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(t+="&in_loc="+encodeURIComponent(e.location)),null!=e.description&&""!=e.description&&(t+="&desc="+encodeURIComponent(e.description)),window.open(t,"_blank").focus()}function atcb_generate_microsoft(e,t="365"){let a="https://";a+="outlook"==t?"outlook.live.com":"outlook.office.com",a+="/calendar/0/deeplink/compose?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent";t=atcb_generate_time(e,"delimiters","microsoft");a+="&startdt="+t.start+"&enddt="+t.end,t.allday&&(a+="&allday=true"),null!=e.name&&""!=e.name&&(a+="&subject="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(a+="&location="+encodeURIComponent(e.location)),null!=e.description&&""!=e.description&&(a+="&body="+encodeURIComponent(e.description.replace(/\n/g,"%0A"))),window.open(a,"_blank").focus()}function atcb_generate_teams(e){let t="https://teams.microsoft.com/l/meeting/new?";var a=atcb_generate_time(e,"delimiters","microsoft");t+="&startTime="+a.start+"&endTime="+a.end;let n="";null!=e.name&&""!=e.name&&(t+="&subject="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(n=encodeURIComponent(e.location),t+="&location="+n,n+=" // "),null!=e.description_iCal&&""!=e.description_iCal&&(t+="&content="+n+encodeURIComponent(e.description_iCal)),window.open(t,"_blank").focus()}function atcb_generate_ical(e){let t=new Date;t=t.toISOString();var a=atcb_generate_time(e,"clean","ical");let n="";a.allday&&(n=";VALUE=DATE");const c=["BEGIN:VCALENDAR","VERSION:2.0"];c.push("PRODID:-// github.com/jekuer/add-to-calendar-button // atcb v"+atcbVersion+" //EN"),c.push("CALSCALE:GREGORIAN"),c.push("BEGIN:VEVENT"),c.push("UID:"+t+"@add-to-calendar-button"),c.push("DTSTAMP:"+a.start,"DTSTART"+n+":"+a.start,"DTEND"+n+":"+a.end,"SUMMARY:"+e.name.replace(/.{65}/g,"$&\r\n ")),null!=e.description_iCal&&""!=e.description_iCal&&c.push("DESCRIPTION:"+e.description_iCal.replace(/\n/g,"\\n").replace(/.{60}/g,"$&\r\n ")),null!=e.location&&""!=e.location&&c.push("LOCATION:"+e.location),t=t.replace(/\.\d{3}/g,"").replace(/[^a-z\d]/gi,""),c.push("STATUS:CONFIRMED","LAST-MODIFIED:"+t,"SEQUENCE:0","END:VEVENT","END:VCALENDAR");a="data:text/calendar;charset=utf-8,"+encodeURIComponent(c.join("\r\n")),e=e.iCalFileName||"event-to-save-in-my-calendar";try{if(window.ActiveXObject){if(window.ActiveXObject&&document.execCommand){const i=window.open(a,"_blank");i.document.close(),i.document.execCommand("SaveAs",!0,e||a),i.close()}}else{const l=document.createElement("a");l.href=a,l.target="_blank",l.download=e;var o=new MouseEvent("click",{view:window,button:0,bubbles:!0,cancelable:!1});l.dispatchEvent(o),(window.URL||window.webkitURL).revokeObjectURL(l.href)}}catch(e){console.error(e)}}function atcb_generate_time(e,a="delimiters",n="general"){var c=e.startDate.split("-"),o=e.endDate.split("-");let i="",l="",r=!1;if(null!=e.startTime&&null!=e.endTime){if(null!=e.timeZoneOffset&&""!=e.timeZoneOffset)i=new Date(c[0]+"-"+c[1]+"-"+c[2]+"T"+e.startTime+":00.000"+e.timeZoneOffset),l=new Date(o[0]+"-"+o[1]+"-"+o[2]+"T"+e.endTime+":00.000"+e.timeZoneOffset);else if(i=new Date(c[0]+"-"+c[1]+"-"+c[2]+"T"+e.startTime+":00.000+00:00"),l=new Date(o[0]+"-"+o[1]+"-"+o[2]+"T"+e.endTime+":00.000+00:00"),null!=e.timeZone&&""!=e.timeZone){const t=new Date(i.toLocaleString("en-US",{timeZone:"UTC"})),s=("currentBrowser"==e.timeZone&&(e.timeZone=Intl.DateTimeFormat().resolvedOptions().timeZone),new Date(i.toLocaleString("en-US",{timeZone:e.timeZone})));e=t.getTime()-s.getTime();i.setTime(i.getTime()+e),l.setTime(l.getTime()+e)}i=i.toISOString().replace(".000",""),l=l.toISOString().replace(".000",""),"clean"==a&&(i=i.replace(/-/g,"").replace(/:/g,""),l=l.replace(/-/g,"").replace(/:/g,""))}else{r=!0,i=new Date(Date.UTC(c[0],c[1]-1,c[2]));let e=i.toISOString().replace(/T(.+)Z/g,""),t=(l=new Date(Date.UTC(o[0],o[1]-1,o[2])),"google"!=n&&"microsoft"!=n&&"ical"!=n||l.setDate(l.getDate()+1),l.toISOString().replace(/T(.+)Z/g,""));"clean"==a&&(e=e.replace(/-/g,""),t=t.replace(/-/g,"")),i=e,l=t}return{start:i,end:l,allday:r}}if(isBrowser()){document.addEventListener("keydown",e=>{"Escape"===e.key&&atcb_close()});let e=window.innerWidth;window.addEventListener("resize",()=>{window.innerWidth!=e&&(e=window.innerWidth,atcb_close(!0))})}isBrowser()&&document.addEventListener("DOMContentLoaded",atcb_init,!1); | ||
const atcbVersion="1.9.1",isBrowser=new Function("try { return this===window; }catch(e){ return false; }"),isiOS=isBrowser()?new Function("if ((/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)){ return true; }else{ return false; }"):new Function("return false;");function atcb_init(){console.log("add-to-calendar button initialized (version "+atcbVersion+")"),console.log("See https://github.com/jekuer/add-to-calendar-button for details");const a=document.querySelectorAll(".atcb");if(0<a.length){var n=document.querySelectorAll(".atcb_initialized");for(let t=0;t<a.length;t++)if(!a[parseInt(t)].classList.contains("atcb_initialized")){let e;const c=a[parseInt(t)].querySelector("script");c&&c.innerHTML?(e=JSON.parse(c.innerHTML.replace(/(\r\n|\n|\r)/g,"").replace(/(<(?!br)([^>]+)>)/gi,"")),e=atcb_parse_schema_json(e),e.deleteJSON=!1):(e=JSON.parse(a[parseInt(t)].innerHTML.replace(/(\r\n|\n|\r)/g,"").replace(/(<(?!br)([^>]+)>)/gi,"")),e.deleteJSON=!0),e=atcb_patch_config(e),atcb_check_required(e)&&(e=atcb_decorate_data(e),atcb_validate(e)&&atcb_generate(a[parseInt(t)],t+n.length,e))}}}function atcb_parse_schema_json(t){try{Object.keys(t.event).forEach(e=>{"@"!==e.charAt(0)&&(t[""+e]=t.event[""+e])}),delete t.event}catch(e){console.error("add-to-calendar button problem: it seems like you use the schema.org style, but did not define it properly")}return t}function atcb_patch_config(t){const a={title:"name",dateStart:"startDate",dateEnd:"endDate",timeStart:"startTime",timeEnd:"endTime"};return Object.keys(a).forEach(e=>{null==t[a[""+e]]&&null!=t[""+e]&&(t[a[""+e]]=t[""+e])}),t}function atcb_decorate_data(e){if((e=atcb_date_cleanup(e)).startDate=atcb_date_calculation(e.startDate),e.endDate=atcb_date_calculation(e.endDate),!e.description||e.descriptionHtmlFree)return e;const t=Object.assign({},e);return t.description=t.description.replace(/<br\s*\/?>/gi,"\n"),t.descriptionHtmlFree=t.description.replace(/\[url\]/gi,"").replace(/\[\/url\]/gi,""),t.description=t.description.replace(/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/gi,'<a href="$1" target="_blank" rel="noopener">$1</a>'),t}function atcb_check_required(t){if(null==t.options||t.options.length<1)return console.error("add-to-calendar button generation failed: no options set"),!1;return["name","startDate","endDate"].every(function(e){return null!=t[""+e]&&""!=t[""+e]||(console.error("add-to-calendar button generation failed: required setting missing ["+e+"]"),!1)})}function atcb_date_cleanup(n){return["start","end"].forEach(function(e){var t;if(null!=n[e+"Date"]&&(n[e+"Date"]=n[e+"Date"].replace(/\.\d{3}/,"").replace("Z",""),null!=(t=n[e+"Date"].split("T"))[1]&&(n[e+"Date"]=t[0],n[e+"Time"]=t[1])),null!=n[e+"Time"]&&8===n[e+"Time"].length){const a=n[e+"Time"];n[e+"Time"]=a.substring(0,a.length-3)}}),n}function atcb_date_calculation(e){const t=new Date;var a=t.getUTCMonth()+1+"-"+t.getUTCDate()+"-"+t.getUTCFullYear();const n=(e=e.replace(/today/gi,a)).split("+");a=n[0].split("-");let c=new Date(a[0],a[1]-1,a[2]);return a[0].length<4&&(c=new Date(a[2],a[0]-1,a[1])),null!=n[1]&&0<n[1]&&c.setDate(c.getDate()+parseInt(n[1])),c.getFullYear()+"-"+(c.getMonth()+1<10?"0":"")+(c.getMonth()+1)+"-"+(c.getDate()<10?"0":"")+c.getDate()}function atcb_validate(a){const t=["Apple","Google","iCal","Microsoft365","Outlook.com","MicrosoftTeams","Yahoo"];if(!a.options.every(function(e){e=e.split("|");return!!t.includes(e[0])||(console.error("add-to-calendar button generation failed: invalid option ["+e[0]+"]"),!1)}))return!1;const e=["startDate","endDate"],n=e;if(!e.every(function(e){if(10!==a[""+e].length)return console.error("add-to-calendar button generation failed: date misspelled [-> YYYY-MM-DD]"),!1;var t=a[""+e].split("-");return t.length<3||3<t.length?(console.error("add-to-calendar button generation failed: date misspelled ["+e+": "+a[""+e]+"]"),!1):(n[""+e]=new Date(t[0],t[1]-1,t[2]),!0)}))return!1;return!!["startTime","endTime"].every(function(e){if(null!=a[""+e]){if(5!==a[""+e].length)return console.error("add-to-calendar button generation failed: time misspelled [-> HH:MM]"),!1;var t=a[""+e].split(":");if(t.length<2||2<t.length)return console.error("add-to-calendar button generation failed: time misspelled ["+e+": "+a[""+e]+"]"),!1;if(23<t[0])return console.error("add-to-calendar button generation failed: time misspelled - hours number too high ["+e+": "+t[0]+"]"),!1;if(59<t[1])return console.error("add-to-calendar button generation failed: time misspelled - minutes number too high ["+e+": "+t[1]+"]"),!1;"startTime"==e&&(n.startDate=new Date(n.startDate.getTime()+36e5*t[0]+6e4*t[1])),"endTime"==e&&(n.endDate=new Date(n.endDate.getTime()+36e5*t[0]+6e4*t[1]))}return!0})&&(null!=a.startTime&&null==a.endTime||null==a.startTime&&null!=a.endTime?(console.error("add-to-calendar button generation failed: if you set a starting time, you also need to define an end time"),!1):!(n.endDate<n.startDate)||(console.error("add-to-calendar button generation failed: end date before start date"),!1))}function atcb_generate_label(e,t=!1,a){if(t){const n=document.createElement("span");n.classList.add("atcb_icon"),e.appendChild(n)}if(""!=a){const c=document.createElement("span");c.classList.add("atcb_text"),c.textContent=a,e.appendChild(c)}}function atcb_generate(e,t,a){a.deleteJSON&&(e.innerHTML="");const n=document.createElement("div"),c=(n.classList.add("atcb_button_wrapper"),e.appendChild(n),document.createElement("button"));c.id="atcb_button_"+t,c.classList.add("atcb_button"),c.setAttribute("type","button"),n.appendChild(c),atcb_generate_label(c,!0,a.label||"Add to Calendar"),c.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M81.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zm-3.65 76.03c1.83 0 3.32 1.49 3.32 3.32s-1.49 3.32-3.32 3.32l-12.95-.04-.04 12.93c0 1.83-1.49 3.32-3.32 3.32s-3.32-1.49-3.32-3.32l.04-12.94-12.93-.05c-1.83 0-3.32-1.49-3.32-3.32s1.49-3.32 3.32-3.32l12.94.04.04-12.93c0-1.83 1.49-3.32 3.32-3.32s3.32 1.49 3.32 3.32l-.04 12.95 12.94.04h0zM29.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zM6.4 45.32h110.08V21.47c0-.8-.33-1.53-.86-2.07-.53-.53-1.26-.86-2.07-.86H103c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h10.55c2.57 0 4.9 1.05 6.59 2.74s2.74 4.02 2.74 6.59v27.06 65.03c0 2.57-1.05 4.9-2.74 6.59s-4.02 2.74-6.59 2.74H9.33c-2.57 0-4.9-1.05-6.59-2.74-1.69-1.7-2.74-4.03-2.74-6.6V48.53 21.47c0-2.57 1.05-4.9 2.74-6.59s4.02-2.74 6.59-2.74H20.6c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H9.33c-.8 0-1.53.33-2.07.86-.53.53-.86 1.26-.86 2.07v23.85h0zm110.08 6.41H6.4v61.82c0 .8.33 1.53.86 2.07.53.53 1.26.86 2.07.86h104.22c.8 0 1.53-.33 2.07-.86.53-.53.86-1.26.86-2.07V51.73h0zM50.43 18.54c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h21.49c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H50.43h0z"/></svg>',"click"==a.trigger?c.addEventListener("mousedown",()=>atcb_toggle(a,c,!1,!0)):(c.addEventListener("touchstart",()=>atcb_toggle(a,c,!1,!0),{passive:!0}),c.addEventListener("mouseenter",()=>atcb_open(a,c,!1,!0))),c.addEventListener("keydown",function(e){"Enter"==e.key&&atcb_toggle(a,c,!0,!0)}),e.classList.remove("atcb"),e.classList.add("atcb_initialized"),a.inline?e.style.display="inline-block":e.style.display="block",console.log("add-to-calendar button #"+(t+1)+" created")}function atcb_generate_dropdown_list(n){const c=document.createElement("div");return c.classList.add("atcb_list"),n.options.forEach(function(e){var t=e.split("|");const a=document.createElement("div");switch(a.classList.add("atcb_list_item"),a.tabIndex=0,c.appendChild(a),t[0]){case"Apple":atcb_generate_label(a,!0,t[1]||"Apple"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" viewBox="0 0 640 640"><path d="M494.782 340.02c-.803-81.025 66.084-119.907 69.072-121.832-37.595-54.993-96.167-62.552-117.037-63.402-49.843-5.032-97.242 29.362-122.565 29.362-25.253 0-64.277-28.607-105.604-27.85-54.32.803-104.4 31.594-132.403 80.245C29.81 334.457 71.81 479.58 126.816 558.976c26.87 38.882 58.914 82.56 100.997 81 40.512-1.594 55.843-26.244 104.848-26.244 48.993 0 62.753 26.245 105.64 25.406 43.606-.803 71.232-39.638 97.925-78.65 30.887-45.12 43.548-88.75 44.316-90.994-.969-.437-85.029-32.634-85.879-129.439l.118-.035zM414.23 102.178C436.553 75.095 451.636 37.5 447.514-.024c-32.162 1.311-71.163 21.437-94.253 48.485-20.729 24.012-38.836 62.28-33.993 99.036 35.918 2.8 72.591-18.248 94.926-45.272l.036-.047z"/></svg>',a.addEventListener("click",function(){atcb_generate_ical(n),atcb_close()});break;case"Google":atcb_generate_label(a,!0,t[1]||"Google"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M93.78 29.1H29.1v64.68h64.68V29.1z" fill="#fff"/><path d="M93.78 122.88l29.1-29.1h-29.1v29.1z" fill="#f72a25"/><path d="M122.88 29.1h-29.1v64.68h29.1V29.1z" fill="#fbbc04"/><path d="M93.78 93.78H29.1v29.1h64.68v-29.1z" fill="#34a853"/><path d="M0 93.78v19.4c0 5.36 4.34 9.7 9.7 9.7h19.4v-29.1H0h0z" fill="#188038"/><path d="M122.88 29.1V9.7c0-5.36-4.34-9.7-9.7-9.7h-19.4v29.1h29.1 0z" fill="#1967d2"/><path d="M93.78 0H9.7C4.34 0 0 4.34 0 9.7v84.08h29.1V29.1h64.67V0h.01z" fill="#4285f4"/><path d="M42.37 79.27c-2.42-1.63-4.09-4.02-5-7.17l5.61-2.31c.51 1.94 1.4 3.44 2.67 4.51 1.26 1.07 2.8 1.59 4.59 1.59 1.84 0 3.41-.56 4.73-1.67 1.32-1.12 1.98-2.54 1.98-4.26 0-1.76-.7-3.2-2.09-4.32s-3.14-1.67-5.22-1.67H46.4v-5.55h2.91c1.79 0 3.31-.48 4.54-1.46 1.23-.97 1.84-2.3 1.84-3.99 0-1.5-.55-2.7-1.65-3.6s-2.49-1.35-4.18-1.35c-1.65 0-2.96.44-3.93 1.32s-1.7 2-2.12 3.24l-5.55-2.31c.74-2.09 2.09-3.93 4.07-5.52s4.51-2.39 7.58-2.39c2.27 0 4.32.44 6.13 1.32s3.23 2.1 4.26 3.65c1.03 1.56 1.54 3.31 1.54 5.25 0 1.98-.48 3.65-1.43 5.03-.95 1.37-2.13 2.43-3.52 3.16v.33c1.79.74 3.36 1.96 4.51 3.52 1.17 1.58 1.76 3.46 1.76 5.66s-.56 4.16-1.67 5.88c-1.12 1.72-2.66 3.08-4.62 4.07s-4.17 1.49-6.62 1.49c-2.84 0-5.46-.81-7.88-2.45h0 0zm34.46-27.84l-6.16 4.45-3.08-4.67 11.05-7.97h4.24v37.6h-6.05V51.43h0z" fill="#1a73e8"/></svg>',a.addEventListener("click",function(){atcb_generate_google(n),atcb_close()});break;case"iCal":atcb_generate_label(a,!0,t[1]||"iCal File"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 122.88 122.88"><path d="M81.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zm-15.5 99.08c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zM15.85 67.09c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zm25.14 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H91.25h0zm-75.4 18.36c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2H81.9c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H66.11h0zm25.14 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H91.25h0zm-75.4 18.36c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H15.85h0zm25.13 0c-.34 0-.61-1.43-.61-3.2s.27-3.2.61-3.2h15.79c.34 0 .61 1.43.61 3.2s-.27 3.2-.61 3.2H40.98h0zM29.61 4.73c0-2.61 2.58-4.73 5.77-4.73s5.77 2.12 5.77 4.73v20.72c0 2.61-2.58 4.73-5.77 4.73s-5.77-2.12-5.77-4.73V4.73h0zM6.4 45.32h110.07V21.47c0-.8-.33-1.53-.86-2.07-.53-.53-1.26-.86-2.07-.86H103c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h10.55c2.57 0 4.9 1.05 6.59 2.74s2.74 4.02 2.74 6.59v27.06 65.03c0 2.57-1.05 4.9-2.74 6.59s-4.02 2.74-6.59 2.74H9.33c-2.57 0-4.9-1.05-6.59-2.74-1.69-1.7-2.74-4.03-2.74-6.6V48.52 21.47c0-2.57 1.05-4.9 2.74-6.59s4.02-2.74 6.59-2.74H20.6c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H9.33c-.8 0-1.53.33-2.07.86-.53.53-.86 1.26-.86 2.07v23.85h0zm110.08 6.41H6.4v61.82c0 .8.33 1.53.86 2.07.53.53 1.26.86 2.07.86h104.22c.8 0 1.53-.33 2.07-.86.53-.53.86-1.26.86-2.07V51.73h0zM50.43 18.54c-1.77 0-3.2-1.43-3.2-3.2s1.43-3.2 3.2-3.2h21.49c1.77 0 3.2 1.43 3.2 3.2s-1.43 3.2-3.2 3.2H50.43h0z"/></svg>',a.addEventListener("click",function(){atcb_generate_ical(n),atcb_close()});break;case"MicrosoftTeams":atcb_generate_label(a,!0,t[1]||"Microsoft Teams"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 2228.833 2073.333"><g fill="#5059c9"><path d="M1554.637 777.5h575.713c54.391 0 98.483 44.092 98.483 98.483v524.398c0 199.901-162.051 361.952-361.952 361.952h0-1.711c-199.901.028-361.975-162-362.004-361.901v-.052-571.409c.001-28.427 23.045-51.471 51.471-51.471h0z"/><circle cx="1943.75" cy="440.583" r="233.25"/></g><g fill="#7b83eb"><circle cx="1218.083" cy="336.917" r="336.917"/><path d="M1667.323 777.5H717.01c-53.743 1.33-96.257 45.931-95.01 99.676v598.105c-7.505 322.519 247.657 590.16 570.167 598.053 322.51-7.893 577.671-275.534 570.167-598.053V877.176c1.245-53.745-41.268-98.346-95.011-99.676z"/></g><path opacity=".1" d="M1244 777.5v838.145c-.258 38.435-23.549 72.964-59.09 87.598-11.316 4.787-23.478 7.254-35.765 7.257H667.613c-6.738-17.105-12.958-34.21-18.142-51.833-18.144-59.477-27.402-121.307-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52H1244z"/><path opacity=".2" d="M1192.167 777.5v889.978a91.84 91.84 0 0 1-7.257 35.765c-14.634 35.541-49.163 58.833-87.598 59.09H691.975c-8.812-17.105-17.105-34.21-24.362-51.833s-12.958-34.21-18.142-51.833a631.28 631.28 0 0 1-27.472-183.49V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.313z"/><path opacity=".2" d="M1192.167 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855h-447.84A631.28 631.28 0 0 1 622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h475.312z"/><path opacity=".2" d="M1140.333 777.5v786.312c-.395 52.223-42.632 94.46-94.855 94.855H649.472A631.28 631.28 0 0 1 622 1475.177V877.02c-1.246-53.659 41.198-98.19 94.855-99.52h423.478z"/><path opacity=".1" d="M1244 509.522v163.275c-8.812.518-17.105 1.037-25.917 1.037s-17.105-.518-25.917-1.037c-17.496-1.161-34.848-3.937-51.833-8.293a336.92 336.92 0 0 1-233.25-198.003 288.02 288.02 0 0 1-16.587-51.833h258.648c52.305.198 94.657 42.549 94.856 94.854z"/><use xlink:href="#C" opacity=".2"/><use xlink:href="#C" opacity=".2"/><path opacity=".2" d="M1140.333 561.355v103.148A336.92 336.92 0 0 1 907.083 466.5h138.395c52.305.199 94.656 42.551 94.855 94.855z"/><linearGradient id="A" gradientUnits="userSpaceOnUse" x1="198.099" y1="392.261" x2="942.234" y2="1681.073"><stop offset="0" stop-color="#5a62c3"/><stop offset=".5" stop-color="#4d55bd"/><stop offset="1" stop-color="#3940ab"/></linearGradient><path fill="url(#A)" d="M95.01 466.5h950.312c52.473 0 95.01 42.538 95.01 95.01v950.312c0 52.473-42.538 95.01-95.01 95.01H95.01c-52.473 0-95.01-42.538-95.01-95.01V561.51c0-52.472 42.538-95.01 95.01-95.01z"/><path fill="#fff" d="M820.211,828.193H630.241v517.297H509.211V828.193H320.123V727.844h500.088V828.193z"/><defs ><path id="C" d="M1192.167 561.355v111.442c-17.496-1.161-34.848-3.937-51.833-8.293a336.92 336.92 0 0 1-233.25-198.003h190.228c52.304.198 94.656 42.55 94.855 94.854z"/></defs></svg>',a.addEventListener("click",function(){atcb_generate_teams(n),atcb_close()});break;case"Microsoft365":atcb_generate_label(a,!0,t[1]||"Microsoft 365"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 278050 333334" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd"><path fill="#ea3e23" d="M278050 305556l-29-16V28627L178807 0 448 66971l-448 87 22 200227 60865-23821V80555l117920-28193-17 239519L122 267285l178668 65976v73l99231-27462v-316z"/></svg>',a.addEventListener("click",function(){atcb_generate_microsoft(n,"365"),atcb_close()});break;case"Outlook.com":atcb_generate_label(a,!0,t[1]||"Outlook.com"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.129793726981 0 33.251996719421 32" width="2500" height="2397"><path d="M28.596 2H11.404A1.404 1.404 0 0 0 10 3.404V5l9.69 3L30 5V3.404A1.404 1.404 0 0 0 28.596 2z" fill="#0364b8"/><path d="M31.65 17.405A11.341 11.341 0 0 0 32 16a.666.666 0 0 0-.333-.576l-.013-.008-.004-.002L20.812 9.24a1.499 1.499 0 0 0-1.479-.083 1.49 1.49 0 0 0-.145.082L8.35 15.415l-.004.002-.012.007A.666.666 0 0 0 8 16a11.344 11.344 0 0 0 .35 1.405l11.492 8.405z" fill="#0a2767"/><path d="M24 5h-7l-2.021 3L17 11l7 6h6v-6z" fill="#28a8ea"/><path d="M10 5h7v6h-7z" fill="#0078d4"/><path d="M24 5h6v6h-6z" fill="#50d9ff"/><path d="M24 17l-7-6h-7v6l7 6 10.832 1.768z" fill="#0364b8"/><path d="M17 11h7v6h-7z" fill="#0078d4"/><path d="M10 17h7v6h-7z" fill="#064a8c"/><path d="M24 17h6v6h-6z" fill="#0078d4"/><path d="M20.19 25.218l-11.793-8.6.495-.87 10.909 6.212a.528.528 0 0 0 .42-.012l10.933-6.23.496.869z" fill="#0a2767" opacity=".5"/><path d="M31.667 16.577l-.014.008-.003.002-10.838 6.174a1.497 1.497 0 0 1-1.46.091l3.774 5.061 8.254 1.797v.004A1.498 1.498 0 0 0 32 28.5V16a.666.666 0 0 1-.333.577z" fill="#1490df"/><path d="M32 28.5v-.738l-9.983-5.688-1.205.687a1.497 1.497 0 0 1-1.46.091l3.774 5.061 8.254 1.797v.004A1.498 1.498 0 0 0 32 28.5z" opacity=".05"/><path d="M31.95 28.883L21.007 22.65l-.195.11a1.497 1.497 0 0 1-1.46.092l3.774 5.061 8.254 1.797v.004a1.501 1.501 0 0 0 .57-.83z" opacity=".1"/><path d="M8.35 16.59v-.01h-.01l-.03-.02A.65.65 0 0 1 8 16v12.5A1.498 1.498 0 0 0 9.5 30h21a1.503 1.503 0 0 0 .37-.05.637.637 0 0 0 .18-.06.142.142 0 0 0 .06-.02 1.048 1.048 0 0 0 .23-.13c.02-.01.03-.01.04-.03z" fill="#28a8ea"/><path d="M18 24.667V8.333A1.337 1.337 0 0 0 16.667 7H10.03v7.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v10h8.667A1.337 1.337 0 0 0 18 24.667z" opacity=".1"/><path d="M17 25.667V9.333A1.337 1.337 0 0 0 15.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v11h7.667A1.337 1.337 0 0 0 17 25.667z" opacity=".2"/><path d="M17 23.667V9.333A1.337 1.337 0 0 0 15.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v9h7.667A1.337 1.337 0 0 0 17 23.667z" opacity=".2"/><path d="M16 23.667V9.333A1.337 1.337 0 0 0 14.667 8H10.03v6.456l-1.68.958-.005.002-.012.007A.666.666 0 0 0 8 16v.005V16v9h6.667A1.337 1.337 0 0 0 16 23.667z" opacity=".2"/><path d="M1.333 8h13.334A1.333 1.333 0 0 1 16 9.333v13.334A1.333 1.333 0 0 1 14.667 24H1.333A1.333 1.333 0 0 1 0 22.667V9.333A1.333 1.333 0 0 1 1.333 8z" fill="#0078d4"/><path d="M3.867 13.468a4.181 4.181 0 0 1 1.642-1.814A4.965 4.965 0 0 1 8.119 11a4.617 4.617 0 0 1 2.413.62 4.14 4.14 0 0 1 1.598 1.733 5.597 5.597 0 0 1 .56 2.55 5.901 5.901 0 0 1-.577 2.666 4.239 4.239 0 0 1-1.645 1.794A4.8 4.8 0 0 1 7.963 21a4.729 4.729 0 0 1-2.468-.627 4.204 4.204 0 0 1-1.618-1.736 5.459 5.459 0 0 1-.567-2.519 6.055 6.055 0 0 1 .557-2.65zm1.75 4.258a2.716 2.716 0 0 0 .923 1.194 2.411 2.411 0 0 0 1.443.435 2.533 2.533 0 0 0 1.541-.449 2.603 2.603 0 0 0 .897-1.197 4.626 4.626 0 0 0 .286-1.665 5.063 5.063 0 0 0-.27-1.686 2.669 2.669 0 0 0-.866-1.24 2.387 2.387 0 0 0-1.527-.473 2.493 2.493 0 0 0-1.477.439 2.741 2.741 0 0 0-.944 1.203 4.776 4.776 0 0 0-.007 3.44z" fill="#fff"/></svg>',a.addEventListener("click",function(){atcb_generate_microsoft(n,"outlook"),atcb_close()});break;case"Yahoo":atcb_generate_label(a,!0,t[1]||"Yahoo"),a.firstChild.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 3386.34 3010.5" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd"><path d="M0 732.88h645.84l376.07 962.1 380.96-962.1h628.76l-946.8 2277.62H451.98l259.19-603.53L.02 732.88zm2763.84 768.75h-704.26L2684.65 0l701.69.03-622.5 1501.6zm-519.78 143.72c216.09 0 391.25 175.17 391.25 391.22 0 216.06-175.16 391.23-391.25 391.23-216.06 0-391.19-175.17-391.19-391.23 0-216.05 175.16-391.22 391.19-391.22z" fill="#5f01d1" fill-rule="nonzero"/></svg>',a.addEventListener("click",function(){atcb_generate_yahoo(n),atcb_close()})}a.addEventListener("keydown",function(e){"Enter"==e.key&&this.click()})}),c}function atcb_generate_bg_overlay(e){const t=document.createElement("div");t.classList.add("atcb_bgoverlay"),"modal"!==e.listStyle&&t.classList.add("atcb_animate_bg"),t.tabIndex=0,t.addEventListener("click",()=>atcb_close(!0));let a=!1;return t.addEventListener("touchstart",()=>a=!1,{passive:!0}),t.addEventListener("touchmove",()=>a=!0,{passive:!0}),t.addEventListener("touchend",function(){!1===a&&atcb_close(!0)},{passive:!0}),t.addEventListener("focus",()=>atcb_close(!1)),"click"!==e.trigger?t.addEventListener("mousemove",()=>atcb_close(!0)):t.classList.add("atcb_click"),t}function atcb_toggle(e,t,a=!0,n=!1){t.classList.contains("atcb_active")?atcb_close():atcb_open(e,t,a,n)}function atcb_open(e,t,a=!0,n=!1){if(!document.querySelector(".atcb_list")){const c=atcb_generate_dropdown_list(e);t?(t.classList.add("atcb_active"),"modal"===e.listStyle?(t.classList.add("atcb_modal_style"),c.classList.add("atcb_modal")):(t=t.getBoundingClientRect(),c.style.width=t.width+"px",c.style.top=t.bottom+window.scrollY-3+"px",c.style.left=t.left+"px",c.classList.add("atcb_dropdown"),n&&c.classList.add("atcb_generated_button"))):(e.listStyle="modal",c.classList.add("atcb_modal")),document.body.appendChild(c),document.body.appendChild(atcb_generate_bg_overlay(e)),a&&c.firstChild.focus()}}function atcb_close(e=!1){if(!e){let e=document.querySelector(".atcb_active");e&&e.focus()}Array.from(document.querySelectorAll(".atcb_active")).forEach(e=>{e.classList.remove("atcb_active")}),Array.from(document.querySelectorAll(".atcb_list")).concat(Array.from(document.querySelectorAll(".atcb_bgoverlay"))).forEach(e=>e.remove())}function atcb_action(e,t,a=!0){if(!atcb_check_required(e))throw new Error("data missing; see logs");if(!atcb_validate(e=atcb_decorate_data(e)))throw new Error("Invalid data; see logs");atcb_open(e,t,a)}function atcb_generate_google(e){let t="https://calendar.google.com/calendar/render?action=TEMPLATE";var a=atcb_generate_time(e,"clean","google");t+="&dates="+a.start+"%2F"+a.end,null!=e.name&&""!=e.name&&(t+="&text="+encodeURIComponent(e.name));let n="";null!=e.description&&""!=e.description&&(n=e.description),null!=e.location&&""!=e.location&&(t+="&location="+encodeURIComponent(e.location),isiOS()&&(""!=n&&(n+="<br><br>"),n+="📍: "+e.location)),""!=n&&(t+="&details="+encodeURIComponent(n)),n+="hhh",atcb_secure_url(t)&&window.open(t,"_blank").focus()}function atcb_generate_yahoo(e){let t="https://calendar.yahoo.com/?v=60";var a=atcb_generate_time(e,"clean");t+="&st="+a.start+"&et="+a.end,a.allday&&(t+="&dur=allday"),null!=e.name&&""!=e.name&&(t+="&title="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(t+="&in_loc="+encodeURIComponent(e.location)),null!=e.descriptionHtmlFree&&""!=e.descriptionHtmlFree&&(t+="&desc="+encodeURIComponent(e.descriptionHtmlFree)),atcb_secure_url(t)&&window.open(t,"_blank").focus()}function atcb_generate_microsoft(e,t="365"){let a="https://";a+="outlook"==t?"outlook.live.com":"outlook.office.com",a+="/calendar/0/deeplink/compose?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent";t=atcb_generate_time(e,"delimiters","microsoft");a+="&startdt="+t.start+"&enddt="+t.end,t.allday&&(a+="&allday=true"),null!=e.name&&""!=e.name&&(a+="&subject="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(a+="&location="+encodeURIComponent(e.location)),null!=e.description&&""!=e.description&&(a+="&body="+encodeURIComponent(e.description.replace(/\n/g,"<br>"))),atcb_secure_url(a)&&window.open(a,"_blank").focus()}function atcb_generate_teams(e){let t="https://teams.microsoft.com/l/meeting/new?";var a=atcb_generate_time(e,"delimiters","microsoft");t+="&startTime="+a.start+"&endTime="+a.end;let n="";null!=e.name&&""!=e.name&&(t+="&subject="+encodeURIComponent(e.name)),null!=e.location&&""!=e.location&&(n=encodeURIComponent(e.location),t+="&location="+n,n+=" // "),null!=e.descriptionHtmlFree&&""!=e.descriptionHtmlFree&&(t+="&content="+n+encodeURIComponent(e.descriptionHtmlFree)),atcb_secure_url(t)&&window.open(t,"_blank").focus()}function atcb_generate_ical(e){let t=new Date;t=t.toISOString();var a=atcb_generate_time(e,"clean","ical");let n="";a.allday&&(n=";VALUE=DATE");const c=["BEGIN:VCALENDAR","VERSION:2.0"];c.push("PRODID:-// github.com/jekuer/add-to-calendar-button // atcb v"+atcbVersion+" //EN"),c.push("CALSCALE:GREGORIAN"),c.push("BEGIN:VEVENT"),c.push("UID:"+t+"@add-to-calendar-button"),c.push("DTSTAMP:"+a.start,"DTSTART"+n+":"+a.start,"DTEND"+n+":"+a.end,"SUMMARY:"+e.name.replace(/.{65}/g,"$&\r\n ")),null!=e.descriptionHtmlFree&&""!=e.descriptionHtmlFree&&c.push("DESCRIPTION:"+e.descriptionHtmlFree.replace(/\n/g,"\\n").replace(/.{60}/g,"$&\r\n ")),null!=e.location&&""!=e.location&&c.push("LOCATION:"+e.location),t=t.replace(/\.\d{3}/g,"").replace(/[^a-z\d]/gi,""),c.push("STATUS:CONFIRMED","LAST-MODIFIED:"+t,"SEQUENCE:0","END:VEVENT","END:VCALENDAR");a="data:text/calendar;charset=utf-8,"+encodeURIComponent(c.join("\r\n")),e=e.iCalFileName||"event-to-save-in-my-calendar";try{if(window.ActiveXObject){if(window.ActiveXObject&&document.execCommand){const l=window.open(a,"_blank");l.document.close(),l.document.execCommand("SaveAs",!0,e||a),l.close()}}else{const i=document.createElement("a");i.href=a,i.target="_blank",i.download=e;var o=new MouseEvent("click",{view:window,button:0,bubbles:!0,cancelable:!1});i.dispatchEvent(o),(window.URL||window.webkitURL).revokeObjectURL(i.href)}}catch(e){console.error(e)}}function atcb_generate_time(e,a="delimiters",n="general"){var c=e.startDate.split("-"),o=e.endDate.split("-");let l="",i="",r=!1;if(null!=e.startTime&&null!=e.endTime){if(null!=e.timeZoneOffset&&""!=e.timeZoneOffset)l=new Date(c[0]+"-"+c[1]+"-"+c[2]+"T"+e.startTime+":00.000"+e.timeZoneOffset),i=new Date(o[0]+"-"+o[1]+"-"+o[2]+"T"+e.endTime+":00.000"+e.timeZoneOffset);else if(l=new Date(c[0]+"-"+c[1]+"-"+c[2]+"T"+e.startTime+":00.000+00:00"),i=new Date(o[0]+"-"+o[1]+"-"+o[2]+"T"+e.endTime+":00.000+00:00"),null!=e.timeZone&&""!=e.timeZone){const t=new Date(l.toLocaleString("en-US",{timeZone:"UTC"})),s=("currentBrowser"==e.timeZone&&(e.timeZone=Intl.DateTimeFormat().resolvedOptions().timeZone),new Date(l.toLocaleString("en-US",{timeZone:e.timeZone})));e=t.getTime()-s.getTime();l.setTime(l.getTime()+e),i.setTime(i.getTime()+e)}l=l.toISOString().replace(".000",""),i=i.toISOString().replace(".000",""),"clean"==a&&(l=l.replace(/-/g,"").replace(/:/g,""),i=i.replace(/-/g,"").replace(/:/g,""))}else{r=!0,l=new Date(Date.UTC(c[0],c[1]-1,c[2]));let e=l.toISOString().replace(/T(.+)Z/g,""),t=(i=new Date(Date.UTC(o[0],o[1]-1,o[2])),"google"!=n&&"microsoft"!=n&&"ical"!=n||i.setDate(i.getDate()+1),i.toISOString().replace(/T(.+)Z/g,""));"clean"==a&&(e=e.replace(/-/g,""),t=t.replace(/-/g,"")),l=e,i=t}return{start:l,end:i,allday:r}}function atcb_secure_url(e){return!e.match(/((\.\.\/)|(\.\.\\)|(%2e%2e%2f)|(%252e%252e%252f)|(%2e%2e\/)|(%252e%252e\/)|(\.\.%2f)|(\.\.%252f)|(%2e%2e%5c)|(%252e%252e%255c)|(%2e%2e\\)|(%252e%252e\\)|(\.\.%5c)|(\.\.%255c)|(\.\.%c0%af)|(\.\.%25c0%25af)|(\.\.%c1%9c)|(\.\.%25c1%259c))/gi)||(console.error("Seems like the generated URL includes at least one security issue and got blocked. Please check the calendar button parameters!"),!1)}if(isBrowser()){document.addEventListener("keydown",e=>{"Escape"===e.key&&atcb_close()});let e=window.innerWidth;window.addEventListener("resize",()=>{window.innerWidth!=e&&(e=window.innerWidth,atcb_close(!0))})}isBrowser()&&document.addEventListener("DOMContentLoaded",atcb_init,!1); | ||
//# sourceMappingURL=atcb.min.js.map |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
const atcbVersion = "1.9.0"; | ||
const atcbVersion = "1.9.1"; | ||
/* Creator: Jens Kuerschner (https://jenskuerschner.de) | ||
@@ -35,3 +35,3 @@ * Project: https://github.com/jekuer/add-to-calendar-button | ||
// skip already initialized ones | ||
if (atcButtons[i].classList.contains("atcb_initialized")) { | ||
if (atcButtons[parseInt(i)].classList.contains("atcb_initialized")) { | ||
continue; | ||
@@ -41,9 +41,10 @@ } | ||
// check if schema.org markup is present | ||
const schema = atcButtons[i].querySelector("script"); | ||
const schema = atcButtons[parseInt(i)].querySelector("script"); | ||
// get their JSON content first | ||
if (schema && schema.innerHTML) { | ||
// get schema.org event markup and flatten the event block | ||
// get schema.org event markup and flatten the event block, plus | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
schema.innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
); | ||
atcbConfig = atcb_parse_schema_json(atcbConfig); | ||
@@ -53,6 +54,7 @@ // set flag to not delete HTML content later | ||
} else { | ||
// get JSON from HTML block | ||
// get JSON from HTML block, but | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
atcButtons[i].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcButtons[parseInt(i)].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); | ||
// set flag to delete HTML content later | ||
@@ -70,3 +72,3 @@ atcbConfig.deleteJSON = true; | ||
// ... and generate the button on success | ||
atcb_generate(atcButtons[i], i + atcButtonsInitialized.length, atcbConfig); | ||
atcb_generate(atcButtons[parseInt(i)], i + atcButtonsInitialized.length, atcbConfig); | ||
} | ||
@@ -84,3 +86,3 @@ } | ||
if (key.charAt(0) !== "@") { | ||
atcbConfig[key] = atcbConfig.event[key]; | ||
atcbConfig[`${key}`] = atcbConfig.event[`${key}`]; | ||
} | ||
@@ -108,4 +110,4 @@ }); | ||
Object.keys(keyChanges).forEach((key) => { | ||
if (atcbConfig[keyChanges[key]] == null && atcbConfig[key] != null) { | ||
atcbConfig[keyChanges[key]] = atcbConfig[key]; | ||
if (atcbConfig[keyChanges[`${key}`]] == null && atcbConfig[`${key}`] != null) { | ||
atcbConfig[keyChanges[`${key}`]] = atcbConfig[`${key}`]; | ||
} | ||
@@ -125,3 +127,3 @@ }); | ||
// if no description or already decorated, return early | ||
if (!atcbConfig.description || atcbConfig.description_iCal) return atcbConfig; | ||
if (!atcbConfig.description || atcbConfig.descriptionHtmlFree) return atcbConfig; | ||
@@ -132,8 +134,6 @@ // make a copy of the given argument rather than mutating in place | ||
data.description = data.description.replace(/<br\s*\/?>/gi, "\n"); | ||
data.description_iCal = data.description.replace(/\[url\]/g, "").replace(/\[\/url\]/g, ""); | ||
data.description = decodeURIComponent( | ||
data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/g, | ||
encodeURIComponent('<a href="$1" target="_blank" rel="noopener">$1</a>') | ||
) | ||
data.descriptionHtmlFree = data.description.replace(/\[url\]/gi, "").replace(/\[\/url\]/gi, ""); | ||
data.description = data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/gi, | ||
'<a href="$1" target="_blank" rel="noopener">$1</a>' | ||
); | ||
@@ -153,3 +153,3 @@ return data; | ||
return requiredField.every(function (field) { | ||
if (data[field] == null || data[field] == "") { | ||
if (data[`${field}`] == null || data[`${field}`] == "") { | ||
console.error("add-to-calendar button generation failed: required setting missing [" + field + "]"); | ||
@@ -233,14 +233,14 @@ return false; | ||
!dates.every(function (date) { | ||
if (data[date].length !== 10) { | ||
if (data[`${date}`].length !== 10) { | ||
console.error("add-to-calendar button generation failed: date misspelled [-> YYYY-MM-DD]"); | ||
return false; | ||
} | ||
const dateParts = data[date].split("-"); | ||
const dateParts = data[`${date}`].split("-"); | ||
if (dateParts.length < 3 || dateParts.length > 3) { | ||
console.error( | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[date] + "]" | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[`${date}`] + "]" | ||
); | ||
return false; | ||
} | ||
newDate[date] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
newDate[`${date}`] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
return true; | ||
@@ -255,12 +255,16 @@ }) | ||
!times.every(function (time) { | ||
if (data[time] != null) { | ||
if (data[time].length !== 5) { | ||
if (data[`${time}`] != null) { | ||
if (data[`${time}`].length !== 5) { | ||
console.error("add-to-calendar button generation failed: time misspelled [-> HH:MM]"); | ||
return false; | ||
} | ||
const timeParts = data[time].split(":"); | ||
const timeParts = data[`${time}`].split(":"); | ||
// validate the time parts | ||
if (timeParts.length < 2 || timeParts.length > 2) { | ||
console.error( | ||
"add-to-calendar button generation failed: time misspelled [" + time + ": " + data[time] + "]" | ||
"add-to-calendar button generation failed: time misspelled [" + | ||
time + | ||
": " + | ||
data[`${time}`] + | ||
"]" | ||
); | ||
@@ -550,3 +554,3 @@ return false; | ||
// give keyboard focus to first item in list, if not blocked, because there is definitely no keyboard trigger. | ||
// Mintd that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
// Mind that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
if (keyboardTrigger) { | ||
@@ -600,2 +604,6 @@ list.firstChild.focus(); | ||
} | ||
let tmpDataDescription = ""; | ||
if (data.description != null && data.description != "") { | ||
tmpDataDescription = data.description; | ||
} | ||
if (data.location != null && data.location != "") { | ||
@@ -606,14 +614,16 @@ url += "&location=" + encodeURIComponent(data.location); | ||
// workaround to cover a bug, where, when using Google Calendar on an iPhone, the location is not recognized. So, for the moment, we simply add it to the description. | ||
if (data.description == null || data.description == "") { | ||
data.description = ""; | ||
} else { | ||
data.description += "%0A%0A"; | ||
if (tmpDataDescription != "") { | ||
tmpDataDescription += "<br><br>"; | ||
} | ||
data.description += "📍: " + data.location; | ||
tmpDataDescription += "📍: " + data.location; | ||
} | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&details=" + encodeURIComponent(data.description); | ||
if (tmpDataDescription != "") { | ||
url += "&details=" + encodeURIComponent(tmpDataDescription); | ||
} | ||
window.open(url, "_blank").focus(); | ||
tmpDataDescription += "hhh"; | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -638,6 +648,10 @@ | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&desc=" + encodeURIComponent(data.description); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Yahoo does not support html tags in a stable way | ||
url += "&desc=" + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -669,5 +683,8 @@ | ||
if (data.description != null && data.description != "") { | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "%0A")); | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "<br>")); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -694,7 +711,10 @@ | ||
} | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
// using description_iCal instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.description_iCal); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -723,5 +743,6 @@ | ||
); | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
ics_lines.push( | ||
"DESCRIPTION:" + data.description_iCal.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
"DESCRIPTION:" + | ||
data.descriptionHtmlFree.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
); | ||
@@ -753,2 +774,3 @@ } | ||
else if (!!window.ActiveXObject && document.execCommand) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
const _window = window.open(dlurl, "_blank"); | ||
@@ -842,2 +864,11 @@ _window.document.close(); | ||
function atcb_secure_url(url) { | ||
if (url.match(/((\.\.\/)|(\.\.\\)|(%2e%2e%2f)|(%252e%252e%252f)|(%2e%2e\/)|(%252e%252e\/)|(\.\.%2f)|(\.\.%252f)|(%2e%2e%5c)|(%252e%252e%255c)|(%2e%2e\\)|(%252e%252e\\)|(\.\.%5c)|(\.\.%255c)|(\.\.%c0%af)|(\.\.%25c0%25af)|(\.\.%c1%9c)|(\.\.%25c1%259c))/gi)) { | ||
console.error("Seems like the generated URL includes at least one security issue and got blocked. Please check the calendar button parameters!"); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
} | ||
if (isBrowser()) { | ||
@@ -844,0 +875,0 @@ // Global listener to ESC key to close dropdown |
@@ -6,3 +6,3 @@ /** | ||
*/ | ||
const atcbVersion = "1.9.0"; | ||
const atcbVersion = "1.9.1"; | ||
/* Creator: Jens Kuerschner (https://jenskuerschner.de) | ||
@@ -35,3 +35,3 @@ * Project: https://github.com/jekuer/add-to-calendar-button | ||
// skip already initialized ones | ||
if (atcButtons[i].classList.contains("atcb_initialized")) { | ||
if (atcButtons[parseInt(i)].classList.contains("atcb_initialized")) { | ||
continue; | ||
@@ -41,9 +41,10 @@ } | ||
// check if schema.org markup is present | ||
const schema = atcButtons[i].querySelector("script"); | ||
const schema = atcButtons[parseInt(i)].querySelector("script"); | ||
// get their JSON content first | ||
if (schema && schema.innerHTML) { | ||
// get schema.org event markup and flatten the event block | ||
// get schema.org event markup and flatten the event block, plus | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
schema.innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
); | ||
atcbConfig = atcb_parse_schema_json(atcbConfig); | ||
@@ -53,6 +54,7 @@ // set flag to not delete HTML content later | ||
} else { | ||
// get JSON from HTML block | ||
// get JSON from HTML block, but | ||
// remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcbConfig = JSON.parse( | ||
atcButtons[i].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); // remove real code line breaks before parsing. Use <br> or \n explicitely in the description to create a line break. Also strip HTML tags (especially since stupid Safari adds stuff). | ||
atcButtons[parseInt(i)].innerHTML.replace(/(\r\n|\n|\r)/g, "").replace(/(<(?!br)([^>]+)>)/gi, "") | ||
); | ||
// set flag to delete HTML content later | ||
@@ -70,3 +72,3 @@ atcbConfig.deleteJSON = true; | ||
// ... and generate the button on success | ||
atcb_generate(atcButtons[i], i + atcButtonsInitialized.length, atcbConfig); | ||
atcb_generate(atcButtons[parseInt(i)], i + atcButtonsInitialized.length, atcbConfig); | ||
} | ||
@@ -84,3 +86,3 @@ } | ||
if (key.charAt(0) !== "@") { | ||
atcbConfig[key] = atcbConfig.event[key]; | ||
atcbConfig[`${key}`] = atcbConfig.event[`${key}`]; | ||
} | ||
@@ -108,4 +110,4 @@ }); | ||
Object.keys(keyChanges).forEach((key) => { | ||
if (atcbConfig[keyChanges[key]] == null && atcbConfig[key] != null) { | ||
atcbConfig[keyChanges[key]] = atcbConfig[key]; | ||
if (atcbConfig[keyChanges[`${key}`]] == null && atcbConfig[`${key}`] != null) { | ||
atcbConfig[keyChanges[`${key}`]] = atcbConfig[`${key}`]; | ||
} | ||
@@ -125,3 +127,3 @@ }); | ||
// if no description or already decorated, return early | ||
if (!atcbConfig.description || atcbConfig.description_iCal) return atcbConfig; | ||
if (!atcbConfig.description || atcbConfig.descriptionHtmlFree) return atcbConfig; | ||
@@ -132,8 +134,6 @@ // make a copy of the given argument rather than mutating in place | ||
data.description = data.description.replace(/<br\s*\/?>/gi, "\n"); | ||
data.description_iCal = data.description.replace(/\[url\]/g, "").replace(/\[\/url\]/g, ""); | ||
data.description = decodeURIComponent( | ||
data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/g, | ||
encodeURIComponent('<a href="$1" target="_blank" rel="noopener">$1</a>') | ||
) | ||
data.descriptionHtmlFree = data.description.replace(/\[url\]/gi, "").replace(/\[\/url\]/gi, ""); | ||
data.description = data.description.replace( | ||
/\[url\]([\w&$+.,:;=~!*'?@#\s\-()|/^%]*)\[\/url\]/gi, | ||
'<a href="$1" target="_blank" rel="noopener">$1</a>' | ||
); | ||
@@ -153,3 +153,3 @@ return data; | ||
return requiredField.every(function (field) { | ||
if (data[field] == null || data[field] == "") { | ||
if (data[`${field}`] == null || data[`${field}`] == "") { | ||
console.error("add-to-calendar button generation failed: required setting missing [" + field + "]"); | ||
@@ -233,14 +233,14 @@ return false; | ||
!dates.every(function (date) { | ||
if (data[date].length !== 10) { | ||
if (data[`${date}`].length !== 10) { | ||
console.error("add-to-calendar button generation failed: date misspelled [-> YYYY-MM-DD]"); | ||
return false; | ||
} | ||
const dateParts = data[date].split("-"); | ||
const dateParts = data[`${date}`].split("-"); | ||
if (dateParts.length < 3 || dateParts.length > 3) { | ||
console.error( | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[date] + "]" | ||
"add-to-calendar button generation failed: date misspelled [" + date + ": " + data[`${date}`] + "]" | ||
); | ||
return false; | ||
} | ||
newDate[date] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
newDate[`${date}`] = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | ||
return true; | ||
@@ -255,12 +255,16 @@ }) | ||
!times.every(function (time) { | ||
if (data[time] != null) { | ||
if (data[time].length !== 5) { | ||
if (data[`${time}`] != null) { | ||
if (data[`${time}`].length !== 5) { | ||
console.error("add-to-calendar button generation failed: time misspelled [-> HH:MM]"); | ||
return false; | ||
} | ||
const timeParts = data[time].split(":"); | ||
const timeParts = data[`${time}`].split(":"); | ||
// validate the time parts | ||
if (timeParts.length < 2 || timeParts.length > 2) { | ||
console.error( | ||
"add-to-calendar button generation failed: time misspelled [" + time + ": " + data[time] + "]" | ||
"add-to-calendar button generation failed: time misspelled [" + | ||
time + | ||
": " + | ||
data[`${time}`] + | ||
"]" | ||
); | ||
@@ -550,3 +554,3 @@ return false; | ||
// give keyboard focus to first item in list, if not blocked, because there is definitely no keyboard trigger. | ||
// Mintd that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
// Mind that with custom atcb_action function, this might get triggered as well, if the custom function does not provide a proper value. | ||
if (keyboardTrigger) { | ||
@@ -600,2 +604,6 @@ list.firstChild.focus(); | ||
} | ||
let tmpDataDescription = ""; | ||
if (data.description != null && data.description != "") { | ||
tmpDataDescription = data.description; | ||
} | ||
if (data.location != null && data.location != "") { | ||
@@ -606,14 +614,16 @@ url += "&location=" + encodeURIComponent(data.location); | ||
// workaround to cover a bug, where, when using Google Calendar on an iPhone, the location is not recognized. So, for the moment, we simply add it to the description. | ||
if (data.description == null || data.description == "") { | ||
data.description = ""; | ||
} else { | ||
data.description += "%0A%0A"; | ||
if (tmpDataDescription != "") { | ||
tmpDataDescription += "<br><br>"; | ||
} | ||
data.description += "📍: " + data.location; | ||
tmpDataDescription += "📍: " + data.location; | ||
} | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&details=" + encodeURIComponent(data.description); | ||
if (tmpDataDescription != "") { | ||
url += "&details=" + encodeURIComponent(tmpDataDescription); | ||
} | ||
window.open(url, "_blank").focus(); | ||
tmpDataDescription += "hhh"; | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -638,6 +648,10 @@ | ||
} | ||
if (data.description != null && data.description != "") { | ||
url += "&desc=" + encodeURIComponent(data.description); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Yahoo does not support html tags in a stable way | ||
url += "&desc=" + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -669,5 +683,8 @@ | ||
if (data.description != null && data.description != "") { | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "%0A")); | ||
url += "&body=" + encodeURIComponent(data.description.replace(/\n/g, "<br>")); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -694,7 +711,10 @@ | ||
} | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
// using description_iCal instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.description_iCal); | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
// using descriptionHtmlFree instead of description, since Teams does not support html tags | ||
url += "&content=" + locationString + encodeURIComponent(data.descriptionHtmlFree); | ||
} | ||
window.open(url, "_blank").focus(); | ||
if (atcb_secure_url(url)) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
window.open(url, "_blank").focus(); | ||
} | ||
} | ||
@@ -723,5 +743,6 @@ | ||
); | ||
if (data.description_iCal != null && data.description_iCal != "") { | ||
if (data.descriptionHtmlFree != null && data.descriptionHtmlFree != "") { | ||
ics_lines.push( | ||
"DESCRIPTION:" + data.description_iCal.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
"DESCRIPTION:" + | ||
data.descriptionHtmlFree.replace(/\n/g, "\\n").replace(/.{60}/g, "$&" + "\r\n ") // adjusting for intended line breaks + making sure it does not exceed 75 characters per line | ||
); | ||
@@ -753,2 +774,3 @@ } | ||
else if (!!window.ActiveXObject && document.execCommand) { | ||
// eslint-disable-next-line security/detect-non-literal-fs-filename | ||
const _window = window.open(dlurl, "_blank"); | ||
@@ -842,2 +864,11 @@ _window.document.close(); | ||
function atcb_secure_url(url) { | ||
if (url.match(/((\.\.\/)|(\.\.\\)|(%2e%2e%2f)|(%252e%252e%252f)|(%2e%2e\/)|(%252e%252e\/)|(\.\.%2f)|(\.\.%252f)|(%2e%2e%5c)|(%252e%252e%255c)|(%2e%2e\\)|(%252e%252e\\)|(\.\.%5c)|(\.\.%255c)|(\.\.%c0%af)|(\.\.%25c0%25af)|(\.\.%c1%9c)|(\.\.%25c1%259c))/gi)) { | ||
console.error("Seems like the generated URL includes at least one security issue and got blocked. Please check the calendar button parameters!"); | ||
return false; | ||
} else { | ||
return true; | ||
} | ||
} | ||
if (isBrowser()) { | ||
@@ -844,0 +875,0 @@ // Global listener to ESC key to close dropdown |
{ | ||
"name": "add-to-calendar-button", | ||
"version": "1.9.0", | ||
"version": "1.9.1", | ||
"engines": { | ||
@@ -72,2 +72,3 @@ "node": ">=12.22.0" | ||
"eslint-plugin-commonjs": "^1.0.2", | ||
"eslint-plugin-security": "^1.5.0", | ||
"grunt": ">=1.5.3", | ||
@@ -74,0 +75,0 @@ "grunt-contrib-clean": "^2.0.0", |
@@ -7,8 +7,8 @@ # Your next Add-to-Calendar Button | ||
![#1 Product of the Day on ProductHunt](https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=319458&theme=dark&period=daily) | ||
[![#1 Product of the Day on ProductHunt](https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=319458&theme=dark&period=daily)](https://www.producthunt.com/products/add-to-calendar-button-generator) | ||
![Code Quality](https://img.shields.io/codacy/grade/5c7c0bac087c4dfdb0669e8284f0459a/main?style=for-the-badge) | ||
![Build Status](https://img.shields.io/github/workflow/status/jekuer/add-to-calendar-button/Node.js%20Package?style=for-the-badge) | ||
![npm Downloads](https://img.shields.io/npm/dt/add-to-calendar-button?label=npm%20Downloads&style=for-the-badge) | ||
![jsDelivr npm Hits](https://img.shields.io/jsdelivr/npm/hm/add-to-calendar-button?label=jsDelivr%20npm%20hits&style=for-the-badge) | ||
[![Code Quality](https://img.shields.io/codacy/grade/5c7c0bac087c4dfdb0669e8284f0459a/main?style=for-the-badge)](https://app.codacy.com/gh/jekuer/add-to-calendar-button/dashboard) | ||
[![Build Status](https://img.shields.io/github/workflow/status/jekuer/add-to-calendar-button/Node.js%20Package?style=for-the-badge)](https://github.com/jekuer/add-to-calendar-button/actions/workflows/npm-publish.yml) | ||
[![npm Downloads](https://img.shields.io/npm/dt/add-to-calendar-button?label=npm%20Downloads&style=for-the-badge)](https://www.npmjs.com/package/add-to-calendar-button) | ||
[![jsDelivr npm Hits](https://img.shields.io/jsdelivr/npm/hm/add-to-calendar-button?label=jsDelivr%20npm%20hits&style=for-the-badge)](https://www.jsdelivr.com/package/npm/add-to-calendar-button) | ||
@@ -53,3 +53,3 @@ <br /><br /> | ||
1. Check whether you are looking at the original and therefore up-to-date code at ![github.com/jekuer/add-to-calendar-button](https://github.com/jekuer/add-to-calendar-button). | ||
1. Check whether you are looking at the original and therefore up-to-date code at [github.com/jekuer/add-to-calendar-button](https://github.com/jekuer/add-to-calendar-button). | ||
2. **Download** the code directly from GitHub **or clone** the git repository. | ||
@@ -64,3 +64,3 @@ 3. Copy the css (atcb.min.css) and js (atcb.min.js) files from the assets (not the "npm_dist"!) folders into your project (the **.min.** files are required, but it is recommended to also copy the raw and map files). | ||
1. Instead of downloading the files, you can use the jsDeliver CDN. | ||
2. Put `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.9.0/assets/css/atcb.min.css">` into the <head> and `<script src="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.9.0" defer></script>` into the <body> footer of your website. Leave out the patch number at the version ("1.9" instead of "1.9.2") to automatically pull the latest patched version. See ![jsDeliver.com](https://www.jsdelivr.com/features#npm) for more options. | ||
2. Put `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.9.1/assets/css/atcb.min.css">` into the <head> and `<script src="https://cdn.jsdelivr.net/npm/add-to-calendar-button@1.9.1" defer></script>` into the <body> footer of your website. Leave out the patch number at the version ("1.9" instead of "1.9.2") to automatically pull the latest patched version. See [jsDeliver.com](https://www.jsdelivr.com/features#npm) for more options. | ||
3. Create your button as can be seen in the "Configuration" section below. | ||
@@ -265,3 +265,3 @@ 4. Done. And this setup also automatically keeps track of any bug fixes and minor updates! | ||
**IMPORTANT NOTE:** Run `npm install` and `npm run build` to create the minified js and css file, its sourcemap files as well as the npm_dist/ folder and content! | ||
**IMPORTANT NOTE:** Run `npm install`, `npm format`, and `npm run build` to auto-lint, create the minified js and css files, its sourcemap files as well as the npm_dist/ folder and content! | ||
@@ -278,2 +278,3 @@ <br /> | ||
- v1.9 : big code style update + linter setup | ||
- v1.8 : new button style | ||
@@ -280,0 +281,0 @@ - v1.7 : new code structure and options + tons of optimizations |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
215198
3133
312
1
16