Search code examples
javascripttampermonkeyuserscripts

EventListener not firing - Dynamically create and download calendar event


I am getting the plain text of outlook calendar events and converting them to an ics for download with Tampermonkey.

The button worked when I wrote this a couple of years ago, but now it is not. I am not sure if I need to grant permissions now or if something else broke it. The button is added just fine, but I can't get the event listener to fire.

// .....
// @grant        none
//=====    convert text only calendar to a donwloadable ICS file
elementReady('#desc-content').then((element) => {
  //grab the relevant text
  if (element.innerHTML.includes("BEGIN:VCALENDAR")) {
    //clean up some bit
    var calendar = element.innerHTML.substring(0, element.innerHTML.length - '<div class="clearfix"></div>'.length).replace(/<br\s*[\/]?>/gi, '\n');
    //Create a button element 
    var CalendarEventButton = document.createElement("button");
    CalendarEventButton.innerHTML = 'Download Calendar Event';

    CalendarEventButton.addEventListener("click", function() {
      var filename = "CalendarInvite.ics"; //File name that will be downloaded
      download(filename, calendar); //passing in the file name and text to be downloaded
    }, false);

    element.appendChild(CalendarEventButton); //append the button to the document
  }
});


/* Download an embedded file/text*/
function download(file, text) {

  //creating an invisible element
  var element = document.createElement('a');
  element.setAttribute('href',
    'data:text/calendar;charset=utf-8, ' +
    encodeURIComponent(text));
  element.setAttribute('download', file);

  // Above code is equivalent to
  // <a href="path of file" download="file name">

  document.body.appendChild(element);

  //onClick property
  element.click();

  document.body.removeChild(element);
}

Solution

    1. Used const (ES2015+) instead of var (<= ES5).
    2. Cloned the element in order to remove the div.clearfix in a more reliable way.
    3. Used template strings (`....`).
    4. Used native GM_download method for easier/reliable downloading.
    // .....
    // @grant        GM_download
    //=====    convert text only calendar to a donwloadable ICS file
    elementReady('#desc-content').then((element) => {
      // grab the relevant text
      const cloned = element.cloneNode(true);
    
      if (!cloned.innerText.includes("BEGIN:VCALENDAR")) return;
    
      // clean up some bit
    
      // use the cloned element so that removing clearfix div
      // won't affect DOM
      cloned.querySelector('.clearfix')?.remove();
      const calendar = cloned.innerHTML.replace(/<br\s*[\/]?>/gi, '\n');
    
      // Create a button element 
      const calendarEventButton = document.createElement("button");
      calendarEventButton.innerHTML = 'Download Calendar Event';
    
      calendarEventButton.addEventListener("click", function() {
        const filename = "CalendarInvite.ics"; // File name that will be downloaded
    
        download(filename, calendar); // passing in the file name and text to be downloaded
      }, false);
    
      element.appendChild(calendarEventButton); //append the button to the document
    });
    
    
    /* Download an embedded file/text*/
    function download(file, text) {
      const encoded = encodeURIComponent(text);
      const downloadable = `data:text/calendar;charset=utf-8, ${encoded}`;
    
      GM_download(downloadable, file);
    }