script.js 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. /*
  2. Copyright 2011 - Tommi Laukkanen (www.substanceofcode.com)
  3. This file is part of TwimGo.
  4. NewsFlow is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. Foobar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with NewsFlow. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. Qt.include("twitter.js")
  16. Qt.include("storage.js")
  17. var tweets;
  18. var tweetsHome;
  19. var tweetsMentions;
  20. var selectedTweet;
  21. var selectedTweetID;
  22. var myUsername = "";
  23. var currentScreenName = "";
  24. var currentUserID = "";
  25. var currentTweetText = "";
  26. var isLandscape = true;
  27. var width;
  28. //var widgetTweetIndex = -1;
  29. //var widgetRefreshCount = 0;
  30. var twitter = null;
  31. //var geolocation;
  32. var append = false;
  33. var listsModel;
  34. var searchesModel;
  35. // UI components
  36. var waiting;
  37. var doneIndicator;
  38. var errorIndicator;
  39. var profile;
  40. var tweetListContainer;
  41. var trends;
  42. var loginPage;
  43. var newHomeTweetsIndicator;
  44. var newMentionsIndicator;
  45. var mainMenu;
  46. var page = 1;
  47. var autoRefresh = false;
  48. var autoRefreshURL = "";
  49. var autoRefreshIndex = 0;
  50. var lastTweetID = "";
  51. var lastHomeTweetID = "";
  52. var lastMentionsTweetID = "";
  53. var searchLat = "";
  54. var searchLon = "";
  55. var searchQuery = "";
  56. // Timelines
  57. var HOME_TIMELINE_URL = "https://api.twitter.com/1/statuses/home_timeline.json";
  58. var PUBLIC_TIMELINE_URL = "https://api.twitter.com/1/statuses/public_timeline.json";
  59. var MENTIONS_TIMELINE_URL = "https://api.twitter.com/1/statuses/mentions.json";
  60. var DIRECT_TIMELINE_URL = "https://api.twitter.com/1/direct_messages.json";
  61. var FAVOURITES_TIMELINE_URL = "https://api.twitter.com/1/favorites.json";
  62. var RETWEETSME_TIMELINE_URL = "https://api.twitter.com/1/statuses/retweets_of_me.json";
  63. var PUBLIC_TIMELINE = "https://api.twitter.com/1/statuses/public_timeline.json";
  64. var RETWEETSTOME_TIMELINE_URL = "https://api.twitter.com/1/statuses/retweeted_to_me.json";
  65. var FRIENDS_TIMELINE_URL = "https://api.twitter.com/1/statuses/friends_timeline.json";
  66. var FRIENDS_URL = "http://api.twitter.com/1/statuses/friends.json";
  67. var FOLLOWERS_TIMELINE_URL = "https://api.twitter.com/1/statuses/followers.json";
  68. var USER_TIMELINE_URL = "https://api.twitter.com/1/statuses/user_timeline.json";
  69. var SEARCH_URL = "http://search.twitter.com/search.json";
  70. var LIST_STATUSES_URL = "https://api.twitter.com/1/:user/lists/:id/statuses.json";
  71. function setComponents(waitingItem,
  72. doneIndicatorItem,
  73. profileItem,
  74. tweetListContainerItem,
  75. errorIndicatorItem,
  76. welcomePage,
  77. newHomeTweets,
  78. newMentions,
  79. menu) {
  80. waiting = waitingItem;
  81. doneIndicator = doneIndicatorItem;
  82. profile = profileItem;
  83. tweetListContainer = tweetListContainerItem;
  84. errorIndicator = errorIndicatorItem;
  85. loginPage = welcomePage;
  86. homeIcon = newHomeTweets;
  87. mentionsIcon = newMentions;
  88. mainMenu = menu;
  89. }
  90. function getTwitterTimeAndLogin() {
  91. initializeTwitterObject();
  92. showWaiting(qsTr("Please wait..."));
  93. twitter.requestTime( login );
  94. }
  95. function getTwitterTimeAndToken() {
  96. initializeTwitterObject();
  97. showWaiting(qsTr("Please wait..."));
  98. twitter.requestTime( requestToken );
  99. }
  100. function requestToken() {
  101. initializeTwitterObject();
  102. twitter.requestToken();
  103. }
  104. function setLastHomeID(lastHomeID) {
  105. lastHomeTweetID = lastHomeID;
  106. }
  107. function setLastMentionID(lastMentionID) {
  108. lastMentionsTweetID = lastMentionID;
  109. }
  110. function checkNewHomeTweets() {
  111. twitter.checkNewHomeTweets( lastHomeTweetID, parseNewHomeTweetsResult );
  112. }
  113. function parseNewHomeTweetsResult(data) {
  114. var homeTweets = eval("[" + data + "]")[0];
  115. if(homeTweets.length>0) {
  116. var firstTweet = homeTweets[0];
  117. lastHomeTweetID = firstTweet.id_str;
  118. console.log("New home ID: " + lastHomeTweetID);
  119. saveLastTweetIDs();
  120. homeIcon.showNewIndicator = true;
  121. // if(birdSound.muted==false) {
  122. // birdSound.play();
  123. // }
  124. }
  125. checkNewMentions();
  126. }
  127. function checkNewMentions() {
  128. twitter.checkNewMentions( lastMentionsTweetID, parseNewMentions );
  129. }
  130. function parseNewMentions(data) {
  131. var mentionTweets = eval("[" + data + "]")[0];
  132. if(mentionTweets.length>0) {
  133. var firstTweet = mentionTweets[0];
  134. lastMentionsTweetID = firstTweet.id_str;
  135. saveLastTweetIDs();
  136. mentionsIcon.showNewIndicator = true;
  137. // if(birdSound.muted==false) {
  138. // birdSound.play();
  139. // }
  140. }
  141. }
  142. function saveLastTweetIDs() {
  143. setKeyValue("lastHomeID", lastHomeTweetID);
  144. setKeyValue("lastMentionID", lastMentionsTweetID);
  145. }
  146. function showLogin() {
  147. getTwitterTimeAndToken();
  148. welcomePage.visible = true;
  149. authorizeWindow.visible = true;
  150. }
  151. function setSelectedTweet(id) {
  152. selectedTweetID = id;
  153. }
  154. function setSelectedUser(id) {
  155. currentUserID = id;
  156. }
  157. function loadMentions() {
  158. loadTimeline(MENTIONS_TIMELINE_URL, false);
  159. }
  160. function loadRateLimit() {
  161. twitter.loadRateLimit(parseRateLimit);
  162. }
  163. function parseRateLimit(data) {
  164. /* {"hourly_limit":150,
  165. "reset_time_in_seconds":1297626293,
  166. "reset_time":"Sun Feb 13 19:44:53 +0000 2011",
  167. "remaining_hits":150}
  168. */
  169. var rate = eval("[" + data + "]")[0];
  170. var resetDate = new Date();
  171. resetDate.setTime(rate.reset_time_in_seconds*1000);
  172. var hours = String(resetDate.getHours());
  173. if(hours.length==1) {
  174. hours = "0" + hours;
  175. }
  176. var minutes = String(resetDate.getMinutes());
  177. if(minutes.length==1) {
  178. minutes = "0" + minutes;
  179. }
  180. mainMenu.apiStatus = "API remaining hits: " + rate.remaining_hits + " Hourly limit: " + rate.hourly_limit + " reset at " + hours + ":" + minutes;
  181. }
  182. function loadHome() {
  183. loadTimeline(HOME_TIMELINE_URL, false);
  184. }
  185. function loadDirectMessages() {
  186. loadTimeline(DIRECT_TIMELINE_URL, false);
  187. }
  188. function loadFollowers() {
  189. loadTimeline(FOLLOWERS_TIMELINE_URL, false);
  190. }
  191. function loadRetweets() {
  192. loadTimeline(RETWEETSME_TIMELINE_URL, false);
  193. }
  194. function loadFavourites() {
  195. loadTimeline(FAVOURITES_TIMELINE_URL, false);
  196. }
  197. function loadCurrentUserTweets() {
  198. var url = USER_TIMELINE_URL + "?user_id=" + currentUserID;
  199. loadTimeline(url, false);
  200. }
  201. function loadUserTweets() {
  202. var url = USER_TIMELINE_URL;
  203. loadTimeline(url, false);
  204. }
  205. function loadFriends() {
  206. loadTimeline(FRIENDS_URL, false);
  207. }
  208. function loadReplyText(replyID, replyText) {
  209. twitter.getTweet(replyID, parseSingleReply);
  210. }
  211. function parseSingleReply(data) {
  212. var tweet = eval("[" + data + "]")[0];
  213. replyTextContainer.replyText = tweet.user.screen_name + ": " + tweet.text;
  214. }
  215. function loadList(listID) {
  216. var url = LIST_STATUSES_URL.replace(":user", myUsername).replace(":id", listID);
  217. loadTimeline(url, false);
  218. }
  219. function follow() {
  220. waiting.state = "shown";
  221. twitter.follow(currentUserID, okCallback);
  222. }
  223. function unfollow() {
  224. waiting.state = "shown";
  225. twitter.unfollow(currentUserID, okCallback);
  226. }
  227. function loadTrends(trendsModel) {
  228. trends = trendsModel;
  229. waiting.state = "shown";
  230. twitter.loadTrends(parseTrends);
  231. }
  232. function parseTrends(results) {
  233. var lists = eval("[" + results + "]");
  234. lists = lists[0];
  235. lists = lists[0];
  236. lists = lists.trends;
  237. trends.clear();
  238. for(var i in lists) {
  239. var list = lists[i];
  240. trends.append({
  241. "name": list.name
  242. });
  243. }
  244. waiting.state = "hidden";
  245. }
  246. /** Parse parameter from given URL */
  247. function parseParameter(url, parameter) {
  248. var parameterIndex = url.indexOf(parameter);
  249. if(parameterIndex<0) {
  250. // We didn't find parameter
  251. return "";
  252. }
  253. var equalIndex = url.indexOf("=", parameterIndex);
  254. if(equalIndex<0) {
  255. return "";
  256. }
  257. var value = "";
  258. var nextIndex = url.indexOf("&", equalIndex+1);
  259. if(nextIndex<0) {
  260. value = url.substring(equalIndex+1);
  261. } else {
  262. value = url.substring(equalIndex+1, nextIndex);
  263. }
  264. return value;
  265. }
  266. function doSearch(search, lat, lon) {
  267. waiting.state = "shown";
  268. var query = search;
  269. var url = SEARCH_URL + "?q=" + escape(query);
  270. if(lat!=null && lat.length>0 && lat!="NaN") {
  271. url += "&geocode=" + lat + "," + lon + ",20km";
  272. }
  273. autoRefreshURL = url;
  274. twitter.searchTweets(url, parseSearchResults);
  275. }
  276. function parseSearchResults(searchResults) {
  277. try {
  278. var data = eval("[" + searchResults + "]");
  279. append = false;
  280. autoRefresh = false;
  281. doTweets(data[0].results);
  282. }catch(err) {
  283. errorCallback("Something went wrong with your search...");
  284. }
  285. }
  286. function loadSavedSearches(searches) {
  287. waiting.state = "shown";
  288. searchesModel = searches;
  289. twitter.getSavedSearches(parseSavedSearches);
  290. }
  291. function parseSavedSearches(results) {
  292. results = eval("[" + results + "]")[0];
  293. var searchCount = 0;
  294. searchesModel.clear();
  295. for(var i in results) {
  296. var saved_search = results[i];
  297. searchesModel.append({
  298. "name": saved_search.query,
  299. "searchid": saved_search.id
  300. });
  301. }
  302. waiting.state = "hidden";
  303. }
  304. function saveSearch(query, lat, lon) {
  305. searchLat = lat;
  306. searchLon = lon;
  307. searchQuery = query;
  308. twitter.saveSearch(query, parseSaveSearch);
  309. }
  310. function parseSaveSearch(data) {
  311. doSearch(searchQuery, searchLat, searchLon);
  312. }
  313. function removeSearch(searchid) {
  314. showWaiting(qsTr("Removing search"));
  315. twitter.removeSearch(searchid, parseRemoveSearch);
  316. }
  317. function parseRemoveSearch(data) {
  318. waiting.state = "hidden";
  319. doneIndicator.state = "shown";
  320. }
  321. function loadAndShowLists(listModel) {
  322. listsModel = listModel;
  323. waiting.state = "shown";
  324. twitter.getLists(myUsername, parseLists);
  325. }
  326. function parseLists(results) {
  327. var lists = eval("[" + results + "]")[0].lists;
  328. listsModel.clear();
  329. for(var i in lists) {
  330. var list = lists[i];
  331. listsModel.append({
  332. "slug": list.slug
  333. });
  334. }
  335. waiting.state = "hidden";
  336. }
  337. function loadSingleTweet(tweetID) {
  338. waiting.state = "shown";
  339. twitter.getTweet( tweetID, parseSingleTweet );
  340. }
  341. function parseSingleTweet(tweet) {
  342. //console.log("Tweet: " + tweet);
  343. var tweets = eval("[" + tweet + "]");
  344. doTweets(tweets, false);
  345. }
  346. function fillProfile() {
  347. waiting.state = "shown";
  348. twitter.getUser(currentUserID, parseProfile);
  349. }
  350. function parseProfile(userData) {
  351. var user = eval("[" + userData + "]");
  352. user = user[0];
  353. var name = "";
  354. var profileImage = "";
  355. var userLocation = "";
  356. var statusCount = "-";
  357. var followerCount = "-";
  358. var screenName = "";
  359. var userID = "";
  360. var url = "";
  361. var description = "";
  362. try{
  363. userID = String(user.id);
  364. profile.userID = userID;
  365. profile.description = user.description;
  366. profile.username = user.screen_name;
  367. profile.profileImageURL = user.profile_image_url;
  368. profile.userLocation = user.location;
  369. profile.tweetCount = user.statuses_count;
  370. profile.followingCount = user.friends_count;
  371. profile.followersCount = user.followers_count;
  372. if(user.following) {
  373. profile.isFollowing = true;
  374. } else {
  375. profile.isFollowing = false;
  376. }
  377. currentScreenName = screenName;
  378. currentUserID = String(userID);
  379. } catch(err) {
  380. errorCallback("Can't parse profile because " + err);
  381. }
  382. waiting.state = "hidden";
  383. }
  384. function favourite(tweetID) {
  385. waiting.state = "shown";
  386. twitter.favourite( tweetID, okCallback);
  387. }
  388. function unfavourite(tweetID) {
  389. waiting.state = "shown";
  390. twitter.unfavourite( tweetID, okCallback);
  391. }
  392. function destroy(tweetID) {
  393. waiting.state = "shown";
  394. twitter.destroy( tweetID, okCallback );
  395. for(var i=0; i<tweetsModel.count; i++) {
  396. tweetsModel.remove(i);
  397. break;
  398. }
  399. }
  400. function instantretweet(tweetID) {
  401. waiting.state = "shown";
  402. twitter.retweet( tweetID, okCallback );
  403. }
  404. function initializeTwitterObject() {
  405. if(typeof(twitter)=="undefined" || twitter==null) {
  406. twitter = new Twitter();
  407. twitter.setErrorCallback( errorCallback );
  408. }
  409. }
  410. function login(dummy) {
  411. initializeTwitterObject();
  412. showWaiting("Authenticating...");
  413. twitter.login();
  414. }
  415. function resetTokens() {
  416. if(typeof(twitter)!="undefined" && twitter!=null) {
  417. twitter.resetToken();
  418. }
  419. }
  420. function autoFresh() {
  421. autoRefresh = true;
  422. var url = autoRefreshURL;
  423. url = removeParameter(url, "since_id");
  424. if(typeof(lastTweetID)!="undefined") {
  425. if(url.indexOf("?")>0 && lastTweetID.length>0) {
  426. url += "&since_id=" + String(lastTweetID);
  427. } else {
  428. url += "?since_id=" + String(lastTweetID);
  429. }
  430. }
  431. loadTimeline(url,false);
  432. }
  433. function removeParameter(url, parameter) {
  434. var indexOfParameterStart = url.indexOf(parameter + "=");
  435. if(indexOfParameterStart<0) {
  436. return url;
  437. }
  438. var indexOfParameterEnd = url.indexOf("&", indexOfParameterStart+1);
  439. if(indexOfParameterEnd>0) {
  440. url = url.substring(0,indexOfParameterStart);
  441. url += url.substring(indexOfParameterEnd);
  442. } else {
  443. url = url.substring(0,indexOfParameterStart);
  444. }
  445. return url;
  446. }
  447. function removeHTMLTags(input) {
  448. return input.replace(/<\/?[^>]+(>|$)/g, "");
  449. }
  450. function showWaiting(reason) {
  451. waitingText.text = reason;
  452. waiting.state = "shown";
  453. }
  454. function loadTimeline(timelineUrl, appendFully) {
  455. console.log("My username is " + myUsername);
  456. showWaiting(qsTr("Loading tweets..."));
  457. append = appendFully;
  458. if(append==false) {
  459. autoRefreshURL = timelineUrl;
  460. page = 1;
  461. if(autoRefresh==false) {
  462. lastTweetID = "";
  463. if(timelineUrl.indexOf(HOME_TIMELINE_URL)>-1) {
  464. homeIcon.showNewIndicator = false;
  465. } else if(timelineUrl.indexOf(MENTIONS_TIMELINE_URL)>-1) {
  466. mentionsIcon.showNewIndicator = false;
  467. }
  468. }
  469. }
  470. twitter.getTweets(timelineUrl, parseRealTweets);
  471. }
  472. function parseRealTweets(tweets) {
  473. try {
  474. authorizeWindow.visible = false;
  475. var realTweets = tweets;
  476. if(typeof(realTweets)==undefined) {
  477. return;
  478. }
  479. if(realTweets!=null && realTweets.results!=null) {
  480. // Get search results
  481. realTweets = realTweets.results;
  482. }
  483. // Launch
  484. if(autoRefresh==true) {
  485. if(autoRefreshURL.indexOf(HOME_TIMELINE_URL)>-1) {
  486. checkNewMentions();
  487. } else {
  488. checkNewHomeTweets();
  489. }
  490. }
  491. if(realTweets.length>0 &&
  492. (
  493. (typeof(tweets)!=undefined && tweets.length>0 && tweets[0].id!=realTweets[0].id) ||
  494. (typeof(tweets)==undefined||tweets!=null||tweets.length==0)
  495. )) {
  496. if(realTweets.indexOf("[")!=0) {
  497. realTweets = "[" + realTweets + "]";
  498. realTweets = eval(realTweets);
  499. realTweets = realTweets[0];
  500. } else {
  501. realTweets = eval(realTweets);
  502. }
  503. doTweets(realTweets);
  504. }
  505. }catch(exp) {
  506. errorCallback("Tried hard but couldn't parse Tweets because of " + exp);
  507. }
  508. }
  509. function loadNextPage() {
  510. //tweetsModel.remove(tweetsModel.count-1);
  511. autoRefreshURL = removeParameter(autoRefreshURL, "page");
  512. page = page+1;
  513. var newUrl = "";
  514. if(autoRefreshURL.indexOf("?")>0) {
  515. newUrl = autoRefreshURL + "&page=" + page;
  516. } else {
  517. newUrl = autoRefreshURL + "?page=" + page;
  518. }
  519. newUrl = removeParameter(newUrl, "since_id");
  520. loadTimeline(newUrl,true);
  521. }
  522. function updateStatus(status, replyID, isDirectTo, lat, lon) {
  523. waiting.state = "shown";
  524. if(isDirectTo!=null && typeof(isDirectTo)!=undefined && isDirectTo.length>0) {
  525. twitter.directTweet(status, isDirectTo, okCallback);
  526. } else {
  527. twitter.updateStatus(status, replyID, lat, lon, okCallback);
  528. }
  529. }
  530. function convertTweetToModel(tweet) {
  531. try {
  532. var tweetDate = parseTwitterDate(tweet.created_at);
  533. var isoDate = tweetDate.toString("yyyy-MM-ddThh:mm:ssZ");
  534. var status = "";
  535. var inReplyTo = "";
  536. var inReplyToID = "";
  537. var retweeted = "";
  538. var source = tweet.source;
  539. var isFavourite = false;
  540. var tweetID = tweet.id_str;
  541. if(lastTweetID.length==0 && typeof(tweetID)!="undefined" && tweetID!=null) {
  542. lastTweetID = tweetID;
  543. }
  544. if(tweet.text!=null) {
  545. status = tweet.text;
  546. inReplyTo = tweet.in_reply_to_screen_name;
  547. inReplyToID = tweet.in_reply_to_status_id_str;
  548. isFavourite = tweet.favorited;
  549. if(tweet.retweeted_status!=null) {
  550. retweeted = " retweeted " + tweet.retweeted_status.user.screen_name;
  551. }
  552. } else {
  553. // Friends
  554. status = tweet.status.text;
  555. inReplyTo = tweet.status.in_reply_to_screen_name;
  556. inReplyToID = tweet.status.in_reply_to_status_id;
  557. tweetDate = parseTwitterDate(tweet.status.created_at);
  558. }
  559. var replyBlock = "";
  560. if(inReplyTo!=null && typeof(inReplyTo)!=undefined && inReplyTo.length>0) {
  561. replyBlock = " " + qsTr("in reply to") + " @" + inReplyTo;
  562. }
  563. var profileImageUrl = "";
  564. var userName = "";
  565. if(tweet.user!=null && typeof(tweet.user)!=undefined) {
  566. // Home, Mentions, Favourites etc.
  567. profileImageUrl = tweet.user.profile_image_url;
  568. userName = tweet.user.screen_name;
  569. } else if(tweet.sender!=null && typeof(tweet.sender)!=undefined) {
  570. // Direct Tweets
  571. profileImageUrl = tweet.sender.profile_image_url;
  572. userName = tweet.sender.screen_name;
  573. } else if(tweet.name!=null) {
  574. // Friends
  575. userName = tweet.screen_name;
  576. profileImageUrl = tweet.profile_image_url;
  577. } else if(tweet.from_user!=null){
  578. // Search
  579. userName = tweet.from_user;
  580. profileImageUrl = tweet.profile_image_url;
  581. }
  582. var twtDate = ""; // prettyDate(tweetDate);
  583. if(source!=null && typeof(source)!=undefined) {
  584. //console.log("Source1: " + source);
  585. while(source.indexOf("&lt;")>=0 ||
  586. source.indexOf("&gt;")>=0 ||
  587. source.indexOf("&quot;")>=0) {
  588. source = source.replace("&quot;", "\"");
  589. source = source.replace("&lt;", "<");
  590. source = source.replace("&gt;", ">");
  591. }
  592. source = source.replace(/<\/?[^>]+(>|$)/g, "");
  593. //console.log("Source2: " + source);
  594. } else {
  595. source = "";
  596. }
  597. if(inReplyToID==null) {
  598. inReplyToID = "";
  599. }
  600. var isMine = false;
  601. if(userName == myUsername) {
  602. isMine = true;
  603. }
  604. var isForMe = false;
  605. if(status.indexOf(myUsername)>=0) {
  606. isForMe = true;
  607. }
  608. var previewImageHTML = "";
  609. var displayableStatus = status;
  610. // Parse entities
  611. var urls = new Array();
  612. if(tweet.entities!=null && tweet.entities.urls!=null) {
  613. for(var i in tweet.entities.urls) {
  614. var urlEntity = tweet.entities.urls[i];
  615. var url = urlEntity.url;
  616. var expandedUrl = urlEntity.expanded_url;
  617. urls.push(expandedUrl);
  618. var dispUrl = urlEntity.display_url;
  619. /*if(dispUrl.length>32) {
  620. dispUrl = dispUrl.substring(0,30) + "..";
  621. }
  622. dispUrl = dispUrl.replace("https://", "");
  623. dispUrl = dispUrl.replace("http://", "");
  624. dispUrl = dispUrl.replace("www.", "");*/
  625. dispUrl = "<i>" + dispUrl + "</i>";
  626. displayableStatus = status.replace(url,dispUrl);
  627. status = status.replace(url, expandedUrl);
  628. }
  629. for(var j in tweet.entities.media) {
  630. var mediaEntity = tweet.entities.media[j];
  631. console.log("Parsing media");
  632. if(mediaEntity.media_url!=null) {
  633. previewImageHTML = mediaEntity.media_url;
  634. //console.log("Preview image URL: " + previewImageHTML);
  635. }
  636. }
  637. }
  638. if(previewImageHTML===null || previewImageHTML.length===0) {
  639. previewImageHTML = createPreviewImageHTML(status);
  640. }
  641. var tweetObject = {
  642. "tweetID": tweetID,
  643. "userName": userName,
  644. "status": status,
  645. "displayableStatus": displayableStatus,
  646. "profileImageURL": profileImageUrl,
  647. "tweetDate": twtDate,
  648. "tweetDateStamp": tweetDate,
  649. "replyBlock": replyBlock,
  650. "replyID": String(inReplyToID),
  651. "source": source,
  652. "imagePreviewURL": previewImageHTML,
  653. "isFavourite": isFavourite,
  654. "isMine": isMine,
  655. "isForMe": isForMe
  656. };
  657. if( autoRefresh==true ) {
  658. tweetsModel.insert(autoRefreshIndex, tweetObject);
  659. autoRefreshIndex++;
  660. } else {
  661. var k;
  662. for(k=0; k<tweetsModel.count; k++) {
  663. var twt = tweetsModel.get(k);
  664. //console.log("Old tweet " + twt.tweetID + " vs. new tweet " + tweetObject.tweetID);
  665. if(twt.status===tweetObject.status) {
  666. return;
  667. }
  668. }
  669. tweetsModel.append(tweetObject);
  670. }
  671. } catch(err) {
  672. console.log("Err: " + err);
  673. }
  674. }
  675. function okCallback(data) {
  676. waiting.state = "hidden";
  677. doneIndicator.state = "shown";
  678. }
  679. function errorCallback(data) {
  680. waiting.state = "hidden";
  681. if(typeof(data)!="undefined" && data!=null) {
  682. errorIndicator.reason = data;
  683. if(data.indexOf("Unauthorized")>0) {
  684. //showLogin();
  685. welcomePage.showButtons = true;
  686. }
  687. } else {
  688. errorIndicator.reason = "";
  689. }
  690. errorIndicator.state = "shown";
  691. console.log("ERROR: " + data);
  692. }
  693. function GetHashTags(text, model, tweetID) {
  694. //console.log("Creating hashtag models. TweetID " + tweetID);
  695. var rePattern = new RegExp("(#(\\w+))", "gi");
  696. var arrMatch = null;
  697. var matchCount = 0;
  698. while(arrMatch = rePattern.exec(text)) {
  699. matchCount++;
  700. model.append({
  701. "actionName": arrMatch[0],
  702. "tweetID": tweetID
  703. });
  704. }
  705. rePattern = new RegExp("(@(\\w+))", "gi");
  706. while(arrMatch = rePattern.exec(text)) {
  707. matchCount++;
  708. model.append({
  709. "actionName": arrMatch[0],
  710. "tweetID": tweetID
  711. });
  712. }
  713. rePattern = new RegExp("(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]", "gi");
  714. while(arrMatch = rePattern.exec(text)) {
  715. matchCount+=2; // Link + "Read it later..." link
  716. model.append({
  717. "actionName": arrMatch[0],
  718. "tweetID": tweetID
  719. });
  720. // Read it later link
  721. var title = text.replace(arrMatch[0], "");
  722. model.append({
  723. "actionName": "https://readitlaterlist.com/" + arrMatch[0],
  724. "tweetID": tweetID
  725. });
  726. }
  727. return matchCount;
  728. }
  729. function parseUsernames(text) {
  730. var result = "";
  731. var rePattern = new RegExp("(@(\\w+))", "gi");
  732. var arrMatch = null;
  733. while(arrMatch = rePattern.exec(text)) {
  734. if(arrMatch[0]!=("@" + myUsername)) {
  735. result += arrMatch[0] + " ";
  736. }
  737. }
  738. return result;
  739. }
  740. function doTweets(data) {
  741. if(typeof(data.results)!=undefined && data.results!=null) {
  742. data = data.results;
  743. }
  744. var moreIndex = -1;
  745. console.log("append=" + append + " autoFresh=" + autoRefresh);
  746. if(append==false && autoRefresh==false) {
  747. tweetsModel.clear();
  748. } else {
  749. moreIndex = tweetsModel.count - 1;
  750. if(append && moreIndex>=0) {
  751. tweetsModel.remove(moreIndex);
  752. }
  753. }
  754. if(data.length==0) {
  755. waiting.state = "hidden";
  756. autoRefresh = false;
  757. return;
  758. }
  759. lastTweetID = "";
  760. autoRefreshIndex = 0;
  761. for(var x in data) {
  762. var tweet = data[x];
  763. convertTweetToModel(tweet);
  764. }
  765. // Check for indicators
  766. if(autoRefresh==true) {
  767. if(autoRefreshURL.indexOf(HOME_TIMELINE_URL)>-1) {
  768. homeIcon.showNewIndicator = true;
  769. lastHomeTweetID = lastTweetID;
  770. } else if(autoRefreshURL.indexOf(MENTIONS_TIMELINE_URL)>-1) {
  771. mentionsIcon.showNewIndicator = true;
  772. lastMentionsTweetID = lastTweetID;
  773. }
  774. saveLastTweetIDs();
  775. }
  776. formatTimeStamps();
  777. reduceModelSize();
  778. if( tweetsModel.count>1 &&
  779. tweetsModel.count<100 &&
  780. tweetsModel.get(tweetsModel.count-1).status.indexOf("Load more")<0) {
  781. tweetsModel.append({
  782. "tweetID": "",
  783. "userName": "",
  784. "status": "Load more...<br/><br/><br/><br/>",
  785. "displayableStatus": qsTr("Load more...") + "<br/><br/><br/><br/>",
  786. "profileImageURL": "",
  787. "tweetDate": "",
  788. "replyBlock": "",
  789. "replyID": "",
  790. "source": "",
  791. "imagePreviewURL": "",
  792. "isFavourite": false});
  793. }
  794. tweetListContainer.state = "shown";
  795. tweetListContainer.visible = true;
  796. loginPage.visible = false;
  797. waiting.state = "hidden";
  798. autoRefresh = false;
  799. }
  800. function formatTimeStamps() {
  801. for(var i=0; i<tweetsModel.count; i++) {
  802. var tweet = tweetsModel.get(i);
  803. tweet.tweetDate = prettyDate(tweet.tweetDateStamp);
  804. tweetsModel.set(i, tweet);
  805. }
  806. }
  807. function reduceModelSize() {
  808. while(tweetsModel.count>100) {
  809. tweetsModel.remove( tweetsModel.count-1 );
  810. }
  811. }
  812. function createPreviewImageHTML(text) {
  813. var html = "";
  814. var url = "";
  815. var imgSize = "160";
  816. var linkStart = 0;
  817. var linkEnd = 0;
  818. if(isLandscape==false) {
  819. imgSize = "240";
  820. }
  821. if(text.indexOf("http://twitpic.com/")>=0) {
  822. var imageID = text.substr(text.indexOf("http://twitpic.com/")+19, 6);
  823. url = "http://twitpic.com/show/thumb/" + imageID;
  824. } else if(text.indexOf("https://twitpic.com/")>=0) {
  825. var imageID = text.substr(text.indexOf("https://twitpic.com/")+20, 6);
  826. url = "https://twitpic.com/show/thumb/" + imageID;
  827. } else if(text.indexOf("http://yfrog.com/")>=0) {
  828. linkStart = text.indexOf("http://yfrog.com/");
  829. linkEnd = text.indexOf(" ", linkStart);
  830. var yfrogURL = "";
  831. if(linkEnd<0) {
  832. yfrogURL = text.substring(linkStart);
  833. } else {
  834. yfrogURL = text.substring(linkStart,linkEnd);
  835. }
  836. url = yfrogURL + ".th.jpg";
  837. } else if(text.indexOf("instagr.am")>=0 || text.indexOf("instagram.com")>=0) {
  838. linkStart = text.indexOf("http://insta");
  839. linkEnd = text.indexOf(" ", linkStart);
  840. var instagramURL = "";
  841. if(linkEnd<0) {
  842. instagramURL = text.substring(linkStart);
  843. } else {
  844. instagramURL = text.substring(linkStart,linkEnd);
  845. }
  846. url = instagramURL + "/media/?t=t";
  847. }
  848. return url;
  849. }
  850. function doFailure(data) {
  851. waiting.state = "hidden";
  852. if(typeof(data)!="undefined" && data!=null) {
  853. errorIndicator.reason = data;
  854. } else {
  855. errorIndicator.reason = "";
  856. }
  857. errorIndicator.state = "shown";
  858. console.log("ERROR: " + data);
  859. }
  860. // Takes an ISO time and returns a string representing how
  861. // long ago the date represents.
  862. // 2008-01-28T20:24:17Z
  863. function prettyDate(date){
  864. try {
  865. if(typeof(date)=="undefined") {
  866. return qsTr("some time ago");
  867. }
  868. var diff = (((new Date()).getTime() - date.getTime()) / 1000);
  869. var day_diff = Math.floor(diff / 86400);
  870. if ( isNaN(day_diff) || day_diff >= 31 ) {
  871. return qsTr("some time ago");
  872. } else if (day_diff < 0) {
  873. //console.log("day_diff: " + day_diff);
  874. return qsTr("just now");
  875. }
  876. return day_diff == 0 && (
  877. diff < 60 && qsTr("just now") ||
  878. diff < 120 && qsTr("1 minute ago") ||
  879. diff < 3600 && Math.floor( diff / 60 ) + " " + qsTr("min ago") ||
  880. diff < 7200 && qsTr("1 hour ago") ||
  881. diff < 86400 && Math.floor( diff / 3600 ) + " " + qsTr("hours ago")) ||
  882. day_diff == 1 && qsTr("Yesterday") ||
  883. day_diff < 7 && day_diff + " " + qsTr("days ago") ||
  884. day_diff < 31 && Math.ceil( day_diff / 7 ) + " " + qsTr("weeks ago") ||
  885. day_diff >= 31 && Math.ceil( day_diff / 30 ) + " " + qsTr("months ago");
  886. } catch(err) {
  887. console.log("Error: " + err);
  888. return qsTr("some time ago");
  889. }
  890. }
  891. // pass in the 'created_at' string returned from twitter //
  892. // stamp arrives formatted as Tue Apr 07 22:52:51 +0000 2009 //
  893. function parseTwitterDate(stamp)
  894. {
  895. try {
  896. var parts = stamp.split(" ");
  897. var dayName;
  898. var monthName;
  899. var day;
  900. var time;
  901. var hours;
  902. var minutes;
  903. var seconds;
  904. var offset;
  905. var year;
  906. if(stamp.indexOf(",")>0) {
  907. // Search results
  908. // Date stamp in format: Sun, 09 Jan 2011 18:15:30 +0000
  909. // compared to Tue Apr 07 22:52:51 +0000 2009
  910. dayName = parts[0];
  911. monthName = parts[2];
  912. day = parseInt(parts[1], 10);
  913. time = parts[4].split(":");
  914. hours = parseInt(time[0], 10);
  915. minutes = parseInt(time[1], 10);
  916. seconds = parseInt(time[2], 10);
  917. offset = parts[5];
  918. year = parseInt(parts[3], 10);
  919. } else {
  920. dayName = parts[0];
  921. monthName = parts[1];
  922. day = parseInt(parts[2], 10);
  923. time = parts[3].split(":");
  924. hours = parseInt(time[0], 10);
  925. minutes = parseInt(time[1], 10);
  926. seconds = parseInt(time[2], 10);
  927. offset = parts[4];
  928. year = parseInt(parts[5], 10);
  929. }
  930. var month = 0;
  931. if(monthName=="Jan") {
  932. month = 0;
  933. } else if(monthName=="Feb") {
  934. month = 1;
  935. } else if(monthName=="Mar") {
  936. month = 2;
  937. } else if(monthName=="Apr") {
  938. month = 3;
  939. } else if(monthName=="May") {
  940. month = 4;
  941. } else if(monthName=="Jun") {
  942. month = 5;
  943. } else if(monthName=="Jul") {
  944. month = 6;
  945. } else if(monthName=="Aug") {
  946. month = 7;
  947. } else if(monthName=="Sep") {
  948. month = 8;
  949. } else if(monthName=="Oct") {
  950. month = 9;
  951. } else if(monthName=="Nov") {
  952. month = 10;
  953. } else if(monthName=="Dec") {
  954. month = 11;
  955. }
  956. var dt = new Date();
  957. dt.setUTCDate(day);
  958. dt.setYear(year);
  959. dt.setUTCMonth(month);
  960. dt.setUTCHours(hours);
  961. dt.setUTCMinutes(minutes);
  962. dt.setUTCSeconds(seconds);
  963. return dt;
  964. } catch(err) {
  965. console.log("Error while parsing date: " + err);
  966. return new Date();
  967. }
  968. }