Fullcalendar scheduler v5 auto refresh events - json

Is it possible to 'push' new events to fullcalendar scheduler without page refresh?
My source for events is JSON feed. So I would like a new event to appear in the calendar once another user enters it. There should be a listener/webhook to the json feed and if recognizes a change in the data, it should trigger calendar to refetch events.
Is something like this possible?
I found a way to do it:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var source = new EventSource('sse.php')
source.addEventListener('message', function(e) {
//console.log(e.data);
if (e.data != 'doNotUpdate'){
calendar.refetchEvents();
}
}, false);
}
However, the sse.php, which is the script running on server and checks for new events in database table, is probably being triggered every second or every few seconds and returning doUpdate or doNotUpdate. I am not sure if this is ok? To many requests on MySQL? Should I set it up differently?

Related

Run server-side code with google chart select

I have a google visualization table that I'm publishing in a web app.
Background:
I run a script that lists all the documents in a google folder in a spreadsheet. I then push that list into the google table I have published in the web app.
The need:
I want to manage those that same list of documents directly from the web app. I want to be able to to move the document from one folder to another when I select the applicable row on the table.
Two things I have accomplished:
I have a script that will move the document to a specific folder on
the google drive using it's doc id.
I have an event listener on the table so that when you click a row and
then click the delete icon, you get a prompt that asks, "are sure
you want to archive [enter document name]?" When I click ok, I get my
test prompt that says "document archived". When I click no, I get my
test prompt that says "request cancelled". So from this, I know I
have the appropriate code (at least that's how it seems).
What I'm struggling with:
I can't seem to get the codes above to work together. The event listener is providing me the url of the document which I have parsed to give me only the id. This is what I was hoping to use to get the rest of the code to run, but I think because I'm trying to interact with the server-side from the client-side, it's not working. Can anyone help me figure it out? I know that I need to use google.script.run.withSuccessHandler when running a server side script from the client side, but I don't know how it applies to this case the docid I need is being collected on table select. Any help is appreciated and I hope the above makes sense!
// Draw Dashboard
h2dashboard.bind([h2stringFilter, h2typeFilter], [h2chart]);
h2dashboard.draw(h2dataView);
google.visualization.events.addOneTimeListener(h2chart, 'ready', function() {
google.visualization.events.addListener(h2chart.getChart(), 'select', function() {
var selection = h2chart.getChart().getSelection();
var dt = h2chart.getDataTable();
// Get Value of clicked row
if (selection.length) {
var item = selection[0];
var docurl = dt.getValue(item.row, 1);
var docname = dt.getValue(item.row, 0);
var source = dt.getValue(item.row, 3);
// When button is clicked, show confirm box with value
$(document).ready(function() {
$("#hu2archive").on("click", function() {
var answer = confirm("Are you sure you want to archive " + docname + "?");
if (answer === true) {
var archive = DriveApp.getFolderById("FOLDER ID");
var docid = docurl.match(/[-\w]{25,}/); // This is where I'm grabbing the value from the row.
var doc = DriveApp.getFileById(docid);
doc.makeCopy(archive).setName(doc.getName());
source.removeFile(doc);
alert(docname + " has been archived!");
} else {
alert("Request cancelled");
}
});
});
}
});
});
I just got it! What I was having a hard time understanding was how to pass a variable from the client side to code.gs. I have only run a script in code.gs from the client side on button submit but never passed anything back.
So I ended up changing my code to the below which passes the variable I need into a successhandler where archiveDoc is the function in my code.gs and docurl is the name of the variable I need to pass from the eventlistener.
if (answer === true) { google.script.run.withSuccessHandler(onSuccess).withFailureHandler(err).archiveDoc(docurl);
I'm still new to coding so I just learned something new! So thanks Spencer Easton. I did in fact answer my own question.

Calendar script adding guests but not sending an invite

I have a prototype script that is designed to add a guest to a calendar event. It adds them to the event just fine, but it does not trigger an invite. Could someone point me in the right direction to what's missing?
function addToEvent() {
var guest = "you#gmail.com";
var calendar = 'pbekisz#keuka.edu';
var event = "33l5k7p5qocdprt5j2c9nhbhl8";
var cal = CalendarApp.getCalendarById(calendar);
var theEvent = cal.getEventSeriesById(event);
theEvent.addGuest(guest);
}
addToEvent();
The CalendarApp documentation indicates that invitations can be sent when the event is created. Because the addGuest method does not include any indication as to how one might send the invitation, it appears that this functionality is currently limited to the time of event creation.
As a work around, you can continue with your prototype, and email your new guest(s) that they have been invited and that it should be appearing on their calendar. Alternatively, you could create a new event with your new guest(s) and send the invitation, then add the existing guests with their statuses from your original event, and then remove the original event.
Edit
As I was looking in to this further, I came across an old thread on google-apps-scripts-issues where they found the advanced Calendar API service could be used to achieve what you are trying to accomplish:
function sendInvite(calendarId, eventId, email) {
var event = Calendar.Events.get(calendarId, eventId);
event.attendees.push({
email: email
});
event = Calendar.Events.patch(event, calendarId, eventId, {
sendNotifications: true
});
}

Inviting guests to a "Quick Add" Google Calendar event

I am trying to improve the functionality of the "Quick Add" feature in Google Calendar. Quick Add is the feature that is normally accessed by going to Google Calendar and clicking the down arrow next to the red "Create" button (see image: http://s2.postimg.org/95zxshivt/calendar_screenshot.png).
The functionality I am trying to achieve is to allow the user to invite guests to the newly created Calendar event using keywords in what they type in the Quick Add box. For example, if the user uses the Quick Add box to add an event by entering the text Eat pizza tomorrow at 3pm with michelle#gmail.com and john#gmail.com, Google Calendar adds a new event with the title Eat pizza with michelle#gmail.com and john#gmail.com at 3pm the next day, like it is supposed to. I want to go a step further by having Google also send out two Calendar invites to the newly created event: one for michelle#gmail.com and the other to john#gmail.com.
I appreciate your advice on this topic. I am trying to understand what the best approach is:
Use a trigger with Google Apps Script to catch when the user has added a Calendar event. The trigger will access the title of the event, pick out any e-mail addresses present in the title, and send an invitation to the newly created event to each of those e-mail addresses.
Use a Chrome extension to have the user enter the string that they normally would type into the Quick Add box by clicking on the extension's icon in the Chrome browser. The extension would pick the e-mail addresses out of what the user types in, use createEventFromDescription(description) on the user's input to create the event, and then send an invitation to the newly created event to each of those e-mail addresses.
Please let me know what you think. I would greatly appreciate your ideas.
Lucy
As you probably know, there is not trigger source linked to the creation of an event from the Calendar Ui.
You have indeed 2 possibilities :
encode the event using a dedicated Ui (a chrome extension or a standalone webapp) that would take care of sending the invitations but that would probably not meet the initial requirement you described as "expanding the capabilities os the quickAdd features"
Find a way to detect an event creation and automatically send invitations from its content.
This last possibility is perfectly doable using a timer trigger that monitors your calendar and detects any new event (by comparing a list stored somewhere to the actual calendar content).
I have made such an app for a different purpose and it works nicely but there are a few difficulties you should be aware of.
When storing the events in scriptProperties (it's probably the best place to go) you have a limited amount of storage size available so you must know how much event you will be able to handle.
Any change in an event like adding a detail or rectifying a typo will re-trigger the invitation process and send the invitation again. Although this can probably be avoided but it would be quite complex.
When the script runs right after an event end, the comparison detects an change because one event is missing (from the script pov) so it could send a mail to cancel the event (if you had chosen to implement that functionality of course but I guess it's a "must have"). It might be a bit tricky to handle that situation... (compare event end time to actual time when the trigger fires the script, could be a matter of milliseconds ;-).
Apart from these difficulties, the general idea is as follow :
create a timer trigger to run every hour or so
store every event in this calendar in script Properties (or eventually in a spreadsheet) starting from the present date and ending in a few days (not too far ahead because it wouldn't make sense to send invites for an event happening next year)
compare the list with the calendar content
grab every "new" events and extract email address from the description (using regex for example or string manipulation)
send the invitations (that's the easy part)
This workflow works but it might be a bit fragile in the comparison and in the email detection.
EDIT
Since this was an interesting subject (IMHO) and that I thought I could use efficiently (now that I switched to english in my calendar UI ;-D) I wrote a code to achieve it...
I embedded the code in a spreadsheet to simplify the processsing and the storage of the events in the many calendars I own.
This spreadsheet is viewable here and if you make a copy of it you'll be able to run the code.
I setup a timer trigger that runs the autoCheckAllCal function every hour and it seems to work without any issue.
Tell me what you think.
The full code is reproduced below, it gets data from the calendar, checks if the event has guests and if not it checks the title for any valid email address (one or more) and sends the invitations automatically.
I used a regex to extract emails from the title string (this regex was borrowed from an answer on SO since I'm not good enough at this !)
note : setup an onOpen trigger for myOnOpen (because of global var declaration using SS service)
// update the ID below to your copy ID and run the Callist() function to get the calendars ID on first sheet.
//set up an onOpen trigger for the myOnOpen function
var ss = SpreadsheetApp.openById('1xDOaoSl3HbkS95cj8Jl-82rdiui7G0sFz96PIO6iVF4');// this spreadsheet
var calNamesSheet = ss.getSheetByName('calNames');
var calList = calNamesSheet.getDataRange().getValues();
function MyOnOpen() {
var menuEntries = [ {name: "Lauch autoTest", functionName: "autoCheckAllCals"},
{name: "delete created sheets", functionName: "delsheets"}
];
ss.addMenu("Tracking utilities",menuEntries);//
}
function autoCheckAllCals(){
var today = new Date(); // now
var startDate = new Date(today.setHours(0,0,0,0));// today # 0 AM
var endDate = new Date(new Date(startDate).setDate(startDate.getDate()+7)); // adjust time frame to read here = 7 days
for(var nn=0;nn<calList.length;nn++){
var logArray = new Array();
logArray.push(['Calendar + Title','Description','Start','End','Location','Creators','Date Created','Duration','Guests']);
var calName = calList[nn][0];
var calId = calList[nn][1];
var Calendar = CalendarApp.getCalendarById(calId);
var events = Calendar.getEvents(startDate , endDate);
if (events[0]) {
for (var i = 0; i < events.length; i++) {
var row = new Array();
row.push(calName +' : '+events[i].getTitle());
row.push(events[i].getDescription());
row.push(Utilities.formatDate(events[i].getStartTime(), Session.getScriptTimeZone(), "MMM-dd-yy")+' # ' +Utilities.formatDate(events[i].getStartTime(), Session.getScriptTimeZone(), "HH:mm"));
row.push(Utilities.formatDate(events[i].getEndTime(), Session.getScriptTimeZone(), "MMM-dd-yy")+' # ' +Utilities.formatDate(events[i].getEndTime(), Session.getScriptTimeZone(), "HH:mm"));
row.push(events[i].getLocation());
row.push(events[i].getCreators().join());
row.push('on '+Utilities.formatDate(events[i].getLastUpdated(), Session.getScriptTimeZone(), "MMM-dd-yyyy"));
row.push(((events[i].getEndTime() - events[i].getStartTime()) / 3600000)+' hours');//duration
var inviteList = checkInvites(events[i]);
if (inviteList.length==0){ // if guests were found in checkInvites() then don't read it from event since checkInvites() added them to the cal but this event is not yet updated
var list = events[i].getGuestList();
for(n=0;n<list.length;++n){inviteList.push(list[n].getEmail())};
}else{
for(var n in inviteList){
events[i].addGuest(inviteList[n]);
}
}
row.push(inviteList.join(', '));
logArray.push(row);
}
}
// Logger.log(logArray);
if(logArray.length==0){continue};
try{
var sheetToWrite = ss.insertSheet(calName,ss.getNumSheets());// create sheet if doesn't exist
}catch(err){
var sheetToWrite = ss.getSheetByName(calName);// else open it
}
sheetToWrite.getRange(1,1,logArray.length,logArray[0].length).setValues(logArray).setHorizontalAlignment('left'); // enhance formating
sheetToWrite.getRange(1,1,1,logArray[0].length).setBackground('#EEA').setBorder(true,true,true,true,true,true).setHorizontalAlignment('left').setFontSize(12);
for(var w in logArray[0]){
sheetToWrite.setColumnWidth(Number(w)+1,180);
}
}
}
function checkInvites(event){
var email = []
var title = event.getTitle();
if(title.indexOf('#')==-1){return email};
email = title.match(/([\w-\.]+)#((?:[\w]+\.)+)([a-zA-Z]{2,4})/g);
Logger.log('email var = '+email);
return email;
}
function delsheets(){
var numbofsheet = ss.getNumSheets();// check how many sheets in the spreadsheet
for (var pa=numbofsheet-1;pa>0;pa--){
ss.setActiveSheet(ss.getSheets()[pa]);
if(ss.getSheets()[pa].getSheetName()!='calNames'){
ss.deleteActiveSheet(); // delete sheets begining with the last one
Utilities.sleep(400);
}
}
SpreadsheetApp.flush();
}
// This small function is to get the list of calendar names & Ids that you have access to, please edit the calNames sheet to keep only the ones you want to monitor (without empty rows).
function Callist(){
calNamesSheet.getDataRange().clearContent();
var list = new Array();
var store = new Array();
list = CalendarApp.getAllCalendars()
for (n=0;n<list.length;++n){
var name = list[n].getName() ;
var id = list[n].getId() ;
store.push( [name,id])
}
calNamesSheet.getRange(1,1,store.length,store[0].length).setValues(store);
}
// Serge insas - 08-2014

Is delete function is depreciated in HTML5 indexed database API

HI I am trying to delete a record in indexed database by passing its id, but my the function is not working properly and even Visual Studio intellisence is not showing any such function. Is objectstore.delete() function of the indexed database API has been depreciated or I am doing something wrong in calling it.
Following is the code spinet
var result = objectStore.delete(key);
result.onsuccess = function() {
alert('Success');
};
The delete by key function is working fine in all browsers Chrome, FF and IE10. Here is the sample code:
var connection = indexedDB.open(dbName);
connection.onsuccess = function(e) {
var database = e.target.result;
var transaction = database.transaction(storeName, 'readwrite');
var objectStore = transaction.objectStore(storeName);
var request = objectStore.delete(parseInt(key));
request.onsuccess = function (event)
{
database.close();
};
}
Almost everything in IndexedDB works the same way, and your question belies a misunderstanding of this model: everything happens in a transaction.
Almost nothing is syncronous in the IndexedDB API except opening the database. So you'll never see anything like database.delete() or database.set() when dealing with records.
To delete a record, as with getting or setting, you start by creating a new transaction on the database. You then use that transaction (like in Deni's example) to invoke the method for your change.
The transaction then "disappears" when it goes out of scope of all functions and your change is then committed to the database. It's on this transaction's reference to the database (not the database itself) that you hook event listeners such as success and error callbacks.

Improve my script run time

Is there anyway to improve my script run time? I have a script that creates 2 listboxes: Listbox1 items is all my google site pages, listbox2 items is the sub-pages of listbox1 page. The script runs fine but sometimes it takes between 2 and 5 seconds to get all of the listbox2 items.
You can try my script here.
And here is my script:
function doGet()
{
var app = UiApp.createApplication();
//GUI with 2 listbox
//Listbox1: onclick > lbox1onclick(e), onchange > lbox1onchange(e)
app.add(app.loadComponent("MyUrlParser"));
var lbox1 = app.getElementById('ListBox1');
lbox1.addItem(' ');
var lbox1_Item = SitesApp.getSite('phichdaica').getChildByName('manga').getChildren();
for(var i = lbox1_Item.length-1; i >= 0; i--)
{
lbox1.addItem(lbox1_Item[i].getTitle());
}
return app;
}
function lbox1onclick(e)
{
var app = UiApp.getActiveApplication();
var lbox2 = app.getElementById('ListBox2');
lbox2.clear();
return app;
}
function lbox1onchange(e)
{
var app = UiApp.getActiveApplication();
// var value = e.parameter.lbox1;
var lbox1value = e.parameter.ListBox1;
var lbox2 = app.getElementById('ListBox2');
var lbox2_Item = SitesApp.getSite('phichdaica').getChildByName('manga').getChildByName(lbox1value).getChildren();
for(var i=lbox2_Item.length-1; i >= 0; i--)
{
lbox2.addItem(lbox2_Item[i].getTitle());
}
return app;
}
I don't think it will speed up the process but you could use just one handler function to do that : on change listBox1, clear listBox 2 and re-populate it immediately. What is taking some time is the call to site's content so the difference might not be significative but the 'logic' of your script would be improved ;-)
Looking at your page, I see that listBox 2 is never cleared... is that a temporary issue ? Did you change something recently ?
Also, what is supposed to happen when something is selected in listBox2 ?
EDIT : following your comment, if you want to improve user experience concerning the 'responsiveness' of your UI the best way is to use client handlers to trigger the visibility of a 'wait message' for example(something like "Updating the list"). I usually use an animated gif that I made visible with a client handler and that is made invisible again when the server handler returns (ie I set it invisible in the server handler function).
here is a working example, just try to change the date in the upper right corner.