Merge branch 'master' of github.com:jeena/Tentia into linux

This commit is contained in:
Jeena Paradies 2012-11-10 11:46:47 +01:00
commit d3e988fe2e
171 changed files with 14997 additions and 944 deletions

BIN
.DS_Store vendored

Binary file not shown.

4
.gitignore vendored
View file

@ -1,4 +1,4 @@
build/
Tentia.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/UserInterfaceState.xcuserstate
Mac/build/
Mac/Tentia.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/UserInterfaceState.xcuserstate
dsa_priv.pem
*.pyc

View file

@ -1,21 +0,0 @@
//
// Constants.js
// Tentia
//
// Created by Jeena on 19.09.11.
// Licence: BSD (see attached LICENCE.txt file).
//
OAUTH_CONSUMER_KEY = "JPmU8KJhiBKfpohCiWLg"
OAUTH_CONSUMER_SECRET = "jtfSrnDrRcUnL1nqTMcAW0055m63EMClmkxhiBjQ"
OAUTH_SIGNATURE_METHOD = "HMAC-SHA1"
OAUTH_REQUEST_TOKEN_URL = "http://twitter.com/oauth/request_token"
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 = "Tentia";
API_PATH = "http://api.twitter.com/1/";
WEBSITE_PATH = "http://twitter.com/";

457
Core.js
View file

@ -1,457 +0,0 @@
//
// Core.js
// Tentia
//
// Created by Jeena on 15.04.10.
// Licence: BSD (see attached LICENCE.txt file).
//
function Core(action) {
this.max_length = 20;
// this.timeout = 2 * 60 * 1000;
this.timeout = 10 * 1000; // every 10 seconds
this.action = action;
this.getNewData();
this.unread_mentions = 0;
this.since_id = null;
this.since_id_entity = null;
this.since_time = 0;
this.body = document.createElement("ol");
this.body.className = this.action;
this.cache = {};
this.is_not_init = false;
var _this = this;
setInterval(function() { _this.getNewData() }, this.timeout);
}
Core.prototype.newStatus = function(status) {
if(status != null && status.length > 0) {
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(this.action == "mentions" && this.is_not_init) {
this.unread_mentions += status.length;
controller.unreadMentions_(this.unread_mentions);
}
this.is_not_init = true;
}
Core.prototype.logout = function() {
this.body.innerHTML = "";
}
Core.prototype.getItem = function(status) {
var _this = this;
this.since_id = status.id;
this.since_id_entity = status.entity;
var template = this.getTemplate();
template.reply_to.onclick = function() {
var mentions = [];
for (var i = 0; i < status.mentions.length; i++) {
var mention = status.mentions[i];
if(mention.entity != controller.stringForKey_("entity"))
mentions.push(mention);
};
replyTo(status.entity, status.id, mentions);
return false;
}
//template.retweet.onclick = function() { template.retweet.className = "hidden"; _this.retweet(status.id_str, template.item); return false; }
template.username.innerText = status.entity;
template.username.href = status.entity; // FIXME open profile
findProfileURL(status.entity, function(profile_url) {
if (profile_url) {
getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
template.username.title = template.username.innerText;
template.username.innerText = basic.name;
}
if(basic.avatar_url) {
template.image.onerror = function() { template.image.src = 'default-avatar.png' };
template.image.src = basic.avatar_url;
}
}
}, null, false); // do not send auth-headers
}
});
template.in_reply.parentNode.className = "hidden";
template.message.innerHTML = replaceUsernamesWithLinks(replaceURLWithHTMLLinks(status.content.text, status.entities, template.message));
findMentions(template.message, status.mentions);
var time = document.createElement("abbr");
time.innerText = ISODateString(new Date(status.published_at * 1000));
time.title = time.innerText;
time.className = "timeago";
$(time).timeago();
template.ago.appendChild(time);
// {"type":"Point","coordinates":[57.10803113,12.25854746]}
if (status.content && status.content.location && status.content.location.type == "Point") {
template.geo.href = "http://maps.google.com/maps?q=" + status.content.location.coordinates[0] + "," + status.content.location.coordinates[1];
template.geo.style.display = "";
}
template.source.href = status.app.url;
template.source.innerHTML = status.app.name;
template.source.title = status.app.url;
return template.item;
}
Core.prototype.getTemplate = function() {
if(this.template == "undefined") {
return jQuery.extend(true, {}, this.template);
}
var a = document.createElement("a");
var item = document.createElement("li");
var reply_to = a.cloneNode();
reply_to.className = "reply_to"
reply_to.innerText = " ";
reply_to.href = "#";
item.appendChild(reply_to);
var retweet = a.cloneNode();
retweet.className = "retweet";
retweet.innerText = " ";
retweet.href = "#";
// item.appendChild(retweet); // FIXME
var image = document.createElement("img");
image.className = "image";
image.src = "default-avatar.png";
image.onmousedown = function(e) { e.preventDefault(); };
item.appendChild(image);
var image_username = a.cloneNode();
image.appendChild(image_username);
var data = document.createElement("div");
data.className = "data";
item.appendChild(data);
var head = document.createElement("h1");
data.appendChild(head);
var username = a.cloneNode();
head.appendChild(username);
var in_reply = document.createElement("span");
in_reply.className = "reply";
head.appendChild(in_reply);
var space = document.createTextNode(" ");
head.appendChild(space);
var geo = document.createElement("a");
geo.style.display = "none";
head.appendChild(geo);
var pin = document.createElement("img");
pin.src = "pin.png";
pin.alt = "Map link";
geo.appendChild(pin);
var in_reply_text = document.createTextNode(" in reply to ");
in_reply.appendChild(in_reply_text)
var in_reply_a = a.cloneNode();
in_reply.appendChild(in_reply_a);
var message = document.createElement("p");
message.className = "message";
data.appendChild(message);
var images = document.createElement("p")
images.className = "images";
data.appendChild(images);
var date = message.cloneNode();
date.className = "date";
data.appendChild(date);
var ago = a.cloneNode();
date.appendChild(ago);
var from = document.createTextNode(" from ");
date.appendChild(from)
var source = document.createElement("a");
source.className = "source";
date.appendChild(source)
this.template = {
item: item,
reply_to: reply_to,
retweet: retweet,
image: image,
username: username,
in_reply: in_reply_a,
message: message,
ago: ago,
source: source,
geo: geo,
images: images
}
return jQuery.extend(true, {}, this.template);
}
Core.prototype.getNewData = function() {
var those = this;
var url = URI(mkApiRootPath("/posts"));
url.addSearch("post_types", "https://tent.io/types/post/status/v0.1.0");
url.addSearch("limit", this.max_length);
if(this.since_id) {
url.addSearch("since_id", this.since_id);
url.addSearch("since_id_entity", this.since_id_entity);
}
if (this.action == "mentions") {
url.addSearch("mentioned_entity", controller.stringForKey_("entity"));
}
var http_method = "GET";
var callback = function(resp) {
try {
var json = JSON.parse(resp.responseText)
} catch (e) {
//alert(resp.responseText);
alert(url + " JSON parse error");
throw e;
}
those.newStatus(json);
}
var data = null;
if (controller.stringForKey_("user_access_token")) {
getURL(url.toString(), http_method, callback, data); // FIXME: error callback
}
}
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity) {
var _this = this;
var url = URI(mkApiRootPath("/posts"));
var http_method = "POST";
var callback = function(data) { _this.getNewData(); }
var data = {
"type": "https://tent.io/types/post/status/v0.1.0",
"published_at": (new Date().getTime() / 1000),
"permissions": {
"public": true
},
"content": {
"text": content,
},
};
var mentions = parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
if (mentions.length > 0) {
data["mentions"] = mentions;
}
getURL(url.toString(), http_method, callback, JSON.stringify(data)); // FIXME: error callback
}
/* Helper functions */
function replaceURLWithHTMLLinks(text, entities, message_node) {
var exp = /(([^\^]https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_()|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
return text.replace(exp, "<a href='$1'>$1</a>");
}
function replaceUsernamesWithLinks(text, mentions) {
return text; // FIXME!
var username = /(^|\s)(\^)(\w+)/ig;
var hash = /(^|\s)(#)(\w+)/ig;
text = text.replace(username, "$1$2<a href='tentia://profile/$3'>$3</a>");
return text.replace(hash, "$1$2<a href='http://search.twitter.com/search?q=%23$3'>$3</a>");
}
function replyTo(entity, status_id, mentions) {
var string = "^" + entity.replace("https://", "") + " ";
for (var i = 0; i < mentions.length; i++) {
var e = mentions[i].entity.replace("https://", "");
if(string.indexOf(e) == -1) string += "^" + e + " ";
}
controller.openNewMessageWindowInReplyTo_statusId_withString_(entity, status_id, string);
}
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);
}
});
}
function findMentions(node, mentions) {
var text = node.innerHTML;
var mentions_in_text = [];
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var name = res[i];
var e = name.substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
for (var j = 0; j < mentions.length; j++) {
var m = mentions[j];
if(m.entity.startsWith(e)) {
mentions_in_text.push({
entity: m.entity,
text: name
});
}
}
}
}
for (var i = 0; i < mentions_in_text.length; i++) {
var mention = mentions_in_text[i];
(function(mention) { // need this closure
findProfileURL(mention.entity, function(profile_url) {
if (profile_url) {
getURL(profile_url, "GET", function(resp) {
var profile = JSON.parse(resp.responseText);
var basic = profile["https://tent.io/types/info/basic/v0.1.0"];
if (profile && basic) {
if(basic.name) {
var new_text = node.innerHTML.replace(
mention.text,
"<strong class='name' title='" + mention.entity + "'" + ">"
+ basic.name
+ "</strong>"
);
node.innerHTML = new_text;
}
}
}, null, false); // do not send auth-headers
}
});
})(mention);
}
}
function parseMentions(text, post_id, entity) {
var mentions = [];
if (post_id && entity) {
mentions.push({
post: post_id,
entity: entity
})
}
var res = text.match(/(\^\S+)/ig);
if (res) {
for (var i = 0; i < res.length; i++) {
var e = res[i].substring(1);
if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") {
e = "https://" + e;
}
if (e != entity) {
mentions.push({entity:e});
}
}
}
return mentions;
}
function ISODateString(d){
function pad(n){return n<10 ? '0'+n : n}
return d.getUTCFullYear()+'-'
+ pad(d.getUTCMonth()+1)+'-'
+ pad(d.getUTCDate())+'T'
+ pad(d.getUTCHours())+':'
+ pad(d.getUTCMinutes())+':'
+ pad(d.getUTCSeconds())+'Z'
}
var tentia_instance;

BIN
Mac/.DS_Store vendored Normal file

Binary file not shown.

View file

@ -14,11 +14,13 @@
#import "AccessToken.h"
@interface Controller : NSObject {
@interface Controller : NSObject <NSUserNotificationCenterDelegate> {
IBOutlet WebView *timelineView;
IBOutlet NSWindow *timelineViewWindow;
IBOutlet WebView *mentionsView;
IBOutlet NSWindow *mentionsViewWindow;
IBOutlet WebView *conversationView;
IBOutlet NSWindow *conversationViewWindow;
NSWindow *loginViewWindow;
NSProgressIndicator *loginActivityIndicator;
IBOutlet NSMenuItem *globalHotkeyMenuItem;
@ -32,6 +34,8 @@
@property (retain, nonatomic) IBOutlet NSWindow *timelineViewWindow;
@property (retain, nonatomic) IBOutlet WebView *mentionsView;
@property (retain, nonatomic) IBOutlet NSWindow *mentionsViewWindow;
@property (retain, nonatomic) IBOutlet WebView *conversationView;
@property (retain, nonatomic) IBOutlet NSWindow *conversationViewWindow;
@property (assign) IBOutlet NSWindow *loginViewWindow;
@property (assign) IBOutlet NSProgressIndicator *loginActivityIndicator;
@property (retain, nonatomic) IBOutlet NSMenuItem *globalHotkeyMenuItem;
@ -47,7 +51,9 @@
- (void)openNewMessageWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string;
- (NSString *)pluginURL;
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
- (void)unreadMentions:(NSInteger)count;
- (void)unreadMentions:(int)count;
- (void)notificateUserAboutMention:(NSString *)text fromName:(NSString *)name withPostId:(NSString *)postId andEntity:(NSString *)entity;
- (void)openURL:(NSString *)url;
- (void)setString:(NSString *)string forKey:(NSString *)aKey;
@ -58,6 +64,8 @@
- (IBAction)login:(id)sender;
- (IBAction)logout:(id)sender;
- (IBAction)showConversationForPostId:(NSString *)postId andEntity:(NSString *)entity;
OSStatus handler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData);

View file

@ -15,13 +15,15 @@
@synthesize loginViewWindow;
@synthesize loginActivityIndicator;
@synthesize timelineView, timelineViewWindow, mentionsView, mentionsViewWindow, globalHotkeyMenuItem, viewDelegate;
@synthesize timelineView, timelineViewWindow, mentionsView, mentionsViewWindow, conversationView, conversationViewWindow;
@synthesize globalHotkeyMenuItem, viewDelegate;
@synthesize logoLayer;
@synthesize oauthView, accessToken;
- (void)awakeFromNib {
[self initHotKeys];
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
@ -53,6 +55,10 @@
accessToken = [[AccessToken alloc] init];
//[accessToken setString:nil forKey:@"user_access_token"];
if (![accessToken stringForKey:@"version-0.2.0-new-login"]) {
[self logout:self];
[accessToken setString:@"yes" forKey:@"version-0.2.0-new-login"];
}
if (![accessToken stringForKey:@"user_access_token"]) {
[timelineViewWindow performClose:self];
@ -66,10 +72,9 @@
- (void)initOauth {
if (!oauthView) {
NSString *path = [[NSBundle mainBundle] resourcePath];
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/Webkit/"];
NSURL *url = [NSURL fileURLWithPath:path];
NSString *index_string = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@/index_oauth.html", path] encoding:NSUTF8StringEncoding error:nil];
NSString *index_string = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@index.html", path] encoding:NSUTF8StringEncoding error:nil];
oauthView = [[WebView alloc] init];
viewDelegate.oauthView = oauthView;
@ -78,11 +83,44 @@
[oauthView setPolicyDelegate:viewDelegate];
[oauthView setUIDelegate:viewDelegate];
[[oauthView windowScriptObject] setValue:self forKey:@"controller"];
//[oauthView stringByEvaluatingJavaScriptFromString:@"function HostAppGo() { start('oauth'); };"];
} else {
[oauthView stringByEvaluatingJavaScriptFromString:@"tentia_oauth.authenticate()"];
[oauthView stringByEvaluatingJavaScriptFromString:@"start('oauth');"];
}
}
- (void)initWebViews {
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/Webkit/"];
NSURL *url = [NSURL fileURLWithPath:path];
NSString *index_string = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@index.html", path] encoding:NSUTF8StringEncoding error:nil];
viewDelegate.timelineView = timelineView;
[[timelineView mainFrame] loadHTMLString:index_string baseURL:url];
[timelineView setFrameLoadDelegate:viewDelegate];
[timelineView setPolicyDelegate:viewDelegate];
[timelineView setUIDelegate:viewDelegate];
[[timelineView windowScriptObject] setValue:self forKey:@"controller"];
viewDelegate.mentionsView = mentionsView;
[[mentionsView mainFrame] loadHTMLString:index_string baseURL:url];
[mentionsView setFrameLoadDelegate:viewDelegate];
[mentionsView setPolicyDelegate:viewDelegate];
[mentionsView setUIDelegate:viewDelegate];
[[mentionsView windowScriptObject] setValue:self forKey:@"controller"];
viewDelegate.conversationView = conversationView;
[[conversationView mainFrame] loadHTMLString:index_string baseURL:url];
[conversationView setFrameLoadDelegate:viewDelegate];
[conversationView setPolicyDelegate:viewDelegate];
[conversationView setUIDelegate:viewDelegate];
[[conversationView windowScriptObject] setValue:self forKey:@"controller"];
// FIXME: show timelineView after authentification
}
- (void)initHotKeys {
NSInteger newTweetKey = kVK_ANSI_M; // http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes
@ -139,29 +177,6 @@
[loginViewWindow performClose:self];
}
- (void)initWebViews {
NSString *path = [[NSBundle mainBundle] resourcePath];
NSURL *url = [NSURL fileURLWithPath:path];
NSString *index_string = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@"%@/index.html", path] encoding:NSUTF8StringEncoding error:nil];
viewDelegate.timelineView = timelineView;
[[timelineView mainFrame] loadHTMLString:index_string baseURL:url];
[timelineView setFrameLoadDelegate:viewDelegate];
[timelineView setPolicyDelegate:viewDelegate];
[timelineView setUIDelegate:viewDelegate];
[[timelineView windowScriptObject] setValue:self forKey:@"controller"];
viewDelegate.mentionsView = mentionsView;
[[mentionsView mainFrame] loadHTMLString:index_string baseURL:url];
[mentionsView setFrameLoadDelegate:viewDelegate];
[mentionsView setPolicyDelegate:viewDelegate];
[mentionsView setUIDelegate:viewDelegate];
[[mentionsView windowScriptObject] setValue:self forKey:@"controller"];
// FIXME: show timelineView after authentification
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector {
return NO;
}
@ -200,7 +215,7 @@
NSRange range = [aString rangeOfString:@"oauthtoken"];
if (range.length > 0) {
[oauthView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"tentia_oauth.requestAccessToken('%@')", aString]];
[oauthView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"tentia_instance.requestAccessToken('%@')", aString]];
} else {
NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil];
[newTweet withString:aString];
@ -232,7 +247,7 @@
return nil;
}
- (void)unreadMentions:(NSInteger)count {
- (void)unreadMentions:(int)count {
if (![mentionsViewWindow isVisible] && count > 0) {
[timelineViewWindow setTitle:[NSString stringWithFormat:@"Tentia (^%i)", count]];
[[[NSApplication sharedApplication] dockTile] setBadgeLabel:[NSString stringWithFormat:@"%i", count]];
@ -243,6 +258,22 @@
}
}
- (void)notificateUserAboutMention:(NSString *)text fromName:(NSString *)name withPostId:(NSString *)postId andEntity:(NSString *)entity {
NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = @"Tent Mention";
notification.subtitle = [NSString stringWithFormat:@"Mentioned by %@", name];
notification.informativeText = text;
notification.hasActionButton = YES;
notification.actionButtonTitle = @"Show";
notification.soundName = NSUserNotificationDefaultSoundName;
notification.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
entity, @"entity",
postId, @"postId", nil];
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
- (void)openURL:(NSString *)url {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
}
@ -276,6 +307,9 @@
[timelineView stringByEvaluatingJavaScriptFromString:@"tentia_instance.logout();"];
[mentionsView stringByEvaluatingJavaScriptFromString:@"tentia_instance.logout();"];
if (oauthView) {
[oauthView stringByEvaluatingJavaScriptFromString:@"tentia_instance.logout();"];
}
[accessToken setString:nil forKey:@"app_mac_key"];
[accessToken setString:nil forKey:@"app_mac_key_id"];
@ -301,6 +335,20 @@
[mentionsView stringByEvaluatingJavaScriptFromString:@"tentia_instance.getNewData(true)"];
}
- (IBAction)showConversationForPostId:(NSString *)postId andEntity:(NSString *)entity
{
NSString *js = [NSString stringWithFormat:@"tentia_instance.showStatus('%@', '%@');", postId, entity];
[conversationView stringByEvaluatingJavaScriptFromString:js];
[conversationViewWindow makeKeyAndOrderFront:self];
}
// Notifications
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
//[self showConversationForPostId:[notification.userInfo objectForKey:@"postId"] andEntity:[notification.userInfo objectForKey:@"entity"]];
[[self mentionsViewWindow] makeKeyAndOrderFront:self];
}
/* CARBON */

View file

@ -3,7 +3,7 @@
<data>
<int key="IBDocument.SystemTarget">1080</int>
<string key="IBDocument.SystemVersion">12C60</string>
<string key="IBDocument.InterfaceBuilderVersion">2843</string>
<string key="IBDocument.InterfaceBuilderVersion">2844</string>
<string key="IBDocument.AppKitVersion">1187.34</string>
<string key="IBDocument.HIToolboxVersion">625.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
@ -15,7 +15,7 @@
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>2843</string>
<string>2844</string>
<string>1810</string>
</object>
</object>
@ -729,6 +729,15 @@
<string key="NSTitle">Window</string>
<object class="NSMutableArray" key="NSMenuItems">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMenuItem" id="163233745">
<reference key="NSMenu" ref="835318025"/>
<string key="NSTitle">Timeline</string>
<string key="NSKeyEquiv">1</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="1033313550"/>
<reference key="NSMixedImage" ref="310636482"/>
</object>
<object class="NSMenuItem" id="1011231497">
<reference key="NSMenu" ref="835318025"/>
<string key="NSTitle">Minimize</string>
@ -920,7 +929,7 @@
<reference key="NSNextKeyView"/>
<string key="FrameName"/>
<string key="GroupName"/>
<object class="WebPreferences" key="Preferences">
<object class="WebPreferences" key="Preferences" id="561166140">
<string key="Identifier">12</string>
<object class="NSMutableDictionary" key="Values">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -935,12 +944,72 @@
<string key="NSFrameSize">{376, 581}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="126069112"/>
</object>
<string key="NSScreenRect">{{0, 0}, {2560, 1418}}</string>
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
<string key="NSFrameAutosaveName">mentions</string>
<bool key="NSWindowIsRestorable">YES</bool>
</object>
<object class="NSWindowTemplate" id="919859780">
<int key="NSWindowStyleMask">15</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{1292, 328}, {376, 581}}</string>
<int key="NSWTFlags">1685586944</int>
<string key="NSWindowTitle">Conversation</string>
<string key="NSWindowClass">NSWindow</string>
<nil key="NSViewClass"/>
<nil key="NSUserInterfaceItemIdentifier"/>
<object class="NSView" key="NSWindowView" id="469460548">
<reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="WebView" id="352293288">
<reference key="NSNextResponder" ref="469460548"/>
<int key="NSvFlags">274</int>
<object class="NSMutableSet" key="NSDragTypes">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="set.sortedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>Apple HTML pasteboard type</string>
<string>Apple PDF pasteboard type</string>
<string>Apple PICT pasteboard type</string>
<string>Apple URL pasteboard type</string>
<string>Apple Web Archive pasteboard type</string>
<string>NSColor pasteboard type</string>
<string>NSFilenamesPboardType</string>
<string>NSStringPboardType</string>
<string>NeXT RTFD pasteboard type</string>
<string>NeXT Rich Text Format v1.0 pasteboard type</string>
<string>NeXT TIFF v4.0 pasteboard type</string>
<string>WebURLsWithTitlesPboardType</string>
<string>public.png</string>
<string>public.url</string>
<string>public.url-name</string>
</object>
</object>
<string key="NSFrameSize">{376, 581}</string>
<reference key="NSSuperview" ref="469460548"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<string key="FrameName"/>
<string key="GroupName"/>
<reference key="Preferences" ref="561166140"/>
<bool key="UseBackForwardList">NO</bool>
<bool key="AllowsUndo">YES</bool>
</object>
</object>
<string key="NSFrameSize">{376, 581}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="352293288"/>
</object>
<string key="NSScreenRect">{{0, 0}, {2560, 1418}}</string>
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
<string key="NSFrameAutosaveName">conversations</string>
<bool key="NSWindowIsRestorable">YES</bool>
</object>
<object class="NSWindowTemplate" id="842998572">
<int key="NSWindowStyleMask">7</int>
<int key="NSWindowBacking">2</int>
@ -1073,6 +1142,7 @@
<string key="NSFrame">{{391, 46}, {75, 32}}</string>
<reference key="NSSuperview" ref="503676418"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<string key="NSReuseIdentifierKey">_NS:9</string>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="54847478">
@ -1561,6 +1631,22 @@
</object>
<int key="connectionID">622</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">conversationView</string>
<reference key="source" ref="408500656"/>
<reference key="destination" ref="352293288"/>
</object>
<int key="connectionID">632</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">conversationViewWindow</string>
<reference key="source" ref="408500656"/>
<reference key="destination" ref="919859780"/>
</object>
<int key="connectionID">633</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">makeKeyAndOrderFront:</string>
@ -1569,6 +1655,14 @@
</object>
<int key="connectionID">547</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">makeKeyAndOrderFront:</string>
<reference key="source" ref="1010634651"/>
<reference key="destination" ref="163233745"/>
</object>
<int key="connectionID">642</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">checkForUpdates:</string>
@ -1617,6 +1711,14 @@
</object>
<int key="connectionID">619</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="919859780"/>
<reference key="destination" ref="408500656"/>
</object>
<int key="connectionID">631</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@ -1704,8 +1806,8 @@
<reference ref="705341025"/>
<reference ref="776162233"/>
<reference ref="425164168"/>
<reference ref="281587867"/>
<reference ref="295904906"/>
<reference ref="281587867"/>
<reference ref="157409543"/>
<reference ref="1007514384"/>
</object>
@ -1961,6 +2063,7 @@
<reference ref="625202149"/>
<reference ref="575023229"/>
<reference ref="1011231497"/>
<reference ref="163233745"/>
</object>
<reference key="parent" ref="713487014"/>
</object>
@ -2356,6 +2459,30 @@
<reference key="object" ref="776162233"/>
<reference key="parent" ref="720053764"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">628</int>
<reference key="object" ref="919859780"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="469460548"/>
</object>
<reference key="parent" ref="0"/>
<string key="objectName">Mentions</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">629</int>
<reference key="object" ref="469460548"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="352293288"/>
</object>
<reference key="parent" ref="919859780"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">630</int>
<reference key="object" ref="352293288"/>
<reference key="parent" ref="469460548"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">551</int>
<reference key="object" ref="295904906"/>
@ -2366,6 +2493,11 @@
<reference key="object" ref="281587867"/>
<reference key="parent" ref="720053764"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">641</int>
<reference key="object" ref="163233745"/>
<reference key="parent" ref="835318025"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@ -2477,6 +2609,12 @@
<string>610.IBPluginDependency</string>
<string>613.IBPluginDependency</string>
<string>620.IBPluginDependency</string>
<string>628.IBPluginDependency</string>
<string>628.IBWindowTemplateEditedContentRect</string>
<string>628.NSWindowTemplate.visibleAtLaunch</string>
<string>629.IBPluginDependency</string>
<string>630.IBPluginDependency</string>
<string>641.IBPluginDependency</string>
<string>72.IBPluginDependency</string>
<string>73.IBPluginDependency</string>
<string>79.IBPluginDependency</string>
@ -2593,6 +2731,12 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{344, 175}, {376, 581}}</string>
<boolean value="NO"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.WebKitIBPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@ -2613,7 +2757,7 @@
<reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
<int key="maxID">627</int>
<int key="maxID">642</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@ -2657,6 +2801,8 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>conversationView</string>
<string>conversationViewWindow</string>
<string>globalHotkeyMenuItem</string>
<string>loginActivityIndicator</string>
<string>loginViewWindow</string>
@ -2669,6 +2815,8 @@
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>WebView</string>
<string>NSWindow</string>
<string>NSMenuItem</string>
<string>NSProgressIndicator</string>
<string>NSWindow</string>
@ -2684,6 +2832,8 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>conversationView</string>
<string>conversationViewWindow</string>
<string>globalHotkeyMenuItem</string>
<string>loginActivityIndicator</string>
<string>loginViewWindow</string>
@ -2696,6 +2846,14 @@
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBToOneOutletInfo">
<string key="name">conversationView</string>
<string key="candidateClassName">WebView</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">conversationViewWindow</string>
<string key="candidateClassName">NSWindow</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">globalHotkeyMenuItem</string>
<string key="candidateClassName">NSMenuItem</string>

View file

@ -3,12 +3,12 @@
<data>
<int key="IBDocument.SystemTarget">1080</int>
<string key="IBDocument.SystemVersion">12C60</string>
<string key="IBDocument.InterfaceBuilderVersion">2843</string>
<string key="IBDocument.InterfaceBuilderVersion">2844</string>
<string key="IBDocument.AppKitVersion">1187.34</string>
<string key="IBDocument.HIToolboxVersion">625.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">2843</string>
<string key="NS.object.0">2844</string>
</object>
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -59,7 +59,7 @@
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="834602598">
<int key="NSCellFlags">-1809842175</int>
<int key="NSCellFlags2">272629760</int>
<int key="NSCellFlags2">268435456</int>
<string key="NSContents"/>
<object class="NSFont" key="NSSupport" id="991349575">
<string key="NSName">LucidaGrande</string>

View file

@ -141,18 +141,27 @@
BOOL retval = NO;
if (commandSelector == @selector(insertNewline:)) {
NSText *text = [[textField window] fieldEditor:YES forObject:nil];
NSRange range = [text selectedRange];
NSString *stringBefore = [textField.stringValue substringToIndex:range.location];
NSString *stringAfter = [textField.stringValue substringFromIndex:range.location + range.length];
textField.stringValue = [NSString stringWithFormat:@"%@\n%@", stringBefore, stringAfter];
NSRange r = NSMakeRange(range.location + 1, 0);
[text scrollRangeToVisible:r];
[text setSelectedRange:r];
retval = YES; // causes Apple to NOT fire the default enter action
textField.stringValue = [NSString stringWithFormat:@"%@\n", textField.stringValue];
[[[textField window] fieldEditor:YES forObject:nil] scrollRangeToVisible:NSMakeRange([[textField stringValue] length], 0)];
[[[textField window] fieldEditor:YES forObject:nil] setSelectedRange:NSMakeRange([[textField stringValue] length], 0)];
}
if (commandSelector == @selector(noop:)) {
else if (commandSelector == @selector(noop:)) {
retval = YES;
[self sendTweet:control];
}
return retval;
}
@end

Some files were not shown because too many files have changed in this diff Show more