trying to add images
This commit is contained in:
parent
555e7cca3c
commit
a128e0278d
17 changed files with 369 additions and 31 deletions
|
@ -13,6 +13,8 @@
|
|||
#import "Constants.h"
|
||||
#import "AccessToken.h"
|
||||
#import <Growl/Growl.h>
|
||||
#import "NSData+Base64.h"
|
||||
#import "MimeType.h"
|
||||
|
||||
@interface Controller : NSObject <GrowlApplicationBridgeDelegate> {
|
||||
IBOutlet WebView *timelineView;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import "Controller.h"
|
||||
#import "NewMessageWindow.h"
|
||||
#import "PostModel.h"
|
||||
#import "NSData+Base64.h"
|
||||
|
||||
@implementation Controller
|
||||
@synthesize loginViewWindow;
|
||||
|
@ -244,7 +245,6 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)openNewMessageWindow:(id)sender
|
||||
{
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
@ -273,7 +273,6 @@
|
|||
NewMessageWindow *newTweet = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil];
|
||||
[newTweet withString:aString];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
|
||||
|
@ -292,11 +291,24 @@
|
|||
if (post.location) {
|
||||
locationObject = [NSString stringWithFormat:@"[%f, %f]", post.location.coordinate.latitude, post.location.coordinate.longitude];
|
||||
}
|
||||
NSString *func = [NSString stringWithFormat:@"tentia_instance.sendNewMessage(\"%@\", \"%@\", \"%@\", %@)",
|
||||
|
||||
NSString *imageFilePath = @"null";
|
||||
if (post.imageFilePath) {
|
||||
NSError *error;
|
||||
NSString *mimeType = [MimeType mimeTypeForFileAtPath:post.imageFilePath error:&error];
|
||||
NSData *data = [[NSData alloc] initWithContentsOfFile:post.imageFilePath];
|
||||
NSString *base64 = [data base64Encoding_xcd];
|
||||
[data release];
|
||||
imageFilePath = [NSString stringWithFormat:@"\"data:%@;base64,%@\"", mimeType, base64];
|
||||
}
|
||||
|
||||
NSString *func = [NSString stringWithFormat:@"tentia_instance.sendNewMessage(\"%@\", \"%@\", \"%@\", %@, %@)",
|
||||
text,
|
||||
post.inReplyTostatusId,
|
||||
post.inReplyToEntity,
|
||||
locationObject];
|
||||
locationObject,
|
||||
imageFilePath];
|
||||
|
||||
[timelineView stringByEvaluatingJavaScriptFromString:func];
|
||||
}
|
||||
|
||||
|
|
|
@ -184,15 +184,23 @@
|
|||
<string key="NSTitle">Add current location</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<object class="NSCustomResource" key="NSOnImage">
|
||||
<object class="NSCustomResource" key="NSOnImage" id="400068421">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuCheckmark</string>
|
||||
</object>
|
||||
<object class="NSCustomResource" key="NSMixedImage">
|
||||
<object class="NSCustomResource" key="NSMixedImage" id="196417858">
|
||||
<string key="NSClassName">NSImage</string>
|
||||
<string key="NSResourceName">NSMenuMixedState</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="502380341">
|
||||
<reference key="NSMenu" ref="723763594"/>
|
||||
<string key="NSTitle">Add image</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="400068421"/>
|
||||
<reference key="NSMixedImage" ref="196417858"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
|
@ -263,6 +271,14 @@
|
|||
</object>
|
||||
<int key="connectionID">100054</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">addImage:</string>
|
||||
<reference key="source" ref="512844837"/>
|
||||
<reference key="destination" ref="502380341"/>
|
||||
</object>
|
||||
<int key="connectionID">100056</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">delegate</string>
|
||||
|
@ -378,6 +394,7 @@
|
|||
<object class="NSMutableArray" key="children">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
<reference ref="921309347"/>
|
||||
<reference ref="502380341"/>
|
||||
</object>
|
||||
<reference key="parent" ref="0"/>
|
||||
</object>
|
||||
|
@ -386,6 +403,11 @@
|
|||
<reference key="object" ref="921309347"/>
|
||||
<reference key="parent" ref="723763594"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">100055</int>
|
||||
<reference key="object" ref="502380341"/>
|
||||
<reference key="parent" ref="723763594"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
|
@ -403,6 +425,7 @@
|
|||
<string>100040.IBPluginDependency</string>
|
||||
<string>100041.IBPluginDependency</string>
|
||||
<string>100043.IBPluginDependency</string>
|
||||
<string>100055.IBPluginDependency</string>
|
||||
<string>5.IBPluginDependency</string>
|
||||
<string>5.IBWindowTemplateEditedContentRect</string>
|
||||
<string>6.IBPluginDependency</string>
|
||||
|
@ -421,6 +444,7 @@
|
|||
<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>{{127, 736}, {299, 113}}</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
|
@ -437,7 +461,7 @@
|
|||
<reference key="dict.values" ref="0"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">100054</int>
|
||||
<int key="maxID">100056</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
|
|
13
Mac/MimeType.h
Normal file
13
Mac/MimeType.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// MimeType.h
|
||||
// Tentia
|
||||
//
|
||||
// Created by Jeena on 23/11/2012.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MimeType : NSObject
|
||||
+(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err;
|
||||
@end
|
27
Mac/MimeType.m
Normal file
27
Mac/MimeType.m
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// MimeType.m
|
||||
// Tentia
|
||||
//
|
||||
// Created by Jeena on 23/11/2012.
|
||||
//
|
||||
//
|
||||
|
||||
#import "MimeType.h"
|
||||
|
||||
@implementation MimeType
|
||||
|
||||
+(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err {
|
||||
NSString *uti, *mimeType = nil;
|
||||
|
||||
if (!(uti = [[NSWorkspace sharedWorkspace] typeOfFile:path error:err]))
|
||||
return nil;
|
||||
if (err)
|
||||
*err = nil;
|
||||
|
||||
if ((mimeType = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassMIMEType)))
|
||||
mimeType = NSMakeCollectable(mimeType);
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
@end
|
46
Mac/NSData+Base64.h
Normal file
46
Mac/NSData+Base64.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Created by Cédric Luthi on 2012-02-24.
|
||||
// Copyright (c) 2012 Cédric Luthi. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSData+Base64.h"
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
@implementation NSData (Base64)
|
||||
|
||||
+ (id) dataWithBase64Encoding_xcd:(NSString *)base64Encoding
|
||||
{
|
||||
if ([base64Encoding length] % 4 != 0)
|
||||
return nil;
|
||||
|
||||
NSString *plist = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"UTF-8\"?><plist version=\"1.0\"><data>%@</data></plist>", base64Encoding];
|
||||
return [NSPropertyListSerialization propertyListWithData:[plist dataUsingEncoding:NSASCIIStringEncoding] options:0 format:NULL error:NULL];
|
||||
}
|
||||
|
||||
- (NSString *) base64Encoding_xcd
|
||||
{
|
||||
NSData *plist = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL];
|
||||
NSRange fullRange = NSMakeRange(0, [plist length]);
|
||||
NSRange startRange = [plist rangeOfData:[@"<data>" dataUsingEncoding:NSASCIIStringEncoding] options:0 range:fullRange];
|
||||
NSRange endRange = [plist rangeOfData:[@"</data>" dataUsingEncoding:NSASCIIStringEncoding] options:NSDataSearchBackwards range:fullRange];
|
||||
if (startRange.location == NSNotFound || endRange.location == NSNotFound)
|
||||
return nil;
|
||||
|
||||
NSUInteger base64Location = startRange.location + startRange.length;
|
||||
NSUInteger base64length = endRange.location - base64Location;
|
||||
NSData *base64Data = [NSData dataWithBytesNoCopy:(void *)((uintptr_t)base64Location + (uintptr_t)[plist bytes]) length:base64length freeWhenDone:NO];
|
||||
NSString *base64Encoding = [[NSString alloc] initWithData:base64Data encoding:NSASCIIStringEncoding];
|
||||
base64Encoding = [base64Encoding stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
base64Encoding = [base64Encoding stringByReplacingOccurrencesOfString:@"\n" withString:@""];
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
return base64Encoding;
|
||||
#else
|
||||
return [base64Encoding autorelease];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
13
Mac/NSData+Base64.m
Normal file
13
Mac/NSData+Base64.m
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Created by Cédric Luthi on 2012-02-24.
|
||||
// Copyright (c) 2012 Cédric Luthi. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSData (Base64)
|
||||
|
||||
+ (id) dataWithBase64Encoding_xcd:(NSString *)base64String;
|
||||
- (NSString *) base64Encoding_xcd;
|
||||
|
||||
@end
|
|
@ -11,7 +11,7 @@
|
|||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
|
||||
@interface NewMessageWindow : NSDocument <NSTextFieldDelegate, CLLocationManagerDelegate>
|
||||
@interface NewMessageWindow : NSDocument <NSTextFieldDelegate, CLLocationManagerDelegate, NSOpenSavePanelDelegate>
|
||||
{
|
||||
IBOutlet NSTextField *textField;
|
||||
IBOutlet NSTextField *counter;
|
||||
|
@ -22,6 +22,7 @@
|
|||
NSMenuItem *addImage;
|
||||
CLLocationManager *locationManager;
|
||||
CLLocation *currentLocation;
|
||||
NSString *imageFilePath;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet NSTextField *textField;
|
||||
|
@ -30,6 +31,7 @@
|
|||
@property (assign) IBOutlet NSButton *addMenuButton;
|
||||
@property (retain, nonatomic) CLLocationManager *locationManager;
|
||||
@property (retain, nonatomic) CLLocation *currentLocation;
|
||||
@property (retain, nonatomic) NSString *imageFilePath;
|
||||
|
||||
- (IBAction)sendTweet:(NSControl *)control;
|
||||
- (void)inReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string;
|
||||
|
|
|
@ -22,12 +22,14 @@
|
|||
@synthesize addMenuButton;
|
||||
@synthesize textField, counter;
|
||||
@synthesize locationManager, currentLocation;
|
||||
@synthesize imageFilePath;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[locationManager stopUpdatingLocation];
|
||||
[locationManager release];
|
||||
[currentLocation release];
|
||||
[imageFilePath release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
@ -139,10 +141,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (IBAction)addImage:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
- (IBAction)openAddMenu:(id)sender
|
||||
{
|
||||
NSRect frame = [(NSButton *)sender frame];
|
||||
|
@ -203,6 +201,7 @@
|
|||
post.inReplyTostatusId = inReplyTostatusId;
|
||||
post.inReplyToEntity = inReplyToEntity;
|
||||
post.location = self.currentLocation;
|
||||
post.imageFilePath = self.imageFilePath;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"sendTweet" object:post];
|
||||
[self close];
|
||||
} else {
|
||||
|
@ -246,4 +245,66 @@
|
|||
return retval;
|
||||
}
|
||||
|
||||
#pragma mark Add images
|
||||
|
||||
- (IBAction)addImage:(id)sender
|
||||
{
|
||||
NSMenuItem *menuItem = (NSMenuItem *)sender;
|
||||
|
||||
if (!self.imageFilePath)
|
||||
{
|
||||
[menuItem setTitle:@"Remove image"];
|
||||
|
||||
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
|
||||
[openDlg setPrompt:@"Select"];
|
||||
[openDlg setDelegate:self];
|
||||
|
||||
// Enable the selection of files in the dialog.
|
||||
[openDlg setCanChooseFiles:YES];
|
||||
|
||||
// Enable the selection of directories in the dialog.
|
||||
[openDlg setCanChooseDirectories:NO];
|
||||
|
||||
// Display the dialog. If the OK button was pressed,
|
||||
// process the files.
|
||||
if ( [openDlg runModalForDirectory:nil file:nil] == NSOKButton )
|
||||
{
|
||||
// Get an array containing the full filenames of all
|
||||
// files and directories selected.
|
||||
NSArray* files = [openDlg filenames];
|
||||
|
||||
// Loop through all the files and process them.
|
||||
for( int i = 0; i < [files count]; i++ )
|
||||
{
|
||||
self.imageFilePath = [files objectAtIndex:i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.imageFilePath = nil;
|
||||
[menuItem setTitle:@"Add image"];
|
||||
}
|
||||
}
|
||||
|
||||
-(BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
|
||||
{
|
||||
NSString* ext = [filename pathExtension];
|
||||
if (ext == @"" || ext == @"/" || ext == nil || ext == NULL || [ext length] < 1) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSEnumerator* tagEnumerator = [[NSArray arrayWithObjects:@"png", @"jpg", @"gif", @"jpeg", nil] objectEnumerator];
|
||||
NSString* allowedExt;
|
||||
while ((allowedExt = [tagEnumerator nextObject]))
|
||||
{
|
||||
if ([ext caseInsensitiveCompare:allowedExt] == NSOrderedSame)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -14,13 +14,13 @@
|
|||
NSString *inReplyTostatusId;
|
||||
NSString *inReplyToEntity;
|
||||
CLLocation *location;
|
||||
NSImage *image;
|
||||
NSString *imageFilePath;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSString *text;
|
||||
@property (nonatomic, retain) NSString *inReplyTostatusId;
|
||||
@property (nonatomic, retain) NSString *inReplyToEntity;
|
||||
@property (nonatomic, retain) CLLocation *location;
|
||||
@property (nonatomic, retain) NSImage *image;
|
||||
@property (nonatomic, retain) NSString *imageFilePath;
|
||||
|
||||
@end
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
@implementation PostModel
|
||||
|
||||
@synthesize text, inReplyTostatusId, inReplyToEntity, location, image;
|
||||
@synthesize text, inReplyTostatusId, inReplyToEntity, location, imageFilePath;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
|
@ -19,7 +19,7 @@
|
|||
[inReplyTostatusId release];
|
||||
[inReplyToEntity release];
|
||||
[location release];
|
||||
[image release];
|
||||
[imageFilePath release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F618EC912DB5E6100E500D9 /* PostModel.m */; };
|
||||
1F70619F1178FBB300C85707 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F70619E1178FBB300C85707 /* Carbon.framework */; };
|
||||
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F77DB46118C5F1C007C7F1E /* Constants.m */; };
|
||||
1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6A165EE0F60022A84D /* NSData+Base64.m */; };
|
||||
1F880B6E165FE8890022A84D /* MimeType.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6D165FE8890022A84D /* MimeType.m */; };
|
||||
1FA09847144602530079E258 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FA09846144602530079E258 /* libicucore.dylib */; };
|
||||
1FC254A01427DFAD0035D84B /* AccessToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FC2549B1427D9930035D84B /* AccessToken.m */; };
|
||||
1FDEF722164EFE9100F927F3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FDEF721164EFE9100F927F3 /* Growl.framework */; };
|
||||
|
@ -64,6 +66,10 @@
|
|||
1F70619E1178FBB300C85707 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
|
||||
1F77DB45118C5F1C007C7F1E /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Constants.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
1F77DB46118C5F1C007C7F1E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Constants.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
1F880B69165EE0F60022A84D /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base64.h"; sourceTree = "<group>"; };
|
||||
1F880B6A165EE0F60022A84D /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base64.m"; sourceTree = "<group>"; };
|
||||
1F880B6C165FE8890022A84D /* MimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MimeType.h; sourceTree = "<group>"; };
|
||||
1F880B6D165FE8890022A84D /* MimeType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MimeType.m; sourceTree = "<group>"; };
|
||||
1FA09846144602530079E258 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
||||
1FC2549A1427D9930035D84B /* AccessToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AccessToken.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
1FC2549B1427D9930035D84B /* AccessToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AccessToken.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
|
@ -165,6 +171,10 @@
|
|||
1F618EC912DB5E6100E500D9 /* PostModel.m */,
|
||||
1FC2549A1427D9930035D84B /* AccessToken.h */,
|
||||
1FC2549B1427D9930035D84B /* AccessToken.m */,
|
||||
1F880B69165EE0F60022A84D /* NSData+Base64.h */,
|
||||
1F880B6A165EE0F60022A84D /* NSData+Base64.m */,
|
||||
1F880B6C165FE8890022A84D /* MimeType.h */,
|
||||
1F880B6D165FE8890022A84D /* MimeType.m */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
|
@ -282,6 +292,8 @@
|
|||
1FFA36D81177D879006C8562 /* ViewDelegate.m in Sources */,
|
||||
1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */,
|
||||
1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */,
|
||||
1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */,
|
||||
1F880B6E165FE8890022A84D /* MimeType.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
<description>Most recent changes with links to updates.</description>
|
||||
<language>en</language>
|
||||
<item>
|
||||
<title>Version 0.2.4</title>
|
||||
<title>Version 0.3.0</title>
|
||||
<sparkle:minimumSystemVersion>10.5.0</sparkle:minimumSystemVersion>
|
||||
<sparkle:releaseNotesLink>http://jabs.nu/Tentia/download/ReleaseNotes.html</sparkle:releaseNotesLink>
|
||||
<pubDate>Sat, 17 Nov 2012 20:45:22 +0100</pubDate>
|
||||
<pubDate>Thu, 22 Nov 2012 22:01:49 +0100</pubDate>
|
||||
<enclosure url="http://jabs.nu/Tentia/download/Tentia.app.zip"
|
||||
sparkle:version="0.2.4"
|
||||
length="1069130"
|
||||
sparkle:version="0.3.0"
|
||||
length="1031876"
|
||||
type="application/octet-stream"
|
||||
sparkle:dsaSignature="MC0CFCvZgr1pcB0bW0IQ8E7ffqs0SjvpAhUAioix/kjwYUqGqchCTDN6EjncmSE=" />
|
||||
sparkle:dsaSignature="MC0CFQCMY1g2OMW21BMQWoaZjUzMxY+kwQIUdMZXIOCTcGv+4Ht5wcIr07F4dao=" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<p>Implemented remove deleted posts</p>
|
||||
<p>Added a JS and CSS Plugin API</p>
|
||||
<p>Implemented adding location to post</p>
|
||||
<p>Implemented blue right border if you're mentioned in a post</p>
|
||||
<p>Bugfixes</p>
|
||||
|
||||
<hr />
|
||||
|
|
|
@ -117,10 +117,10 @@ function(Core, Paths, HostApp, URI) {
|
|||
}
|
||||
}
|
||||
|
||||
Timeline.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location) {
|
||||
Timeline.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri) {
|
||||
var _this = this;
|
||||
var callback = function(data) { _this.getNewData(); }
|
||||
Core.prototype.sendNewMessage.call(this, content, in_reply_to_status_id, in_reply_to_entity, location, callback);
|
||||
Core.prototype.sendNewMessage.call(this, content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, callback);
|
||||
}
|
||||
|
||||
Timeline.prototype.remove = function(id) {
|
||||
|
|
|
@ -258,20 +258,54 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
|||
return template.item;
|
||||
}
|
||||
|
||||
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, callback) {
|
||||
Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_file_path, callback) {
|
||||
|
||||
if (image_file_path) {
|
||||
|
||||
this.sendNewMessageWithImage(content, in_reply_to_status_id, in_reply_to_entity, location, image_file_path, callback);
|
||||
|
||||
} else {
|
||||
|
||||
var url = URI(Paths.mkApiRootPath("/posts"));
|
||||
|
||||
var http_method = "POST";
|
||||
|
||||
var data = {
|
||||
"type": "https://tent.io/types/post/status/v0.1.0",
|
||||
"published_at": parseInt(new Date().getTime() / 1000, 10),
|
||||
"permissions": {
|
||||
"public": true
|
||||
},
|
||||
"content": {
|
||||
"text": content,
|
||||
},
|
||||
};
|
||||
|
||||
if (location) {
|
||||
data["content"]["location"] = { "type": "Point", "coordinates": location }
|
||||
}
|
||||
|
||||
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
|
||||
if (mentions.length > 0) {
|
||||
data["mentions"] = mentions;
|
||||
}
|
||||
|
||||
Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
Core.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, callback) {
|
||||
|
||||
var url = URI(Paths.mkApiRootPath("/posts"));
|
||||
|
||||
var http_method = "POST";
|
||||
|
||||
var data = {
|
||||
"type": "https://tent.io/types/post/status/v0.1.0",
|
||||
"published_at": (new Date().getTime() / 1000),
|
||||
"type": "https://tent.io/types/post/photo/v0.1.0",
|
||||
"published_at": parseInt(new Date().getTime() / 1000, 10),
|
||||
"permissions": {
|
||||
"public": true
|
||||
},
|
||||
"content": {
|
||||
"text": content,
|
||||
"caption": content,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -280,12 +314,41 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
|||
}
|
||||
|
||||
var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity);
|
||||
|
||||
if (mentions.length > 0) {
|
||||
data["mentions"] = mentions;
|
||||
}
|
||||
|
||||
Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data));
|
||||
var data_string = JSON.stringify(data);
|
||||
|
||||
var boundary = "-----------TentAttachment";
|
||||
var post = boundary + "\r\n";
|
||||
|
||||
post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n';
|
||||
post += 'Content-Length: ' + data_string.length + '\r\n';
|
||||
post += 'Content-Type: application/vnd.tent.v0+json\r\n';
|
||||
post += 'Content-Transfer-Encoding: binary\r\n\r\n';
|
||||
post += data_string;
|
||||
|
||||
post += "\r\n" + boundary + "\r\n";
|
||||
|
||||
var binary_data = this.dataURItoBlob(image_data_uri);
|
||||
var ext = "png";
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
|
||||
var blob_string = e.target.result;
|
||||
post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n';
|
||||
post += 'Content-Length: ' + blob_string.length + "\r\n";
|
||||
post += 'Content-Type: ' + binary_data.mime_type + "\r\n";
|
||||
post += 'Content-Transfer-Encoding: binary\r\n\r\n';
|
||||
post += image_data_uri.split(',')[1];
|
||||
post += "\r\n" + boundary + "--\r\n";
|
||||
|
||||
Paths.postMultipart(url.toString(), callback, post, boundary);
|
||||
}
|
||||
|
||||
reader.readAsBinaryString(binary_data.blob)
|
||||
}
|
||||
|
||||
Core.prototype.remove = function(id, callback) {
|
||||
|
@ -475,6 +538,30 @@ function(jQuery, Paths, URI, HostApp, Followings) {
|
|||
HostApp.openNewMessageWidow(entity, status_id, string);
|
||||
}
|
||||
|
||||
Core.prototype.dataURItoBlob = function(dataURI) {
|
||||
// convert base64 to raw binary data held in a string
|
||||
// doesn't handle URLEncoded DataURIs
|
||||
var byteString = atob(dataURI.split(',')[1]);
|
||||
|
||||
// separate out the mime component
|
||||
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
|
||||
|
||||
// write the bytes of the string to an ArrayBuffer
|
||||
var ab = new ArrayBuffer(byteString.length);
|
||||
var ia = new Uint8Array(ab);
|
||||
for (var i = 0; i < byteString.length; i++) {
|
||||
ia[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
|
||||
// write the ArrayBuffer to a blob, and you're done
|
||||
var blob = new Blob([ab], {type: mimeString});
|
||||
return {
|
||||
mime_type: mimeString,
|
||||
blob: blob,
|
||||
base64: byteString
|
||||
}
|
||||
}
|
||||
|
||||
return Core;
|
||||
|
||||
});
|
|
@ -60,6 +60,44 @@ function(jQuery, HostApp, Hmac) {
|
|||
});
|
||||
}
|
||||
|
||||
Paths.postMultipart = function(url, callback, data, boundary) {
|
||||
debug(url)
|
||||
debug(data)
|
||||
|
||||
jQuery.ajax({
|
||||
|
||||
beforeSend: function(xhr) {
|
||||
|
||||
if (data) xhr.setRequestHeader("Content-Length", data.length);
|
||||
debug("Content-Length: " + data.length);
|
||||
|
||||
var user_access_token = HostApp.stringForKey("user_access_token");
|
||||
|
||||
if (user_access_token) {
|
||||
|
||||
auth_header = Hmac.makeAuthHeader(
|
||||
url,
|
||||
"POST",
|
||||
HostApp.stringForKey("user_mac_key"),
|
||||
user_access_token
|
||||
);
|
||||
debug(auth_header)
|
||||
xhr.setRequestHeader("Authorization", auth_header);
|
||||
}
|
||||
},
|
||||
url: url,
|
||||
accepts: "application/vnd.tent.v0+json",
|
||||
contentType: "multipart/form-data;boundary=" + boundary,
|
||||
type: "POST",
|
||||
complete: callback,
|
||||
data: data,
|
||||
processData: false,
|
||||
error: function(xhr, ajaxOptions, thrownError) {
|
||||
console.error("postMultipart " + xhr.statusText + " (" + url + "): '" + xhr.responseText + "'");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Paths.findProfileURL = function(entity, callback, errorCallback) {
|
||||
|
||||
jQuery.ajax({
|
||||
|
|
Reference in a new issue