diff --git a/Mac/Controller.h b/Mac/Controller.h index c440493..b422ea0 100644 --- a/Mac/Controller.h +++ b/Mac/Controller.h @@ -13,6 +13,8 @@ #import "Constants.h" #import "AccessToken.h" #import +#import "NSData+Base64.h" +#import "MimeType.h" @interface Controller : NSObject { IBOutlet WebView *timelineView; diff --git a/Mac/Controller.m b/Mac/Controller.m index d26294b..8ec834b 100644 --- a/Mac/Controller.m +++ b/Mac/Controller.m @@ -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]; } diff --git a/Mac/English.lproj/NewMessageWindow.xib b/Mac/English.lproj/NewMessageWindow.xib index a845fb8..def5ffb 100644 --- a/Mac/English.lproj/NewMessageWindow.xib +++ b/Mac/English.lproj/NewMessageWindow.xib @@ -184,15 +184,23 @@ Add current location 2147483647 - + NSImage NSMenuCheckmark - + NSImage NSMenuMixedState + + + Add image + + 2147483647 + + + @@ -263,6 +271,14 @@ 100054 + + + addImage: + + + + 100056 + delegate @@ -378,6 +394,7 @@ YES + @@ -386,6 +403,11 @@ + + 100055 + + + @@ -403,6 +425,7 @@ 100040.IBPluginDependency 100041.IBPluginDependency 100043.IBPluginDependency + 100055.IBPluginDependency 5.IBPluginDependency 5.IBWindowTemplateEditedContentRect 6.IBPluginDependency @@ -421,6 +444,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin {{127, 736}, {299, 113}} com.apple.InterfaceBuilder.CocoaPlugin @@ -437,7 +461,7 @@ - 100054 + 100056 diff --git a/Mac/MimeType.h b/Mac/MimeType.h new file mode 100644 index 0000000..50a40d6 --- /dev/null +++ b/Mac/MimeType.h @@ -0,0 +1,13 @@ +// +// MimeType.h +// Tentia +// +// Created by Jeena on 23/11/2012. +// +// + +#import + +@interface MimeType : NSObject ++(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err; +@end diff --git a/Mac/MimeType.m b/Mac/MimeType.m new file mode 100644 index 0000000..75372f7 --- /dev/null +++ b/Mac/MimeType.m @@ -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 diff --git a/Mac/NSData+Base64.h b/Mac/NSData+Base64.h new file mode 100644 index 0000000..24d0984 --- /dev/null +++ b/Mac/NSData+Base64.h @@ -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:@"%@", 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:[@"" dataUsingEncoding:NSASCIIStringEncoding] options:0 range:fullRange]; + NSRange endRange = [plist rangeOfData:[@"" 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 \ No newline at end of file diff --git a/Mac/NSData+Base64.m b/Mac/NSData+Base64.m new file mode 100644 index 0000000..1a71914 --- /dev/null +++ b/Mac/NSData+Base64.m @@ -0,0 +1,13 @@ +// +// Created by Cédric Luthi on 2012-02-24. +// Copyright (c) 2012 Cédric Luthi. All rights reserved. +// + +#import + +@interface NSData (Base64) + ++ (id) dataWithBase64Encoding_xcd:(NSString *)base64String; +- (NSString *) base64Encoding_xcd; + +@end \ No newline at end of file diff --git a/Mac/NewMessageWindow.h b/Mac/NewMessageWindow.h index 6f49e95..3c17540 100644 --- a/Mac/NewMessageWindow.h +++ b/Mac/NewMessageWindow.h @@ -11,7 +11,7 @@ #import -@interface NewMessageWindow : NSDocument +@interface NewMessageWindow : NSDocument { 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; diff --git a/Mac/NewMessageWindow.m b/Mac/NewMessageWindow.m index 5806f89..50073a5 100644 --- a/Mac/NewMessageWindow.m +++ b/Mac/NewMessageWindow.m @@ -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 diff --git a/Mac/PostModel.h b/Mac/PostModel.h index 5130c1b..426a539 100644 --- a/Mac/PostModel.h +++ b/Mac/PostModel.h @@ -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 diff --git a/Mac/PostModel.m b/Mac/PostModel.m index ccebd0e..777c3ff 100644 --- a/Mac/PostModel.m +++ b/Mac/PostModel.m @@ -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]; } diff --git a/Mac/Tentia.xcodeproj/project.pbxproj b/Mac/Tentia.xcodeproj/project.pbxproj index c044196..a4bd7c6 100644 --- a/Mac/Tentia.xcodeproj/project.pbxproj +++ b/Mac/Tentia.xcodeproj/project.pbxproj @@ -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 = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 1F77DB46118C5F1C007C7F1E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Constants.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 1F880B69165EE0F60022A84D /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base64.h"; sourceTree = ""; }; + 1F880B6A165EE0F60022A84D /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base64.m"; sourceTree = ""; }; + 1F880B6C165FE8890022A84D /* MimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MimeType.h; sourceTree = ""; }; + 1F880B6D165FE8890022A84D /* MimeType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MimeType.m; sourceTree = ""; }; 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 = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 1FC2549B1427D9930035D84B /* AccessToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AccessToken.m; sourceTree = ""; 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 = ""; @@ -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; }; diff --git a/Mac/publish/Appcast.xml b/Mac/publish/Appcast.xml index 844bb76..3915ba7 100755 --- a/Mac/publish/Appcast.xml +++ b/Mac/publish/Appcast.xml @@ -6,15 +6,15 @@ Most recent changes with links to updates. en - Version 0.2.4 + Version 0.3.0 10.5.0 http://jabs.nu/Tentia/download/ReleaseNotes.html - Sat, 17 Nov 2012 20:45:22 +0100 + Thu, 22 Nov 2012 22:01:49 +0100 + sparkle:dsaSignature="MC0CFQCMY1g2OMW21BMQWoaZjUzMxY+kwQIUdMZXIOCTcGv+4Ht5wcIr07F4dao=" /> diff --git a/Mac/publish/ReleaseNotes.html b/Mac/publish/ReleaseNotes.html index 038b14b..adf92ce 100644 --- a/Mac/publish/ReleaseNotes.html +++ b/Mac/publish/ReleaseNotes.html @@ -20,6 +20,7 @@

Implemented remove deleted posts

Added a JS and CSS Plugin API

Implemented adding location to post

+

Implemented blue right border if you're mentioned in a post

Bugfixes


diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index 1892422..43e2d4c 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -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) { diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 614c5e4..61a14a6 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -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; }); \ No newline at end of file diff --git a/WebKit/scripts/helper/Paths.js b/WebKit/scripts/helper/Paths.js index b3978d6..59d876f 100644 --- a/WebKit/scripts/helper/Paths.js +++ b/WebKit/scripts/helper/Paths.js @@ -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({