Retrieve events number from SharePoint calendar using JS - javascript

I have a SharePoint calendar list, and I'm looking for a script to retrieve the number of events on a day. For example, for today, 10 August, I want to just retrieve the number of events stored in my calendar.
Any suggestion will be very helpful.

The Problem with Querying Calendars in JavaScript: Recurrence
Ordinarily retrieving data from SharePoint with JavaScript is really straightforward (at least for versions beyond SharePoint 2007) using either REST or the JavaScript Object Model. However, calendars have functionality for creating recurring events which can complicate things.
For example, a recurring event may have a start date of two years ago and an end date many years in the future, but maybe the event itself only actually occurs on the third Tuesday of every month. If you just query the list and try to compare today's date against the start date and end date to see if they overlap, that recurring event will show up in your results (even though today is not the third Tuesday of the month).
In server-side code you can get around this by setting the ExpandRecurrence property to true on the SPQuery object used to query the list. However, as of SP2010 and SP2013, that property is not exposed on the equivalent JavaScript Object Model.
Workaround: Using the Lists.GetListItems web service**
An alternative is to use one of the old web services that are still floating around... specifically the Lists web service accessible at /_vti_bin/Lists.asmx. This web service has a GetListItems method that accepts a SOAP message in which you can specify a query option to expand recurrence as you would on the server side.
Here's an example demonstrating how you can query the Lists web service using plain JavaScript:
// Set webUrl and listGuid to values specific to your site and list
var webUrl = "http://server/sitewhereyourlistexists";
var listGuid = "{000000000-0000-0000-0000-000000000000}"
// An XMLHttpRequest object is used to access the web service
var xhr = new XMLHttpRequest();
var url = webUrl + "/_vti_bin/Lists.asmx";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type","text/xml; charset=utf-8");
xhr.setRequestHeader("SOAPAction","http://schemas.microsoft.com/sharepoint/soap/GetListItems");
// The message body consists of an XML document
// with SOAP elements corresponding to the GetListItems method parameters
// i.e. listName, query, and queryOptions
var data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<GetListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">" +
"<listName>"+listGuid+"</listName>" +
"<query>" +
"<Query><Where>" +
"<DateRangesOverlap>" +
"<FieldRef Name=\"EventDate\"/>"+
"<FieldRef Name=\"EndDate\"/>"+
"<FieldRef Name=\"RecurrenceID\"/>"+
"<Value Type=\"DateTime\"><Today/></Value>"+
"</DateRangesOverlap>"+
"</Where></Query>"+
"</query>" +
"<queryOptions>"+
"<QueryOptions>"+
"<ExpandRecurrence>TRUE</ExpandRecurrence>"+
"</QueryOptions>"+
"</queryOptions>" +
"</GetListItems>" +
"</soap:Body>" +
"</soap:Envelope>";
// Here we define what code we want to run upon successfully getting the results
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var doc = xhr.responseXML;
// grab all the "row" elements from the XML results
var rows = doc.getElementsByTagName("z:row");
var results = "Today's Schedule ("+rows.length+"):\n\n";
var events = {};
for(var i = 0, len = rows.length; i < len; i++){
var id = rows[i].getAttribute("ows_FSObjType"); // prevent duplicates from appearing in results
if(!events[id]){
events[id] = true;
var allDay = rows[i].getAttribute("ows_fAllDayEvent"),
title = rows[i].getAttribute("ows_Title"),
start = rows[i].getAttribute("ows_EventDate");
var index = start.indexOf(" ");
var date = start.substring(5,index)+"-"+start.substring(2,4); // get the date in MM-dd-yyyy format
start = start.substring(index, index+6); // get the start time in hh:mm format
var end = rows[i].getAttribute("ows_EndDate");
index = end.indexOf(" "); end = end.substring(index,index+6); // get the end time in hh:mm format
results += date + " " + (allDay == "1" ? "All Day\t" : start + " to " + end ) + " \t " + title + "\n";
}
}
alert(results);
}else{
alert("Error "+xhr.status);
}
}
};
// Finally, we actually kick off the query
xhr.send(data);
Checking ranges other than today's date
In the <Value> child node of the <DateRangesOverlap> node, you can specify <Now />, <Today />, <Week />, <Month />, or <Year />.
Week, Month, and Year will check for events within the same week, month, or year of the current date.
To check a date range relative to some date other than today's, you can add a <CalendarDate> node to the <QueryOptions> node of the CAML query, as seen below.
"<query>" +
"<Query><Where>" +
"<DateRangesOverlap>" +
"<FieldRef Name=\"EventDate\"/>"+
"<FieldRef Name=\"EndDate\"/>"+
"<FieldRef Name=\"RecurrenceID\"/>"+
"<Value Type=\"DateTime\"><Week /></Value>"+
"</DateRangesOverlap>"+
"</Where></Query>"+
"</query>" +
"<queryOptions>"+
"<QueryOptions>"+
"<ExpandRecurrence>TRUE</ExpandRecurrence>"+
"<CalendarDate>2017-03-10</CalendarDate>" +
"</QueryOptions>"+
"</queryOptions>" +
Note that values of <Now /> and <Year /> do not seem to respect the CalendarDate value.

Related

How to I get javascript date split code to work for all browsers?

I have a piece of code that works in Chrome and MSIE but failing in Opera and Firefox
var end = Browser.getValue(getElement("mydate"));
var parts = end.split('.');
var us_date = parts[1]+'/'+parts[0]+'/'+parts[2];
var someDate = new Date(us_date);
var numberOfDaysRemove = 1;
someDate.setDate(someDate.getDate() - numberOfDaysRemove);
var returndate = someDate.getDate() + '.' + (someDate.getMonth() + 1) + '.' + someDate.getFullYear() + " " + someDate.getHours() + ':' + someDate.getMinutes();
I know why it doesn't work in Opera and Firefox as I need to replace the
var parts = end.split('.');
var returndate = someDate.getDate() + '.' + (someDate.getMonth() + 1) + '.' + someDate.getFullYear() + " " + someDate.getHours() + ':' + someDate.getMinutes();
with
var parts = end.split('/');
var returndate = someDate.getDate() + '/' + (someDate.getMonth() + 1) + '/' + someDate.getFullYear() + " " + someDate.getHours() + ':' + someDate.getMinutes();
When I do this then it won't work in Chrome or MSIE.
Is there a way to get this code to work in all browsers?
You should never parse strings using the Date constructor or Date.parse (which do the same thing) as it is almost entirely implementation dependent and unreliable. Always manually parse strings, a library can help but if you only need to support one or two formats, a bespoke function is trivial.
Given that you have:
var end = Browser.getValue(getElement("mydate"));
var parts = end.split('.');
var us_date = parts[1]+'/'+parts[0]+'/'+parts[2];
I suspect end is something like "dd.mm.yyyy", so replace the last line with:
var someDate = new Date(parts[2], parts[1]-1, parts[0]);
which will work in every browser since javascript was invented.
Edit
Presuming that the date string is "dd.mm.yyyy", a simple function to parse it regardless of the separator is:
/* Parse date string in format d/m/y
** #param {string} s - date string
** #returns {Date} date object
*/
function parseDMY(s) {
var b = s.split(/\D/);
return new Date(b[2], b[1]-1, b[0]);
}
document.write(parseDMY('23.01.2016'));
This assumes that the values are a valid date and will allow any non–digit separator, so d.m.y, d/m/y and d-m-y are all acceptable.
My suggestion is to use something like jquery to manipulate the DOM.
Jquery, adding a level of abstraction, allows to avoid having to adapt the code to the "single browser standard", because even though today is a bit better (than years ago), basically there is still no real standard.
So for instance, if you do $('#mydate') jquery will retrieve that element in every browser (using IE getElementById etc...) and you don't need anymore to worry about your code to be cross-browser.
$('#mydate').val() //assuming it to be an input, will retrieve the value and then you can work with your own logic.
Hope it helps.

Query Instagram posts by hashtag and time range

I'm trying to query posts from Instagram by providing the hashtag and the time range (since and until dates).
I use the recent tags endpoint.
https://api.instagram.com/v1/tags/{tag-name}/media/recent?access_token=ACCESS-TOKEN
My code is written in Node.js using the instagram-node library (see the inline comments):
// Require the config file
var config = require('../config.js');
// Require and intialize the instagram instance
var ig = require('instagram-node').instagram();
// Set the access token
ig.use({ access_token: config.instagram.access_token });
// We export this function for public use
// hashtag: the hashtag to search for
// minDate: the since date
// maxDate: the until date
// callback: the callback function (err, posts)
module.exports = function (hashtag, minDate, maxDate, callback) {
// Create the posts array (will be concated with new posts from pagination responses)
var posts = [];
// Convert the date objects into timestamps (seconds)
var sinceTime = Math.floor(minDate.getTime() / 1000);
var untilTime = Math.floor(maxDate.getTime() / 1000);
// Fetch the IG posts page by page
ig.tag_media_recent(hashtag, { count: 50 }, function fetchPosts(err, medias, pagination, remaining, limit) {
// Handle error
if (err) {
return callback(err);
}
// Manually filter by time
var filteredByTime = medias.filter(function (currentPost) {
// Convert the created_time string into number (seconds timestamp)
var createdTime = +currentPost.created_time;
// Check if it's after since date and before until date
return createdTime >= sinceTime && createdTime <= untilTime;
});
// Get the last post on this page
var lastPost = medias[medias.length - 1] || {};
// ...and its timestamp
var lastPostTimeStamp = +(lastPost.created_time || -1);
// ...and its timestamp date object
var lastPostDate = new Date(lastPostTimeStamp * 1000);
// Concat the new [filtered] posts to the big array
posts = posts.concat(filteredByTime);
// Show some output
console.log('found ' + filteredByTime.length + ' new items total: ' + posts.length, lastPostDate);
// Check if the last post is BEFORE until date and there are no new posts in the provided range
if (filteredByTime.length === 0 && lastPostTimeStamp <= untilTime) {
// ...if so, we can callback!
return callback(null, posts);
}
// Navigate to the next page
pagination.next(fetchPosts);
});
};
This will start fetching the posts with the most recent to least recent ones, and manually filter the created_time.
This works, but it's very very inefficient because if we want, for example, to get the posts from one year ago, we have to iterate the pages until that time, and this will use a lot of requests (probably more than 5k / hour which is the rate limit).
Is there a better way to make this query? How to get the Instagram posts by providing the hashtag and the time range?
I think this is the basic idea you're looking for. I'm not overly familiar with Node.js, so this is all in plain javascript. You'll have to modify it to suit your needs and probably make a function out of it.
The idea is to convert an instagram id (1116307519311125603 in this example) to a date and visa versa to enable you to quickly grab a specific point in time rather then backtrack through all results until finding your desired timestamp. The portion of the id after the underscore '_' should be trimmed off as that refers, in some way, to the user IIRC. There are 4 functions in the example that I hope will help you out.
Happy hacking!
//static
var epoch_hour = 3600,
epoch_day = 86400,
epoch_month = 2592000,
epoch_year = 31557600;
//you'll need to set this part up/integrate it with your code
var dataId = 1116307519311125603,
range = 2 * epoch_hour,
count = 1,
tagName = 'cars',
access = prompt('Enter access token:'),
baseUrl = 'https://api.instagram.com/v1/tags/' +
tagName + '/media/recent?access_token=' + access;
//date && id utilities
function idToEpoch(n){
return Math.round((n / 1000000000000 + 11024476.5839159095) / 0.008388608);
}
function epochToId(n){
return Math.round((n * 0.008388608 - 11024476.5839159095) * 1000000000000);
}
function newDateFromEpoch(n){
var d = new Date(0);
d.setUTCSeconds(n);
return d;
}
function dateToEpoch(d){
return (d.getTime()-d.getMilliseconds())/1000;
}
//start with your id and range; do the figuring
var epoch_time = idToEpoch(dataId),
minumumId = epochToId(epoch_time),
maximumId = epochToId(epoch_time + range),
minDate = newDateFromEpoch(epoch_time),
maxDate = newDateFromEpoch(epoch_time + range);
var newUrl = baseUrl +
'&count=' + count +
'&min_tag_id=' + minumumId +
'&max_tag_id=' + maximumId;
//used for testing
/*alert('Start: ' + minDate + ' (' + epoch_time +
')\nEnd: ' + maxDate + ' (' + (epoch_time +
range) + ')');
window.location = newUrl;*/
To support this excellent answer, an instagram ID is generated via the plpgSQL function:
CREATE OR REPLACE FUNCTION insta5.next_id(OUT result bigint) AS $$
DECLARE
our_epoch bigint := 1314220021721;
seq_id bigint;
now_millis bigint;
shard_id int := 5;
BEGIN
SELECT nextval('insta5.table_id_seq') %% 1024 INTO seq_id;
SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO now_millis;
result := (now_millis - our_epoch) << 23;
result := result | (shard_id << 10);
result := result | (seq_id);
END;
$$ LANGUAGE PLPGSQL;
from Instagram's blog
Despite a similar getting posts process, Data365.co Instagram API, I currently working at, seems to be more suitable and efficient. It does not have a limit of 5,000 posts per hour, and you can specify the period of time for which your need posts in the request itself. Also, the billing will be taken into account only posts from the indicated period. You won't have to pay for data you don't need.
You can see below a task example to download posts by the hashtag bitcoins for the period from January 1, 2021, to January 10, 2021.
POST request: https://api.data365.co/v1.1/instagram/tag/bitcoins/update?max_posts_count=1000&from_date=2021-01-01&to_date=2021-01-10&access_token=TOKEN
A GET request example to get the corresponding list of posts:
https://api.data365.co/v1.1/instagram/tag/bitcoins/posts?from_date=2021-01-01&to_date=2021-01-10&max_page_size=100&order_by=date_desc&access_token=TOKEN
More detailed info view in API documentation at https://api.data365.co/v1.1/instagram/docs#tag/Instagram-hashtag-search

Need to export tables inside a <div> as excel, keeping filled-in input and option data

I have a page that takes some selections in javascript and makes a recommendation based on the inputs. Some of my customers want to be able to save this data in excel format, but I'm running into issues retrofitting that.
Here is the code that I found to export the HTML in a DIV as an XLS:
$('btnExport').addEvent('click', function(e){
//getting values of current time for generating the file name
var dt = new Date();
var day = dt.getDate();
var month = dt.getMonth() + 1;
var year = dt.getFullYear();
var hour = dt.getHours();
var mins = dt.getMinutes();
var postfix = day + "." + month + "." + year + "_" + hour + "." + mins;
//creating a temporary HTML link element (they support setting file names)
var a = document.createElement('a');
//getting data from our div that contains the HTML table
var data_type = 'data:application/vnd.ms-excel';
var table_div = document.getElementById('dvData');
var table_html = table_div.outerHTML.replace(/ /g, '%20');
a.href = data_type + ', ' + table_html;
//setting the file name
a.download = 'exported_table_' + postfix + '.xls';
//triggering the function
a.click();
//just in case, prevent default behaviour
e.preventDefault();
});
This almost does what I need it to, but I would like to be able to preserve the initial selections (both drop downs and fields) as their values in the final output. I found some related code to go in and replace those tags with their values, but that affects the page itself, not the output.
var inputs = document.querySelectorAll('select');
for (var i = 0; i < inputs.length; i++) {
var text = document.createTextNode(inputs[i].value);
inputs[i].parentNode.replaceChild(text, inputs[i]);
}
How do I combine these two functions into something that makes sense? The data I need to export is split across multiple tables. I found some solutions leveraging jquery, but I'm using mootools on the site, and combining the two seems to break things.
I will give you a hint for a lazy solution. On page load clone that div with cloneNode and keep it as a variable. When you need to do the export just export that reference (not the actual div).
On the other hand, if you need to keep some other information entered by user still clone the node and run through all the fields and dropdowns within a cloned instance and set them back to default. If you need a reference to each default value of each dropdown you can do so with some kind of data-* attribute. Then again, export the cloned node.

Google Apps Script - Dynamically Add Remove UiApp Form Elements

I am looking to create a Ui form section in my application that will Dynamically Add Remove UiApp Form Elements. I was trying to use the example from App Script Tutorials here
This example works great as far as performing the add remove elements, but when I use the submit button to capture the values, it submits as a JSON.stringify format. When I just want to capture the values only in a text or string format that will be added to a html email.
If there is way to convert JSON.stringify to text, string or get the values only in format, I will continue to use this example.
If not I was wonder if the following Javascript HTML code can be convert into GAS code and able to capture the values for each entry in a HTML email template to using in MailApp.
http://jsfiddle.net/g59K7/
Any suggestions, examples or adjustments to the codes would be greatly appreciated.
Thank you in advance
If you don't want the result to be in a JSON object, then you can adjust the _processSubmittedData(e) function. Right now he has it writing everything to an Object, which is fine. All you have to do is have a way to parse it:
function _processSubmittedData(e){
var result = {};
result.groupName = e.parameter.groupName;
var numMembers = parseInt(e.parameter.table_tag);
result.members = [];
//Member info array
for(var i=1; i<=numMembers; i++){
var member = {};
member.firstName = e.parameter['fName'+i];
member.lastName = e.parameter['lName'+i];
member.dateOfBirth = e.parameter['dob'+i];
member.note = e.parameter['note'+i];
result.members.push(member);
}
var htmlBody = 'Group Name: ' + result.groupName;
for(var a in result.members) {
var member = result.members[a];
var date = member.dateOfBirth;
var last = member.lastName;
var first = member.firstName;
var note = member.note;
htmlBody += first + ' ' + last + ' was born on ' + date + ' and has this note: ' + note;
}
MailApp.sendEmail('fakeEmail#fake.com',"Test Subject Line", "", {htmlBody: htmlBody});
}

Twitter OAuth Request_Token with Javascript, possibly wrong time?

So I'm trying and failing to get a token from twitter.
I get the following error: "Failed to validate oauth signature and token".
I have read it can be due to your system clock being wrong.
In javascript I tested my date with the following code
var minutes=1000*60;
var hours=minutes*60;
var days=hours*24;
var years=days*365;
var d=new Date();
var t=d.getTime();
var y=t/years;
console.log((y+1970) + " year and " + (t%years)/days)
This gave me the year as 2012 and 17 days..
1972
1976
1980
1984
1988
1992
1996
2000
2004
2008
__=10 leap days. Today is the 8th, so taking away leap days it appears my system clock is on the 7th? Or have I made a mistake here? If this is the problem how do I fix correct my clock?
In cmd when I do the date cmd it gives me todays date, i.e the 8th.
Here is my post request and code in case the problem lies within the code and not the clock.
My Post request is:
POST http://api.twitter.com/oauth/request_token?oauth_callback=127.0.0.1&oauth_consumer_key=FFZJrBaPLsiwTDg5159tTQ&oauth_nonce=tWHEEIW8vLS6tMggo3IXe6e449qv1GpE8LunKRsbRF&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1326039495&oauth_version=1.0&oauth_signature=d%2BQqgTzJCjYIp9vKwm%2BCWzVLPvA
which gets 401 (Unauthorized)
Here is my javascript code.
var url = "http://api.twitter.com/oauth/request_token";
var params={
oauth_callback : "127.0.0.1"
,oauth_consumer_key : "FFZJrBaPLsiwTDg5159tTQ"
,oauth_nonce : OAuth.nonce(42)
,oauth_signature_method : "HMAC-SHA1"
,oauth_timestamp : OAuth.timestamp()
,oauth_version: "1.0"}
//temp is to be the signature base string
var temp = toSignParams("POST",url,params);
console.log(temp);
//This logs the signature base string as "POST&http%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3D127.0.0.1%26oauth_consumer_key%3DFFZJrBaPLsiwTDg5159tTQ%26oauth_nonce%3D5gQVIa3WmwD6ARGGQTITl1Ozgxe2t8em5HC7g8wvMi%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1326038871%26oauth_version%3D1.0"
//which is correct I think.
//When I use this with the base signature from twitters oauth example page I get the result they got.
//it hashes the twitter signing key with base signature.
params.oauth_signature = b64_hmac_sha1("MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98&",temp);
var req = new XMLHttpRequest();
req.open("POST",toURIParams(url,params),true);
req.send();
console.log(params)
req.onreadystatechange=function(){
if (req.readyState==4)
{
console.log(req.responseText); //this is saying "Failed to validate oauth signature and token"
}
}
//function to convert to Signature paramaters, as indicated on twitter page.
function toSignParams(method,base,params){
tail=[];
for (var p in params) {
if (params.hasOwnProperty(p)) {
tail.push(p + "%3D" + encodeURIComponent(params[p]));
}
}
return method + "&" + encodeURIComponent(base) + "&" + tail.join("%26")
}
//function to convert to uri encoded parameters.
function toURIParams(base, params) {
tail = [];
for (var p in params) {
if (params.hasOwnProperty(p)) {
tail.push(p + "=" + encodeURIComponent(params[p]));
}
}
return base + "?" + tail.join("&")
}
Any ideas?
I used a library called "jsOAuth-1.3.3" as was found on the twitter list of libraries compatible with JavaScript but is no longer there.
The 2 javascript options they list now are:
user-stream by #AivisSilins — a simple Node.js User streams client
and
codebird-js by #mynetx — a Twitter Library in JScript.
as found on https://dev.twitter.com/docs/twitter-libraries
If anybody has a problem where they can't get either of those solutions to work, I can try find online or upload the library I used somewhere.

Categories

Resources