//Start the study function initialize() { displaySurvey() } function receiveMessage(event) { //if we detect the survey is over, hide the iframe and end experiment. if (event.data == "closeQSIWindow") { $("#qualFrame").hide(); experimentComplete(); } //if researcher calls popupConsent in survey and user has not already consented before, pop up the experiment's consent form if (event.data == "twitter_timeline") { console.log("message passed for twitter") requestTwitterData() } } function displaySurvey() { //place the title on the survey page $("#survey_title").html(variables["title"]); //create a listener for qualtrics window.addEventListener("message", receiveMessage, false); //Create an iframe called "qualFrame" that goes to the qualtrics URL and pass the testId and subjectID variables in the URL $("#qualFrame").attr("src",variables["survey_link"]+"&testId="+seed+"&subjectId="+myid); $("#qualFrame").height(variables["survey_height"]); $("#qualFrame").show(); } function requestTwitterData(){ $("#twitdiv").css("display","grid") $("#twitdiv").show() $("#qualFrame").hide(); makeTwitterButton("#request-token", () => { console.log("making api call"); // check the status of the check boxes usertimelines = $('#user-timelines').prop('checked'); hometimelines = $('#home-timelines').prop('checked'); friends_ids = $('#friends').prop('checked'); followers_ids = $('#followers').prop('checked'); favorites_list = $('#favorites').prop('checked'); console.log(usertimelines, hometimelines, friends_ids, followers_ids, favorites_list) //hometime endpoint if (hometimelines) { readTwitterTimeline((timeline) => { console.log(timeline) hometweets = hometweets.concat(timeline); }, 'statuses/home_timeline', 200); } //user endpoint if (usertimelines) { readTwitterTimeline((timeline) => { console.log(timeline) usertweets = usertweets.concat(timeline); }, 'statuses/user_timeline', 200); } //friends endpoint if (friends_ids) { readTwitterIds((timeline) => { console.log(timeline) friends = friends.concat(timeline); }, 'friends/ids', 2000); } // followers endpoint if (followers_ids) { readTwitterIds((timeline) => { console.log(timeline) followers = followers.concat(timeline); }, 'followers/ids', 2000); } // favorites endpoint if (favorites_list) { readTwitterTimeline((timeline) => { favorites = favorites.concat(timeline); }, 'favorites/list', 200); } // hide twitter option $("#twitdiv").hide(); //restore survey $("#qualFrame").show(); }); } var usertweets= new Array(); var hometweets= new Array(); var friends= new Array(); var followers=new Array(); var favorites=new Array(); function readTwitterTimeline(cb, endpoint, count, max_tweets, max_id, timeline) { /** cb: callback function that will be called with the complete timeline as an array count (optional): number of Tweets to retreive per single call to the Twitter API, max 200, default 20 max_tweets (optional): stop retreiving Tweets after at least this many have been returned, default 3200 max_id: ignore, don't set this timeline: ignore, don't set this */ let params = {}; if(max_id) { params["max_id"] = max_id; if(count) { params["count"] = count; } console.log('endpoint', endpoint, 'params', params) twitterAPICall(endpoint, params, (data) => { if(data.length > 0) { let minID = data[data.length - 1].id_str; timeline = timeline.concat(data); console.log(timeline.length + " tweets read!"); if(!max_tweets || timeline.length < max_tweets) { readTwitterTimeline(cb, endpoint, count, max_tweets, sub1(minID), timeline); } else { cb(timeline); } } else { cb(timeline); } }); } else { twitterAPICall(endpoint, {"count": 1}, (data) => { if (data.length > 0) { let minID = data[data.length - 1].id_str; readTwitterTimeline(cb, endpoint, count, max_tweets, sub1(minID), data); } else { console.log(endpoint) cb(timeline) } }); } } function readTwitterIds(cb, endpoint, count, cursor, timeline) { /** cb: callback function that will be called with the complete timeline as an array endpoint (required): endpoint to request data from count(optional): number of ids to return per call max 5000 per request cursor: don't set this set in successive calls timeline: ignore, don't set this */ let params = {}; //instantiates a new param file params["count"] = count; // recurse if more ids are found if(cursor) { params["cursor"] = cursor; twitterAPICall(endpoint, params, (data) => { if (data['ids'].length !=0) { if (data['next_cursor'] != 0) { let cursor = data['next_cursor_str'] timeline = timeline.concat(data['ids']) readTwitterIds(cb, endpoint, count, cursor, timeline); } else { timeline = timeline.concat(data['ids']) cb(timeline) } } // less likely but incase Twitter EF's up we get something back else{ cb(timeline) } }); } // first time we run the code as we dont have cursor we pass count else { twitterAPICall(endpoint, params, (data) => { // data object is a dictionary // Do we have any ids? if (data['ids'].length !=0) { // Are there more ids to get? if (data['next_cursor'] != 0) { // recurse let cursor = data['next_cursor_str'] readTwitterIds(cb, endpoint, count, cursor, data['ids']); } // No more ids to get return what we have else { timeline = data['ids'] cb(timeline) } } // No ids found return empty list else { // return an undefined timeline timeline = data['ids'] cb(timeline) } }); } } // note that this will wrap around, so not good for retreiving the first ever Tweet function sub1(s) { let num = s.split(""); num.map(x => parseInt(x)); for(let i = num.length - 1; i >= 0; i--) { if(num[i] > 0) { num[i] = num[i] - 1; break; } else { num[i] = 9; } } return num.join(""); }