diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..f8532a0 Binary files /dev/null and b/.DS_Store differ diff --git a/AccessToken.h b/AccessToken.h index 5fbeac6..1681edf 100644 --- a/AccessToken.h +++ b/AccessToken.h @@ -1,6 +1,6 @@ // // AccessToken.h -// Twittia 2 +// Tentia // // Created by Jeena Paradies on 19/09/2011. // Copyright 2011 __MyCompanyName__. All rights reserved. diff --git a/AccessToken.m b/AccessToken.m index 178a2bf..740e2ad 100644 --- a/AccessToken.m +++ b/AccessToken.m @@ -1,6 +1,6 @@ // // AccessToken.m -// Twittia 2 +// Tentia // // Created by Jeena Paradies on 19/09/2011. // Copyright 2011 __MyCompanyName__. All rights reserved. diff --git a/Appcast.xml b/Appcast.xml index 3ae68f8..ef1c5f9 100755 --- a/Appcast.xml +++ b/Appcast.xml @@ -1,17 +1,17 @@ - Twittia's Changelog - http://github.com/downloads/jeena/Twittia/Appcast.xml + Tentia's Changelog + http://github.com/downloads/jeena/Tentia/Appcast.xml Most recent changes with links to updates. en - Version 2.4.0 + Version 0.1.0 10.5.0 - http://jeenaparadies.net/twittia/ReleaseNotes.html + http://jeenaparadies.net/tentia/ReleaseNotes.html Sun, 02 Oct 2011 21:23:23 +0200 - diff --git a/Constants.h b/Constants.h index 99ab1e7..ea85a62 100644 --- a/Constants.h +++ b/Constants.h @@ -1,6 +1,6 @@ // // Constants.h -// Twittia 2 +// Tentia // // Created by Jeena on 01.05.10. // Licence: BSD (see attached LICENCE.txt file). @@ -22,8 +22,8 @@ #define OAUTH_ACCESS_TOKEN_URL @"http://twitter.com/oauth/access_token" #define OAUTH_SERVICE_NAME @"twitter.com" -#define APP_NAME @"Twittia" -#define TWEET_MAX_LENGTH 140 +#define APP_NAME @"Tentia" +#define MESSAGE_MAX_LENGTH 256 + (NSString *)stringFromVirtualKeyCode:(NSInteger)code; diff --git a/Constants.js b/Constants.js index d39a649..179892e 100644 --- a/Constants.js +++ b/Constants.js @@ -1,6 +1,6 @@ // -// TwittiaOauth.js -// Twittia 2 +// Constants.js +// Tentia // // Created by Jeena on 19.09.11. // Licence: BSD (see attached LICENCE.txt file). @@ -15,7 +15,7 @@ OAUTH_USER_AUTHORIZATION_URL = "http://twitter.com/oauth/authorize" OAUTH_ACCESS_TOKEN_URL = "http://twitter.com/oauth/access_token" OAUTH_SERVICE_NAME = "twitter.com" -APP_NAME = "Twittia"; +APP_NAME = "Tentia"; API_PATH = "http://api.twitter.com/1/"; WEBSITE_PATH = "http://twitter.com/"; diff --git a/Constants.m b/Constants.m index 74c9299..a40d9e2 100644 --- a/Constants.m +++ b/Constants.m @@ -1,6 +1,6 @@ // // Constants.m -// Twittia 2 +// Tentia // // Created by Jeena on 01.05.10. // Licence: BSD (see attached LICENCE.txt file). diff --git a/Controller.h b/Controller.h index 4235a63..cb976fc 100644 --- a/Controller.h +++ b/Controller.h @@ -1,6 +1,6 @@ // // Controller.h -// Twittia 2 +// Tentia // // Created by Jeena on 15.04.10. // Licence: BSD (see attached LICENCE.txt file). @@ -22,7 +22,7 @@ IBOutlet NSMenuItem *globalHotkeyMenuItem; IBOutlet NSImageView *logoLayer; ViewDelegate *viewDelegate; - WebView *twittiaOauthView; + WebView *oauthView; AccessToken *accessToken; } @@ -33,14 +33,14 @@ @property (retain, nonatomic) IBOutlet NSMenuItem *globalHotkeyMenuItem; @property (retain, nonatomic) IBOutlet NSImageView *logoLayer; @property (retain, nonatomic) IBOutlet ViewDelegate *viewDelegate; -@property (retain, nonatomic) WebView *twittiaOauthView; +@property (retain, nonatomic) WebView *oauthView; @property (retain, nonatomic) AccessToken *accessToken; - (void)initOauth; - (void)authentificationSucceded:(id)sender; - (void)initWebViews; - (void)initHotKeys; -- (void)openNewTweetWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId; +- (void)openNewMessageWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId; - (NSString *)pluginURL; - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; - (void)unreadMentions:(NSInteger)count; diff --git a/Controller.m b/Controller.m index 626978f..862fbe1 100644 --- a/Controller.m +++ b/Controller.m @@ -1,13 +1,13 @@ // // Controller.m -// Twittia 2 +// Tentia // // Created by Jeena on 15.04.10. // Licence: BSD (see attached LICENCE.txt file). // #import "Controller.h" -#import "NewTweetWindow.h" +#import "NewMessageWindow.h" #import "TweetModel.h" @@ -15,7 +15,7 @@ @synthesize timelineView, timelineViewWindow, mentionsView, mentionsViewWindow, globalHotkeyMenuItem, viewDelegate; @synthesize logoLayer; -@synthesize twittiaOauthView, accessToken; +@synthesize oauthView, accessToken; - (void)awakeFromNib { @@ -23,8 +23,8 @@ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self - selector:@selector(openNewTweetWindow:) - name:@"openNewTweetWindow" + selector:@selector(openNewMessageWindow:) + name:@"openNewMessageWindow" object:nil]; [nc addObserver:self selector:@selector(sendTweet:) @@ -64,13 +64,13 @@ NSString *index_string = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@/index_oauth.html", path] encoding:NSUTF8StringEncoding error:nil]; - twittiaOauthView = [[WebView alloc] init]; - viewDelegate.twittiaOauthView = twittiaOauthView; - [[twittiaOauthView mainFrame] loadHTMLString:index_string baseURL:url]; - [twittiaOauthView setFrameLoadDelegate:viewDelegate]; - [twittiaOauthView setPolicyDelegate:viewDelegate]; - [twittiaOauthView setUIDelegate:viewDelegate]; - [[twittiaOauthView windowScriptObject] setValue:self forKey:@"controller"]; + oauthView = [[WebView alloc] init]; + viewDelegate.oauthView = oauthView; + [[oauthView mainFrame] loadHTMLString:index_string baseURL:url]; + [oauthView setFrameLoadDelegate:viewDelegate]; + [oauthView setPolicyDelegate:viewDelegate]; + [oauthView setUIDelegate:viewDelegate]; + [[oauthView windowScriptObject] setValue:self forKey:@"controller"]; } - (void)initHotKeys { @@ -146,8 +146,8 @@ [mentionsView setPolicyDelegate:viewDelegate]; [mentionsView setUIDelegate:viewDelegate]; [[mentionsView windowScriptObject] setValue:self forKey:@"controller"]; - - [logoLayer removeFromSuperview]; + + // FIXME: show timelineView after authentification } + (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector { @@ -161,26 +161,26 @@ #pragma mark Notifications -- (IBAction)openNewTweetWindow:(id)sender { +- (IBAction)openNewMessageWindow:(id)sender { [NSApp activateIgnoringOtherApps:YES]; [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; } -- (void)openNewTweetWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId { +- (void)openNewMessageWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId { [NSApp activateIgnoringOtherApps:YES]; - NewTweetWindow *newTweet = (NewTweetWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; + NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; [newTweet inReplyTo:userName statusId:statusId]; } -- (void)openNewTweetWindowWithString:(NSString *)aString { +- (void)openNewMessageWindowWithString:(NSString *)aString { [NSApp activateIgnoringOtherApps:YES]; NSRange range = [aString rangeOfString:@"oauth_token"]; if (range.length > 0) { - [twittiaOauthView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"twittia_oauth.requestAccessToken('%@')", aString]]; + [oauthView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"tentia_oauth.requestAccessToken('%@')", aString]]; } else { - NewTweetWindow *newTweet = (NewTweetWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; + NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; [newTweet withString:aString]; } @@ -188,18 +188,18 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { NSString *text = [[[event paramDescriptorForKeyword:keyDirectObject] stringValue] substringFromIndex:8]; - [self openNewTweetWindowWithString:[text stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [self openNewMessageWindowWithString:[text stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } - (IBAction)sendTweet:(id)sender { TweetModel *tweet = (TweetModel *)[sender object]; - NSString *func = [NSString stringWithFormat:@"twittia_instance.sendNewTweet(\"%@\", \"%@\")", [tweet.text stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""], tweet.inReplyTostatusId]; + NSString *func = [NSString stringWithFormat:@"tentia_instance.sendNewMessage(\"%@\", \"%@\")", [tweet.text stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""], tweet.inReplyTostatusId]; [timelineView stringByEvaluatingJavaScriptFromString:func]; } - (NSString *)pluginURL { NSFileManager *fileManager = [NSFileManager defaultManager]; - NSString *pathToPlugin = [@"~/Library/Application Support/Twittia/Plugin.js" stringByExpandingTildeInPath]; + NSString *pathToPlugin = [@"~/Library/Application Support/Tentia/Plugin.js" stringByExpandingTildeInPath]; if([fileManager fileExistsAtPath:pathToPlugin]) { return [NSString stringWithFormat:@"%@", [NSURL fileURLWithPath:pathToPlugin]]; } @@ -208,12 +208,12 @@ - (void)unreadMentions:(NSInteger)count { if (![mentionsViewWindow isVisible] && count > 0) { - [timelineViewWindow setTitle:[NSString stringWithFormat:@"Twittia (@%i)", count]]; + [timelineViewWindow setTitle:[NSString stringWithFormat:@"Tentia (@%i)", count]]; [[[NSApplication sharedApplication] dockTile] setBadgeLabel:[NSString stringWithFormat:@"%i", count]]; } else { - [timelineViewWindow setTitle:[NSString stringWithFormat:@"Twittia"]]; + [timelineViewWindow setTitle:[NSString stringWithFormat:@"Tentia"]]; [[[NSApplication sharedApplication] dockTile] setBadgeLabel:nil]; - [mentionsView stringByEvaluatingJavaScriptFromString:@"twittia_instance.unread_mentions = 0;"]; + [mentionsView stringByEvaluatingJavaScriptFromString:@"tentia_instance.unread_mentions = 0;"]; } } @@ -241,8 +241,8 @@ } - (void)getTweetUpdates:(id)sender { - [timelineView stringByEvaluatingJavaScriptFromString:@"twittia_instance.getNewData(true)"]; - [mentionsView stringByEvaluatingJavaScriptFromString:@"twittia_instance.getNewData(true)"]; + [timelineView stringByEvaluatingJavaScriptFromString:@"tentia_instance.getNewData(true)"]; + [mentionsView stringByEvaluatingJavaScriptFromString:@"tentia_instance.getNewData(true)"]; } @@ -250,7 +250,7 @@ OSStatus handler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { - [[NSNotificationCenter defaultCenter] postNotificationName:@"openNewTweetWindow" object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"openNewMessageWindow" object:nil]; return noErr; } diff --git a/Core.js b/Core.js new file mode 100644 index 0000000..9c7dc2f --- /dev/null +++ b/Core.js @@ -0,0 +1,573 @@ +// +// Core.js +// Tentia +// +// Created by Jeena on 15.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +function Core(action) { + this.max_length = 100; + this.since_id; + this.timeout = 2 * 60 * 1000; + this.action = action; + this.getNewData(); + this.unread_mentions = 0; + + this.body = document.createElement("ol"); + this.body.className = this.action; + +/* + if (action == "home_timeline") { + this.usernames = []; + this.getUsernames("friends"); + this.getUsernames("followers"); + } +*/ +} + +Core.prototype.newStatus = function(status, supress_new_with_timeout) { + if(status != null) { + for(var i = status.length-1, c=0; i>=c; --i) { + if(this.body.childNodes.length > 0) { + if(this.body.childNodes.length > this.max_length) { + this.body.removeChild(this.body.lastChild); + } + this.body.insertBefore(this.getItem(status[i]), this.body.firstChild); + } else { + this.body.appendChild(this.getItem(status[i])); + } + } + } + + if(!supress_new_with_timeout) { + var _this = this; + setTimeout(function() { _this.getNewData() }, this.timeout); + } + if(this.action == "mentions" && this.is_not_init) { + this.unread_mentions += status.length; + controller.unreadMentions_(this.unread_mentions); + } + this.is_not_init = true; +} + +Core.prototype.getItem = function(status) { + var _this = this; + this.since_id = status.id_str; + + + if(status.retweeted_status != null) { + var original_status = status; + var status = status.retweeted_status; + } + + var template = this.getTemplate(); + + template.reply_to.onclick = function() { replyTo(status.user.screen_name, status.id_str); return false; } + template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; } + + template.image.src = status.user.profile_image_url; + template.username.innerText = status.user.screen_name; + template.username.href = WEBSITE_PATH + status.user.screen_name + + if(original_status != null) { + var retweeted = document.createElement("span") + retweeted.className = "retweeted"; + var retweeted_icon = document.createElement("span"); + retweeted_icon.innerText = " "; + retweeted.appendChild(retweeted_icon); + var retweeted_by = document.createElement("a"); + retweeted_by.innerText = original_status.user.screen_name + " "; + retweeted_by.href = WEBSITE_PATH + original_status.user.screen_name; + retweeted.appendChild(document.createTextNode("@")); + retweeted.appendChild(retweeted_by); + template.in_reply.parentNode.parentNode.insertBefore(retweeted, template.in_reply.parent); + } + + if(status.in_reply_to_status_id_str != null) template.in_reply.innerText = status.in_reply_to_screen_name; + else template.in_reply.parentNode.className = "hidden"; + template.in_reply.href = WEBSITE_PATH + status.in_reply_to_screen_name + "/status/" + status.in_reply_to_status_id_str; + + template.message.innerHTML = replaceTwitterLinks(replaceURLWithHTMLLinks(status.text, status.entities, template.message)); + + var time = document.createElement("abbr"); + time.innerText = status.created_at; + time.title = status.created_at; + time.className = "timeago"; + $(time).timeago(); + template.ago.appendChild(time); + template.ago.href = WEBSITE_PATH + status.user.screen_name + "/status/" + status.id_str; + + // {"type":"Point","coordinates":[57.10803113,12.25854746]} + if (status.geo && status.geo.type == "Point") { + template.geo.href = "http://maps.google.com/maps?q=" + status.geo.coordinates[0] + "," + status.geo.coordinates[1]; + template.geo.style.display = ""; + } + + template.source.innerHTML = status.source; + + if(status.entities.media) { + + for(var i=0; i 0) { + _this.getUsernames(type, data.next_cursor); + } + }, + error:function (xhr, ajaxOptions, thrownError) { + alert(xhr.status); + alert(thrownError); + } + }); +} + +Core.prototype.getUsernamesFromIds = function(ids) { + + var url = API_PATH + "users/lookup.json"; + var _this = this; + var parameters = { user_id:ids.join(",") }; + var message = { method:"GET" , action:url, parameters:parameters }; + + OAuth.completeRequest(message, + { consumerKey : OAUTH_CONSUMER_KEY + , consumerSecret: OAUTH_CONSUMER_SECRET + , token : controller.accessToken.accessToken() + , tokenSecret : controller.accessToken.secret() + }); + + $.ajax({ + beforeSend: function(xhr) { + xhr.setRequestHeader("Authorization", OAuth.getAuthorizationHeader("", message.parameters)); + }, + url: url + "?user_id=" + ids.join(","), + type: 'GET', + dataType: 'json', + success: function(data) { + for (var i=0; i < data.length; i++) { + _this.usernames.push(data[i].screen_name); + } + }, + error:function (xhr, ajaxOptions, thrownError) { + alert(xhr.status); + alert(thrownError); + } + }); +} + +Core.prototype.findUsernamesFor = function(query) { + var ret = []; + for (var i=0; i < this.usernames.length; i++) { + if(this.usernames[i].startsWith(query)) { + ret.push(this.usernames[i]); + } + } + return ret; +} + +/* Helper functions */ + +function replaceURLWithHTMLLinks(text, entities, message_node) { + var urls = entities.urls; + + for(var i = 0; i" + replace + ""); + + var media = null; + + // add thumbnail + if(replace.startsWith("http://youtube.com/") || replace.startsWith("http://www.youtube.com/")) { + var v = getUrlVars(replace)["v"]; + if (v) { + media = { + type: "tentia_youtube", + url: original, + media_url: "http://img.youtube.com/vi/" + v + "/1.jpg" + } + } + + } else if (replace.startsWith("http://twitpic.com/")) { + media = { + type: "tentia_photo", + url: original, + media_url: "http://twitpic.com/show/mini/" + replace.substring("http://twitpic.com/".length) + } + + } else if (replace.startsWith("http://yfrog")) { + media = { + type: "tentia_photo", + url: original, + media_url: replace + ":small" + } + + } else if (replace.startsWith("http://instagr.am/p/") || replace.startsWith("http://instagram.com/p/")) { + media = { + type: "tentia_photo", + url: original, + media_url: replace + "media?size=t" + } + } + + if(media) { + if(entities.media) { + entities.media.push(media); + } else { + entities.media = [media]; + } + } + + } + + return text; +} + +function replaceTwitterLinks(text) { + var username = /(^|\s)(@)(\w+)/ig; + var hash = /(^|\s)(#)(\w+)/ig; + text = text.replace(username, "$1$2$3"); + return text.replace(hash, "$1$2$3"); +} + +function replyTo(username, status_id) { + controller.openNewMessageWindowInReplyTo_statusId_(username, status_id); +} + +function loadPlugin(url) { + var plugin = document.createElement("script"); + plugin.type = "text/javascript"; + plugin.src = url; + document.getElementsByTagName("head")[0].appendChild(plugin); +} + +String.prototype.startsWith = function(prefix) { + return this.indexOf(prefix) === 0; +} + +String.prototype.endsWith = function(suffix) { + return this.match(suffix+"$") == suffix; +}; + +function getUrlVars(url) +{ + var vars = [], hash; + if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#")); + var hashes = url.slice(url.indexOf('?') + 1).split('&'); + for(var i = 0; i < hashes.length; i++) + { + hash = hashes[i].split('='); + vars.push(hash[0]); + vars[hash[0]] = hash[1]; + } + return vars; +} + +function replaceShortened(url, message_node) { + var api = "http://api.bitly.com"; + if(url.startsWith("http://j.mp/")) { + api = "http://api.j.mp"; + } + + var api_url = api + "/v3/expand?format=json&apiKey=R_4fc2a1aa461d076556016390fa6400f6&login=twittia&shortUrl=" + url; // FIXME: new api key + + $.ajax({ + url: api_url, + success: function(data) { + var new_url = data.data.expand[0].long_url; + if (new_url) { + var regex = new RegExp(url, "g"); + message_node.innerHTML = message_node.innerHTML.replace(regex, new_url); + } + }, + error:function (xhr, ajaxOptions, thrownError) { + alert(xhr.status); + alert(thrownError); + } + }); +} + +var tentia_instance; diff --git a/English.lproj/Credits.rtf b/English.lproj/Credits.rtf index 9161c9d..349fb7b 100644 --- a/English.lproj/Credits.rtf +++ b/English.lproj/Credits.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf170 +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 {\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} \viewkind0 @@ -16,7 +16,7 @@ \b Documentation: \b0 \ - http://github.com/jeena/Twittia/wiki\ + http://github.com/jeena/Tentia/wiki\ \ \b With special thanks to: diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib index 3fe2d8f..59786be 100644 --- a/English.lproj/MainMenu.xib +++ b/English.lproj/MainMenu.xib @@ -1,11 +1,11 @@ - 1050 - 11C43 - 1617 - 1138.17 - 567.00 + 1080 + 12C60 + 2843 + 1187.34 + 625.00 YES @@ -13,22 +13,20 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.WebKitIBPlugin - + YES - 1617 - 518 + 2843 + 1810 YES - NSView - NSMenu - NSWindowTemplate - NSMenuItem - WebView - NSImageCell - NSImageView NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + WebView YES @@ -36,11 +34,8 @@ com.apple.WebKitIBPlugin - YES - - YES - - + PluginDependencyRecalculationVersion + YES @@ -780,7 +775,7 @@ 2 {{712, 280}, {397, 581}} 1685586944 - Twittia + Tentia NSWindow @@ -823,59 +818,24 @@ 13 YES - + + YES + NO YES - - - 274 - - YES - - YES - Apple PDF pasteboard type - Apple PICT pasteboard type - Apple PNG pasteboard type - NSFilenamesPboardType - NeXT Encapsulated PostScript v1.2 pasteboard type - NeXT TIFF v4.0 pasteboard type - - - {{17, 17}, {363, 547}} - - - YES - - 67239424 - 33554432 - - NSImage - Icon - - - LucidaGrande - 13 - 1044 - - 0 - 3 - 0 - NO - - YES - {397, 581} + - {{0, 0}, {1920, 1178}} + {{0, 0}, {2560, 1418}} {10000000000000, 10000000000000} - twittia + tentia YES @@ -938,7 +898,7 @@ {376, 581} - {{0, 0}, {1920, 1178}} + {{0, 0}, {2560, 1418}} {10000000000000, 10000000000000} mentions YES @@ -947,6 +907,30 @@ YES + + + terminate: + + + + 448 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 564 + performMiniaturize: @@ -963,14 +947,6 @@ 39 - - - orderFrontStandardAboutPanel: - - - - 142 - performClose: @@ -1179,14 +1155,6 @@ 371 - - - terminate: - - - - 448 - capitalizeWord: @@ -1291,22 +1259,6 @@ 540 - - - checkForUpdates: - - - - 543 - - - - makeKeyAndOrderFront: - - - - 547 - timelineView @@ -1323,22 +1275,6 @@ 562 - - - makeKeyAndOrderFront: - - - - 563 - - - - delegate - - - - 564 - timelineViewWindow @@ -1355,14 +1291,6 @@ 566 - - - delegate - - - - 569 - globalHotkeyMenuItem @@ -1372,12 +1300,36 @@ 570 - - logoLayer - - + + makeKeyAndOrderFront: + + - 589 + 547 + + + + checkForUpdates: + + + + 543 + + + + makeKeyAndOrderFront: + + + + 563 + + + + delegate + + + + 569 @@ -1961,6 +1913,7 @@ + Timeline 536 @@ -1968,7 +1921,6 @@ YES - @@ -2022,20 +1974,6 @@ - - 587 - - - YES - - - - - - 588 - - - @@ -2131,8 +2069,6 @@ 561.IBPluginDependency 57.IBPluginDependency 58.IBPluginDependency - 587.IBPluginDependency - 588.IBPluginDependency 72.IBPluginDependency 73.IBPluginDependency 79.IBPluginDependency @@ -2141,7 +2077,7 @@ 83.IBPluginDependency 92.IBPluginDependency - + YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -2239,8 +2175,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin @@ -2275,7 +2209,7 @@ timelineViewWindow viewDelegate - + YES NSMenuItem NSImageView @@ -2298,7 +2232,7 @@ timelineViewWindow viewDelegate - + YES globalHotkeyMenuItem @@ -2373,32 +2307,10 @@ ./Classes/ViewDelegate.h - - WebView - - reloadFromOrigin: - id - - - reloadFromOrigin: - - reloadFromOrigin: - id - - - - IBProjectSource - ./Classes/WebView.h - - 0 IBCocoaFramework - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 @@ -2409,15 +2321,13 @@ YES YES - Icon NSMenuCheckmark NSMenuMixedState - + YES - {512, 512} - {9, 8} - {7, 2} + {11, 11} + {10, 3} diff --git a/English.lproj/NewTweetWindow.xib b/English.lproj/NewMessageWindow.xib similarity index 68% rename from English.lproj/NewTweetWindow.xib rename to English.lproj/NewMessageWindow.xib index 31ad68a..a41ce8c 100644 --- a/English.lproj/NewTweetWindow.xib +++ b/English.lproj/NewMessageWindow.xib @@ -2,37 +2,34 @@ 1050 - 11C43 - 1617 - 1138.17 - 567.00 + 12C54 + 2843 + 1187.34 + 625.00 com.apple.InterfaceBuilder.CocoaPlugin - 1617 + 2843 YES + NSCustomObject NSTextField NSTextFieldCell - NSWindowTemplate NSView - NSCustomObject + NSWindowTemplate YES com.apple.InterfaceBuilder.CocoaPlugin - YES - - YES - - + PluginDependencyRecalculationVersion + YES - NewTweetWindow + NewMessageWindow FirstResponder @@ -48,7 +45,7 @@ {94, 86} - + 256 YES @@ -57,10 +54,9 @@ 274 {{0, 22}, {299, 91}} - YES - -1809711615 + -1809842175 272629760 @@ -89,16 +85,16 @@ + NO 268 {{257, 2}, {38, 17}} - YES - 68288064 + 68157504 71304192 140 @@ -119,11 +115,10 @@ + NO {299, 113} - - {{0, 0}, {1440, 878}} {94, 108} @@ -164,14 +159,6 @@ 100034 - - - delegate - - - - 100035 - counter @@ -180,13 +167,23 @@ 100038 + + + delegate + + + + 100035 + YES 0 - + + YES + @@ -273,7 +270,7 @@ 5.IBWindowTemplateEditedContentRect 6.IBPluginDependency - + YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -301,129 +298,7 @@ 100038 - - - YES - - NSDocument - - YES - - YES - printDocument: - revertDocumentToSaved: - runPageLayout: - saveDocument: - saveDocumentAs: - saveDocumentTo: - - - YES - id - id - id - id - id - id - - - - YES - - YES - printDocument: - revertDocumentToSaved: - runPageLayout: - saveDocument: - saveDocumentAs: - saveDocumentTo: - - - YES - - printDocument: - id - - - revertDocumentToSaved: - id - - - runPageLayout: - id - - - saveDocument: - id - - - saveDocumentAs: - id - - - saveDocumentTo: - id - - - - - IBProjectSource - ./Classes/NSDocument.h - - - - NewTweetWindow - NSDocument - - sendTweet: - NSControl - - - sendTweet: - - sendTweet: - NSControl - - - - YES - - YES - counter - textField - - - YES - NSTextField - NSTextField - - - - YES - - YES - counter - textField - - - YES - - counter - NSTextField - - - textField - NSTextField - - - - - IBProjectSource - ./Classes/NewTweetWindow.h - - - - + 0 IBCocoaFramework diff --git a/Icon.icns b/Icon.icns index c365038..4359f24 100644 Binary files a/Icon.icns and b/Icon.icns differ diff --git a/Icon.png b/Icon.png new file mode 100644 index 0000000..fbf6160 Binary files /dev/null and b/Icon.png differ diff --git a/NewTweetWindow.h b/NewMessageWindow.h similarity index 90% rename from NewTweetWindow.h rename to NewMessageWindow.h index ea4c970..2ed4270 100644 --- a/NewTweetWindow.h +++ b/NewMessageWindow.h @@ -1,6 +1,6 @@ // // NewTweetWindow.h -// Twittia 2 +// Tentia // // Created by Jeena on 16.04.10. // Licence: BSD (see attached LICENCE.txt file). @@ -10,7 +10,7 @@ #import -@interface NewTweetWindow : NSDocument +@interface NewMessageWindow : NSDocument { IBOutlet NSTextField *textField; IBOutlet NSTextField *counter; diff --git a/NewTweetWindow.m b/NewMessageWindow.m similarity index 95% rename from NewTweetWindow.m rename to NewMessageWindow.m index c6cdd9e..df0b871 100644 --- a/NewTweetWindow.m +++ b/NewMessageWindow.m @@ -1,16 +1,16 @@ // // NewTweetWindow.m -// Twittia 2 +// Tentia // // Created by Jeena on 16.04.10. // Licence: BSD (see attached LICENCE.txt file). // -#import "NewTweetWindow.h" +#import "NewMessageWindow.h" #import "Constants.h" #import "TweetModel.h" -@implementation NewTweetWindow +@implementation NewMessageWindow @synthesize textField, counter; @@ -31,7 +31,7 @@ { // Override returning the nib file name of the document // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead. - return @"NewTweetWindow"; + return @"NewMessageWindow"; } - (NSString *)displayName { @@ -101,7 +101,7 @@ #pragma mark Keyboard delegate methods - (IBAction)sendTweet:(NSControl *)control { - if ([[control stringValue] length] <= TWEET_MAX_LENGTH) { + if ([[control stringValue] length] <= MESSAGE_MAX_LENGTH) { TweetModel *tweet = [[[TweetModel alloc] init] autorelease]; tweet.text = [control stringValue]; tweet.inReplyTostatusId = inReplyTostatusId; diff --git a/OauthImplementation.js b/OauthImplementation.js new file mode 100644 index 0000000..e446025 --- /dev/null +++ b/OauthImplementation.js @@ -0,0 +1,174 @@ +// +// OauthImplementation.js +// Tentia +// +// Created by Jeena on 19.09.11. +// Licence: BSD (see attached LICENCE.txt file). +// + +MY_ENTITY = "https://jeena.tent.is"; + +function getURL(url, type, callback, data) { + $.ajax({ + url: url, + accepts: "application/vnd.tent.v0+json", + contentType: "application/vnd.tent.v0+json", + type: type, + complete: callback, + data: data, + processData: false, + error: function(xhr, ajaxOptions, thrownError) { + alert(xhr.statusText); + alert(ajaxOptions); + alert(thrownError); + } +}); +} + +function OauthImplementation() { + this.requestProfileURL(MY_ENTITY); + //this.requestAToken(); +} + +OauthImplementation.prototype.requestProfileURL = function (entity) { + var those = this; + getURL(entity, "HEAD", function(resp) { + var headers = resp.getAllResponseHeaders(); + var regex = /Link: <([^>]*)>; rel="https:\/\/tent.io\/rels\/profile"/; + var matches = headers.match(regex) + alert(matches[1]); + those.register(matches[1]); + }); + +} + +OauthImplementation.prototype.register = function (url) { + + var app_info = { + "name": "Tentia", + "description": "A small TentStatus client.", + "url": "http://jabs.nu/Tentia/", + "icon": "http://jabs.nu/Tentia/icon.png", + "redirect_uris": [ + "tentia://oauth_token" + ], + "scopes": { + "read_posts": "Uses posts to show them in a list", + "write_posts": "Posts on users behalf" + } + }; + + var those = this; + getURL(url, "GET", function(resp) { + var profile = JSON.parse(resp.responseText); + var server = profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0]; + var callback = function(resp) { + alert(JSON.parse(resp.responseText)); + } + getURL(server + "/apps", "POST", callback, JSON.stringify(app_info)); + }); +} + + + + + + + +OauthImplementation.prototype.requestAToken = function() { + var url = OAUTH_REQUEST_TOKEN_URL; + var _this = this; + + var message = { method:"POST" , action:url }; + + OAuth.completeRequest(message, + { consumerKey : OAUTH_CONSUMER_KEY + , consumerSecret: OAUTH_CONSUMER_SECRET + //, token : controller.oauth.accessToken.key + //, tokenSecret : controller.oauth.accessToken.secret + }); + + $.ajax({ + beforeSend: function(xhr) { + xhr.setRequestHeader("Authorization", OAuth.getAuthorizationHeader("", message.parameters)); + }, + url: url, + type: 'POST', + dataType: 'text', + success: function(data) { + _this.requestTokenTicketFinished(data); + }, + error:function (xhr, ajaxOptions, thrownError) { + alert(xhr.statusText); + alert(ajaxOptions); + alert(thrownError); + } + }); + +} + +OauthImplementation.prototype.requestTokenTicketFinished = function(data) { + controller.openURL_(OAUTH_USER_AUTHORIZATION_URL + "?" + data); +} + +OauthImplementation.prototype.requestAccessToken = function(responseBody) { + // "twittia://oauth_token?oauth_token=jCcf7ClzJMbE4coZdONi467OAQxRGOBZJsuopG8C8&oauth_verifier=BK2ZkAIz51lqI4qta8MnKc280GyDLy0OQBpdsEmjT40" + + var urlVars = getUrlVars(responseBody); + + var url = OAUTH_ACCESS_TOKEN_URL; + var _this = this; + var accessTokenKey = getUrlVars(responseBody) + + var message = { method:"POST" , action:url }; + + OAuth.completeRequest(message, + { consumerKey : OAUTH_CONSUMER_KEY + , consumerSecret: OAUTH_CONSUMER_SECRET + , token : urlVars["oauth_token"] + , tokenSecret : urlVars["oauth_verifier"] + }); + + $.ajax({ + beforeSend: function(xhr) { + xhr.setRequestHeader("Authorization", OAuth.getAuthorizationHeader("", message.parameters)); + }, + url: url, + type: 'POST', + dataType: 'text', + success: function(data) { + _this.requestAccessTokenTicketFinished(data); + }, + error:function (xhr, ajaxOptions, thrownError) { + alert(xhr.statusText); + alert(ajaxOptions); + alert(thrownError); + } + }); +} + +OauthImplementation.prototype.requestAccessTokenTicketFinished = function(responseBody) { + var urlVars = getUrlVars(responseBody); + controller.storeAccessToken_secret_userId_andScreenName_( + urlVars["oauth_token"], + urlVars["oauth_token_secret"], + urlVars["user_id"], + urlVars["screen_name"] + ); +} + +function getUrlVars(url) +{ + var vars = [], hash; + if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#")); + var hashes = url.slice(url.indexOf('?') + 1).split('&'); + for(var i = 0; i < hashes.length; i++) + { + hash = hashes[i].split('='); + vars.push(hash[0]); + vars[hash[0]] = hash[1]; + } + return vars; +} + +var tentia_oauth; \ No newline at end of file diff --git a/README.markdown b/README.markdown index 23d4a62..137aee6 100644 --- a/README.markdown +++ b/README.markdown @@ -1,42 +1,36 @@ -Twittia +Tentia ======= -Twittia is a slim Twitter client for OS X written in mostly JavaScript. -It doesn't implement much of Twitters functionality, only the things **I** +Tentia is a slim Tent client for OS X written in mostly JavaScript. +It doesn't implement much of Tents functionality, only the things **I** care for. Therefore it is **small** and **fast** and looks good by doing so. _"Keep it simple, stupid!"_ Is the mantra, therefore there will not by much more functionality as it is now. But you're welcome to fork and extend it. -[Download Twittia 2](http://github.com/downloads/jeena/Twittia/Twittia.app.zip) +[Download Tentia](http://github.com/downloads/jeena/Tentia/Ttentia.app.zip) It works on Mac OS 10.5 and higher. -![Twittia screenshot](http://github.com/downloads/jeena/Twittia/Screen-shot.png) +![Tentia screenshot](http://github.com/downloads/jeena/Tentia/Screen-shot.png) FAQ:s ----- -1. The global hotkey for a new Tweet is: `Ctrl Alt Cmd t` +1. The global hotkey for a new Message is: `Ctrl Alt Cmd m` -2. Yes there is a twittia: url scheme. +2. Yes there is a tentia: url scheme. 3. Yes, there is a JavaScript-plugin-API. Create this file: - `~/Library/Application Support/Twittia/Plugin.js` + `~/Library/Application Support/Tentia/Plugin.js` + +4. Yes, you can change the look through CSS. Create this file: + `~/Library/Application Support/Tentia/Style.css` + Nice to know ------------ -There was a original Twittia 1 which was written in Ruby-Cocoa, it was -quite ok back then, but the code was a mess. And then along came -Tweetie and I lost the desire to write my own Twitter client, because -it was so much further then twittia and looked nicer and so on. - -But now Tweetie wasn't update for a really long time, and I really -wanted to see retweets in my stream so I decided to rip out the look -from Twittia 1 and implement it in a new much slimmer version. - -And because Twitter offers a JSON API and Twittias rendering Engine is -just a simple WebKit WebView I implemented the core functionality in -JavaScript and am very happy with it. \ No newline at end of file +Originally the code was written for a Twitter client called +[Twittia](https://github.com/jeena/Twittia/wiki). \ No newline at end of file diff --git a/ReleaseNotes.html b/ReleaseNotes.html index 2477f8a..a75be7d 100644 --- a/ReleaseNotes.html +++ b/ReleaseNotes.html @@ -2,7 +2,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - Twittia Release Notes + Tentia Release Notes