Is there a way to save a calendar entry by javascript to personal outlook-calendar within a sharepoint-calendar webpart ?
I want to save a created Entry in a sharepoint-calendar direkt to the personal outlook calendar of the user created it.
Any tip how to do this ?
So, the answer is "kind of".
You technically don't have to write JavaScript to achieve this, as SharePoint has a built in service URL that will download an .ICS file to the user's machine, and whatever that user's default calendaring system (e.g. Outlook) will open that as a new Calendar item.
Although you can construct this link manually if you want to provide a calendar item download for one specific Event, you can certainly use JavaScript to dynamically fill in the parameter values in this URL, which may be easier that having to look up these values individually to manually construct a link.
The URL that you can provide a hyperlink to generate an .ics file is
https://**SITE_URL**/_vti_bin/owssvr.dll?CS=109&Cmd=Display&List={**LIST_GUID**}&CacheControl=1&ID=**EVENT_ID**&Using=event.ics
SITE_URL – The URL to the site where the calendar is hosted
LIST_GUID – The (guid) unique identifier of your calendar list
EVENT_ID – The (integer) ID of the calendar event
for example:
https://mysharepointserver/sites/myteamsite/_vti_bin/owssvr.dll?CS=109&Cmd=Display&List={B2E3EC57-9BA6-46A2-B072-578C9796A42E}&CacheControl=1&ID=26&Using=event.ics
As an example of who you can use JavaScript to generate this link per event, the following code can be put in a Script Editor WebPart on the same page as a Calendar View Web Part, and it will insert a down arrow character in front of every event link that will trigger the .ics file for that event. This script assumes you have the jQuery library already loaded on your page, and you will need to replace the string "NameOfYourEventsList" below with the actual title of your Events list.
function lookupListBeforeAppendingCalendarLink() {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
list = web.get_lists().getByTitle("NameOfYourEventsList");
context.load(list, 'Id');
context.executeQueryAsync(Function.createDelegate(this,listIdSuccess), Function.createDelegate(this,error));
}
function listIdSuccess() {
var listId = list.get_id();
appendAddToCalendarLink(listId);
}
function error(sender, args) {
console.log('Request failed. ' + args.get_message() +
'\n' + args.get_stackTrace());
}
function appendAddToCalendarLink(listId) {
jQuery('.ms-acal-rootdiv .ms-acal-item').each(function () {
var currentCalendarAnchor = jQuery('a', jQuery(this));
var itemId = currentCalendarAnchor.attr('href').split('?ID=')[1];
currentCalendarAnchor.before("<a href='" + _spPageContextInfo.webServerRelativeUrl + "/_vti_bin/owssvr.dll?CS=109&Cmd=Display&List=" + listId + "&CacheControl=1&ID=" + itemId + "&Using=event.ics'>↓</a>");
});
}
function customizeCalendar() {
//if you know the list id, you can hard code it here,
// otherwise use function to look it up first by List title
// var listId = 'B2E3EC57-9BA6-46A2-B072-578C9796A42E'
// appendAddToCalendarLink(listId);
lookupListBeforeAppendingCalendarLink();
}
ExecuteOrDelayUntilScriptLoaded(customizeCalendar, "sp.js")
Related
I inherited this project and am trying to correct a few bugs. This particular issue deals with the user double clicking a box in a form(built in conveyor_maint.php), then picking a value in a window that pops up (getPartNumber.php) and then having that value pass back down the form. It successfully pushes the value into the clipboard, but I cannot figure out how to get the value to go back to the form. I would like it to update the form each time the user picks a value in the popup window, but could have it only update upon closure of the popup window too.
Here are the details:
The table is in conveyor_maint.php
<th> Override Head Tail </th>
<td><input type="text" name="cd_headtail_ovrd" value="$cd_headtail_ovrd" size="20"
ondblclick="getPartNumber('cd_headtail_ovrd','desc_htail_ovrd','TAIL');"
title="DOUBLE CLICK to display a list of tails you may select from. This will override the calculated head tail when choosing BOM data. YOu may leave this field blank.">
<input type="display" name="desc_htail_ovrd"
value="$desc_htail_ovrd" size="30" readonly></td></tr>
When the block is double clicked, it runs the javascript function getpartNumber, from the included file javascript.php
<script language="javascript">
function getPartNumber(field1, field2, filter) {
var user = '$user_login'
var url = 'getPartNumber.php?user_login=' + user + '&filter=' + filter + '&field1=' + field1 + '&field2=' + field2
window.open(url,'Get_Part_Number','height=700,width=900,scrollbars=yes')
getClipboardContents(field1, field2);
}
async function getClipboardContents(field1, field2) {
try {
const text = await navigator.clipboard.readText();
console.log('Pasted content: ', text);
var partarray = text.split("!")
var partno = partarray[0]
var partdesc = partarray[1]
if (text != "") {
window.document.forms[0].elements[field1].value = partno
window.document.forms[0].elements[field2].value = partdesc
}
} catch (err) {
console.error('Failed to read clipboard contents: ', err);
}
}
</script>
The javascript launches the window.open command to open the pop-up GetPartNumber.php
GetPartNumber.php builds a table which the user selects the value to be pushed back to the original form.
It relies on a state_change to push the value into the clipboard:
function state_Change() {
if (xmlhttp.readyState==4) {
if (xmlhttp.status==200) {
myhtml = xmlhttp.responseText;
var dataarray = myhtml.split("~");
var retdata = dataarray[1];
navigator.clipboard.writeText(retdata);
} else {
alert("Problem retrieving XML data:" + xmlhttp.statusText)
}
}
}
This works, as I click the different choices in the popup, they can be pasted into a text file correctly.
Now, this used to work with the following code, but upgrades to the server and related software broke it.
Each time a choice is made in the pop-up, it runs SelectPart()
function SelectPart(partno, user_login) {
window.document.curform.partno.value = partno;
var url = 'getPartData.php?partno=' + partno + '&user_login=' + user_login;
loadXMLDoc(url)
}
Subsequently, getPartData.php runs and echoes the same data I pushed to the clipboard.
I am trying to get rid of the selectPart() and the subsequent code, unless it turns out to be easier to fix.
The fundamental issue I have is that when the javascript.php runs, it opens the window for the selection and the javascript then completes, reading the clipboard and pushing it to the form (while the popups is still open and the user is making their choice). Subsequent selections, change the clipboard, but they don’t get read until I rerun the popup. I need a way to run the async function which reads the clipboard, either with each selection in the popup, or upon closure of the popup window.
I have tried a variety of things including moving the code to other places, global variables (yuck), and other methods to solve it, so I am hoping for a solution to the original problem.
After a bit of digging, I got rid of the clipboard copy and paste entirely.
Using some standard Javascript between a parent and a child window, I updated the code in the child to reference the parent table directly and dynamically pulling the field names and content from an array:
opener.document.curform[results[2]].value = results[0]
opener.document.curform[results[3]].value = results[1]
for some more information, check out this link: https://www.plus2net.com/javascript_tutorial/window-child3.php
This question already has an answer here:
Google app script only updates document's changes after finishing running. Can I force it to refresh before?
(1 answer)
Closed 2 years ago.
I have created a script that is triggered after button click on android app.
The script I've written gets a Google Docs Template and creates a copy of it to edit it afterwards.
After being edited i want to send an email to the email that will be inserted in the app.
The email should include the body, the subject and the file attached as pdf.
I've achieved to send the email with the pdf in it but it sends the copy of the Template without being edited.
Any suggestions to solve this problem?
Here's my code:
//Make a copy of the template file
var templateID = DriveApp.getFileById('My Template ID').makeCopy().getId();
//Rename The copied file
DriveApp.getFileById(templateID).setName(codigOperari + " - " + numero + " - " + operari + " - " + cliente + " - " + data);
//Get the document body as a variable
var doc = DocumentApp.openById(templateID);
var body = doc.getBody();
//Edit the copy of the template
body.replaceText('<<C>>', codigOperari);
body.replaceText('<<NUMPARTE>>', numero);
body.replaceText('<<FECHA>>', data);
body.replaceText('<<CLIENTE>>', cliente);
body.replaceText('<<CORREO>>', e.parameter.ETEmail);
body.replaceText('<<ORDENTRABAJO>>', e.parameter.ETMotiu);
body.replaceText('<<OPERARIO>>', operari);
//A lot of data more
//Message to be sent
var message = {
to: e.parameter.ETEmail,
subject: "Subject",
body: "This is a Test",
name: "Name",
attachments: [DocumentApp.getActiveDocument().getAs(MimeType.PDF)
.setName(codigOperari + " - " + numero + " - " + operari + " - " + cliente + " - " + data)]
}
//Send Email
MailApp.sendEmail(message);
I wrote you a comment as well, but I believe your issue is that you're sending the ActiveDocument and not the document that was edited.
DocumentApp.getActiveDocument() will only ever return the document the script is "anchored" to. If you open up a Google Doc or Spreadsheet, go to the Tools menu, and click Script Editor, you will be given an Apps Script file that is bound to your Google Doc. You can access the document directly in this Apps Script ONLY with DocumentApp.getActiveDocument(). Trying to edit this Google Doc from anywhere else will require the DocumentApp.openById() method.
My guess is that once you ran var body = DocumentApp.openById(templateID) you thought that you actually opened the document and activated it, which lead you to think that all you had to do was attach the "active document". This is wrong though, as you will only ever be attaching the source document. I'm assuming this is the template.
You already have the solution though. The document you're trying to send is stored in the doc variable. var doc = DocumentApp.openById() gives you a variable that points to that spreadsheet indefinitely. You can access this document through this variable at any point (you do so right afterwards with the var body = doc.getBody() statement.
Let me know if this fixed it!
I am very new to javascript and I have setup a web page to retrieve sensors that provide data from sensors, however I also push the values from sensor to mysql database. So I have made a button on the web page that displays a live button liveBtn and and a database button dbBtn based on which button is visible URL is set to either retrieve json from mysql or live from sensors. I want to know which of the below is better approach to set the URL:
by default in HTML page I have made database button dbBtn hidden and liveBtn live button visible.
1st
hostName = window.location.hostname;
function urlSwitcher(){
if ($('#dbBtn:not(:visible)')) {
url ="http://" + hostName + "/arduino/directEncode.php";
} else
{
url = 'http://' + hostName.replace("192.168.1.3", "192.168.1.156"); + ':8095/json';
}
return url;
}
// or the 2nd one.
function urlSwitcher(){
var liveBtn = document.getElementById("liveBtn");
if (liveBtn.style.display !== 'none') {
url ="http://" + hostName + "/arduino/directEncode.php";
} else {
url = 'http://' + hostName.replace("192.168.1.3", "192.168.1.156") + ':8095/json';
}
}
I want to know how should I put or what should I have setup that it executes correctly on the page load. So once the page is loaded URL is available for ajax call.
I have the following code as a Google Apps Script (deployed as a web app) and have inserted it into my Google Enterprise page as a Google Apps Script Gadget. The UI (panel) loads properly with the label, textBox and button, but when I enter in text and click the button, I get the following error:
Error encountered: The resource you requested could not be located.
Here is my script:
function doGet(e) {
// create all UI elements
var myApp = UiApp.createApplication();
var panel = myApp.createVerticalPanel();
var label = myApp.createLabel('Please enter the name of your new site:');
var textBox = myApp.createTextBox().setName('txtSiteName');
var button = myApp.createButton('Create Site');
var btnHandler = myApp.createServerHandler('createNewSite');
button.addClickHandler(btnHandler);
btnHandler.addCallbackElement(panel);
// add all UI elements to the panel
panel.add(label);
panel.add(textBox);
panel.add(button);
// add the panel to the app
myApp.add(panel);
// return the app to the browser to be displayed
return myApp;
}
// button server handler
function createNewSite(e) {
var domain = SitesApp.getActiveSite().getUrl();
var siteName = e.parameter.txtSiteName;
var newSite = SitesApp.createSite(domain, siteName, 'script_center_demo', "this is just a test page");
return app.close();
}
Also, what is the difference between createSite() and createWebPage()?
EDIT: Ok, so using the same doGet() function above, my createNewSite() function could look like this?
function createNewSite(e) {
var domain = 'my-domain.com';
var siteName = e.parameter.txtSiteName;
var newPage = SitesApp.createSite(domain, siteName, 'script_center_demo', "this is just a test page");
var pageName = 'script_center_demo';
var html = '<div><p>This project aims to....</p></div>';
var site = SitesApp.getSite(domain, site);
site.createWebPage('Script Center Demo', pageName, html);
return app.close();
}
Look at this line:
var domain = SitesApp.getActiveSite().getUrl();
You're need to obtain a domain, e.g. example.com, but this line will yield a URI containing google's domain, and a resource path (that contains your domain). Example:
https://sites.google.com/a/example.com/mySite/
^^^^^^^^^^^
When you attempt to create a new site, it cannot be found as a domain. You need to strip the result of getUrl() down to just the domain name.
If you're the Domain administrator, you can use this instead:
var domain = UserManager.getDomain();
Ordinary domain users don't have access to the UserManager Service, so they would need to parse the site URL to extract their domain. I suggest using parseUri by Steven Levithan to handle the task:
var uri = parseUri(SitesApp.getActiveSite().getUrl());
var domain = parseUri(uri.path.slice(3)).host;
The .slice(3) operation is intended to remove /a/ from the path property of the parsed Site URI. This works on my accounts in multiple domains today - ymmv.
After that, we treat the remaining path as a URI and invoke parseUri() again, extracting the host property, which should be our domain.
Also, what is the difference between createSite() and createWebPage()?
You create an instance of a Site, using the Sites service method SiteApp.createSite. Not much to look at, a Site object is a container, a skeleton - you use the Site.createWebPage() method to create Web Pages that will be contained in the Site, and visible to users, mainly via web browsers.
Edit - Debugging Results
Debugging WebApps is tricky. Get familiar with "View - Execution Transcript", since it will show a trace of execution for your createNewSite() handler function when it's invoked. Using that technique, here's what I found, part 1:
We can't call SitesApp.getActiveSite().getUrl() in the handler, because when it's invoked there is no active site. You're already using the simple work-around of hard-coding the domain.
When trying to get a handle on the new site, you have var site = SitesApp.getSite(domain, site);. This is where your latest "resource error" message was coming from. The site parameter is left-over from insertion of the function - it needs to be a string, matching the site name used in createSite().
You're returning app.close(), but have no app defined in the function.
With those problems fixed, here's problems, part 2:
The dialog lets users enter a site name, but there are restrictions on those that need to be followed to make createSite succeed. The simplest rule is that the site name must be lower case. Why not let users enter the site title, and derive the name from that?
What if the site already exists? That's not handled. Same thing for the page creation, later on.
There's no feedback to the user. The example below has very rudimentary status updates in it, which are appended to the UI.
updated code
function createNewSite(e) {
var app = UiApp.getActiveApplication();
var domain = 'mitel.com';
var siteTitle = e.parameter.txtSiteName;
var siteName = siteTitle.toLowerCase();
var result = 'Results: ';
var site = SitesApp.getSite(domain, siteName); // Check if site already exists
if (site)
result += 'Site "' + siteName + '" exists, ';
else {
// Doesn't exist, so create it
site = SitesApp.createSite(domain, siteName, siteTitle, "this is just a test page");
result += 'Site "' + siteName + '" created with title "' + siteTitle + '", ';
}
var pageName = 'script_center_demo';
var html = '<div><p>This project aims to....</p></div>';
var page = site.getChildByName(pageName); // Check if page already exists
if (page)
result += 'Page "' + pageName + '" exists, ';
else {
// Doesn't exist, so create it
page = site.createWebPage('Script Center Demo', pageName, html);
result += 'Page "' + pageName + '" created, ';
}
result += 'Done.';
// Add result text to UI
var uiResult = app.createLabel(result, true);
app.add(uiResult);
return app.close();
}
I would like to use the gdata API to retrieve some event entries from a public calendar feed. Here is the code that I'm using:
var calendarService = new google.gdata.calendar.CalendarService('GoogleInc-jsguide-1.0');
var feedUri = 'http://www.google.com/calendar/feeds/.../public/basic';
var gquery = new google.gdata.calendar.CalendarEventQuery(feedUri);
gquery.setFutureEvents(true);
gquery.setMaxResults(10);
var callback = function(result) {
var entries = result.feed.entry;
for (var i = 0; i < entries.length; i++ ) {
var entry = entries[i];
var title = entry.getTitle().getText();
var times = entry.getTimes();
alert("Title: " + title + " | Times: " + times);
}
}
calendarService.getEventsFeed(gquery, callback);
(Feed URI is the public (or private) XML-Feed for a Google Apps Calendar)
I expected to find the event times in times but it is an empty array. Which is in some way logical, because the actual feed in feedUri doesn't contain any time information.
Questions:
What am I doing wrong? How to retreive calendar entries which include event times?
Why is there a method getTimes() if it's completely useless?
EDIT: I've just seen you're using the "basic" feed - have you tried the "full" feed instead? The description of the basic feed is:
Basic Atom feed without any extension
elements. Its and
properties contain
pre-rendered HTML.
Additionally, you need to be aware of single events vs recurrent events. Information about recurrent events is available via getRecurrence(). For individual events, getTimes() will give the right information.
If you don't see the information via the API, try looking at the source data directly and see whether you can see it there.