Brion VIBBER has uploaded a new change for review.
https://gerrit.wikimedia.org/r/93609
Change subject: Work in progress: JS bridge
......................................................................
Work in progress: JS bridge
Tests don't all work yet, not yet used
Change-Id: I667314bad95e774539a93d17d794169c9cb224fb
---
M Wikipedia-iOS.xcodeproj/project.pbxproj
A Wikipedia-iOS/CommunicationBridge.h
A Wikipedia-iOS/CommunicationBridge.m
A Wikipedia-iOS/bridge-index.html
A Wikipedia-iOSTests/CommunicationBridgeTests.m
5 files changed, 245 insertions(+), 0 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia
refs/changes/09/93609/1
diff --git a/Wikipedia-iOS.xcodeproj/project.pbxproj
b/Wikipedia-iOS.xcodeproj/project.pbxproj
index 3dd962b..c4625ad 100644
--- a/Wikipedia-iOS.xcodeproj/project.pbxproj
+++ b/Wikipedia-iOS.xcodeproj/project.pbxproj
@@ -22,6 +22,11 @@
D4991465181D51DF00E6073C /* InfoPlist.strings in Resources */ =
{isa = PBXBuildFile; fileRef = D4991463181D51DF00E6073C /* InfoPlist.strings
*/; };
D4991467181D51DF00E6073C /* Wikipedia_iOSTests.m in Sources */
= {isa = PBXBuildFile; fileRef = D4991466181D51DF00E6073C /*
Wikipedia_iOSTests.m */; };
D4BC22B4181E9E6300CAC673 /* empty.png in Resources */ = {isa =
PBXBuildFile; fileRef = D4BC22B3181E9E6300CAC673 /* empty.png */; };
+ D4DE203118283FF200148CA2 /* CommunicationBridgeTests.m in
Sources */ = {isa = PBXBuildFile; fileRef = D4DE203018283FF200148CA2 /*
CommunicationBridgeTests.m */; };
+ D4DE20341828400C00148CA2 /* CommunicationBridge.m in Sources */
= {isa = PBXBuildFile; fileRef = D4DE20331828400C00148CA2 /*
CommunicationBridge.m */; };
+ D4DE20351828400C00148CA2 /* CommunicationBridge.m in Sources */
= {isa = PBXBuildFile; fileRef = D4DE20331828400C00148CA2 /*
CommunicationBridge.m */; };
+ D4DE20371828518B00148CA2 /* bridge-index.html in Resources */ =
{isa = PBXBuildFile; fileRef = D4DE20361828518B00148CA2 /* bridge-index.html
*/; };
+ D4DE20381828518B00148CA2 /* bridge-index.html in Resources */ =
{isa = PBXBuildFile; fileRef = D4DE20361828518B00148CA2 /* bridge-index.html
*/; };
D4EE00B9182443FC0090790F /* PageTitle.m in Sources */ = {isa =
PBXBuildFile; fileRef = D4EE00B8182443FC0090790F /* PageTitle.m */; };
D4EE00BA182443FC0090790F /* PageTitle.m in Sources */ = {isa =
PBXBuildFile; fileRef = D4EE00B8182443FC0090790F /* PageTitle.m */; };
D4EE00BD1824459D0090790F /* PageTitleTests.m in Sources */ =
{isa = PBXBuildFile; fileRef = D4EE00BC1824459D0090790F /* PageTitleTests.m */;
};
@@ -58,6 +63,10 @@
D4991464181D51DF00E6073C /* en */ = {isa = PBXFileReference;
lastKnownFileType = text.plist.strings; name = en; path =
en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D4991466181D51DF00E6073C /* Wikipedia_iOSTests.m */ = {isa =
PBXFileReference; lastKnownFileType = sourcecode.c.objc; path =
Wikipedia_iOSTests.m; sourceTree = "<group>"; };
D4BC22B3181E9E6300CAC673 /* empty.png */ = {isa =
PBXFileReference; lastKnownFileType = image.png; path = empty.png; sourceTree =
"<group>"; };
+ D4DE203018283FF200148CA2 /* CommunicationBridgeTests.m */ =
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType =
sourcecode.c.objc; path = CommunicationBridgeTests.m; sourceTree = "<group>"; };
+ D4DE20321828400C00148CA2 /* CommunicationBridge.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
CommunicationBridge.h; sourceTree = "<group>"; };
+ D4DE20331828400C00148CA2 /* CommunicationBridge.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= CommunicationBridge.m; sourceTree = "<group>"; };
+ D4DE20361828518B00148CA2 /* bridge-index.html */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path =
"bridge-index.html"; sourceTree = "<group>"; };
D4EE00B7182443FC0090790F /* PageTitle.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name =
PageTitle.h; path = "mw-support/PageTitle.h"; sourceTree = "<group>"; };
D4EE00B8182443FC0090790F /* PageTitle.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name
= PageTitle.m; path = "mw-support/PageTitle.m"; sourceTree = "<group>"; };
D4EE00BC1824459D0090790F /* PageTitleTests.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name
= PageTitleTests.m; path = "mw-support/PageTitleTests.m"; sourceTree =
"<group>"; };
@@ -129,6 +138,9 @@
D4991453181D51DE00E6073C /* Images.xcassets */,
D499143F181D51DE00E6073C /* Supporting Files */,
D4EE00BB182445670090790F /* mw-support */,
+ D4DE20321828400C00148CA2 /*
CommunicationBridge.h */,
+ D4DE20331828400C00148CA2 /*
CommunicationBridge.m */,
+ D4DE20361828518B00148CA2 /* bridge-index.html
*/,
);
path = "Wikipedia-iOS";
sourceTree = "<group>";
@@ -150,6 +162,7 @@
D4991466181D51DF00E6073C /*
Wikipedia_iOSTests.m */,
D4991461181D51DF00E6073C /* Supporting Files */,
D4EE00BC1824459D0090790F /* PageTitleTests.m */,
+ D4DE203018283FF200148CA2 /*
CommunicationBridgeTests.m */,
);
path = "Wikipedia-iOSTests";
sourceTree = "<group>";
@@ -253,6 +266,7 @@
files = (
D4991454181D51DE00E6073C /* Images.xcassets in
Resources */,
D499144C181D51DE00E6073C /*
Main_iPhone.storyboard in Resources */,
+ D4DE20371828518B00148CA2 /* bridge-index.html
in Resources */,
D4991443181D51DE00E6073C /* InfoPlist.strings
in Resources */,
D4BC22B4181E9E6300CAC673 /* empty.png in
Resources */,
);
@@ -262,6 +276,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ D4DE20381828518B00148CA2 /* bridge-index.html
in Resources */,
D4991465181D51DF00E6073C /* InfoPlist.strings
in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -273,6 +288,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ D4DE20341828400C00148CA2 /*
CommunicationBridge.m in Sources */,
D4991452181D51DE00E6073C /* ViewController.m in
Sources */,
D4EE00B9182443FC0090790F /* PageTitle.m in
Sources */,
D4991449181D51DE00E6073C /* AppDelegate.m in
Sources */,
@@ -284,9 +300,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ D4DE20351828400C00148CA2 /*
CommunicationBridge.m in Sources */,
D4991467181D51DF00E6073C /*
Wikipedia_iOSTests.m in Sources */,
D4EE00BD1824459D0090790F /* PageTitleTests.m in
Sources */,
D4EE00BA182443FC0090790F /* PageTitle.m in
Sources */,
+ D4DE203118283FF200148CA2 /*
CommunicationBridgeTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Wikipedia-iOS/CommunicationBridge.h
b/Wikipedia-iOS/CommunicationBridge.h
new file mode 100644
index 0000000..6fc5576
--- /dev/null
+++ b/Wikipedia-iOS/CommunicationBridge.h
@@ -0,0 +1,25 @@
+//
+// CommunicationBridge.h
+// Wikipedia-iOS
+//
+// Created by Brion on 11/4/13.
+// Copyright (c) 2013 Wikimedia Foundation. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef void (^JSListener)(NSString *, NSDictionary *);
+
+@interface CommunicationBridge : NSObject
+
+@property BOOL isDOMReady;
+
+// Public methods
+- (CommunicationBridge *)initWithWebView:(UIWebView *)webView;
+- (void)addListener:(NSString *)messageType withBlock:(JSListener)block;
+
+// Methods reserved for internal and testing
+- (NSMutableArray *)listenersForMessageType:(NSString *)messageType;
+- (void)fireEvent:(NSString *)messageType withPayload:(NSDictionary *)payload;
+
+@end
diff --git a/Wikipedia-iOS/CommunicationBridge.m
b/Wikipedia-iOS/CommunicationBridge.m
new file mode 100644
index 0000000..9a22949
--- /dev/null
+++ b/Wikipedia-iOS/CommunicationBridge.m
@@ -0,0 +1,66 @@
+//
+// CommunicationBridge.m
+// Wikipedia-iOS
+//
+// Created by Brion on 11/4/13.
+// Copyright (c) 2013 Wikimedia Foundation. All rights reserved.
+//
+
+#import "CommunicationBridge.h"
+
+@implementation CommunicationBridge {
+ UIWebView *webView;
+ NSMutableDictionary *listenersByEvent;
+}
+
+#pragma mark Public methods
+
+- (CommunicationBridge *)initWithWebView:(UIWebView *)targetWebView
+{
+ self = [super init];
+ if (self) {
+ webView = targetWebView;
+ listenersByEvent = [[NSMutableDictionary alloc] init];
+ }
+ [self setupWebView];
+ return self;
+}
+
+- (void)addListener:(NSString *)messageType withBlock:(JSListener)block
+{
+ NSMutableArray *listeners = [self listenersForMessageType:messageType];
+ if (listeners == nil) {
+ listenersByEvent[messageType] = [NSMutableArray arrayWithObject:block];
+ } else {
+ [listeners addObject:block];
+ }
+}
+
+
+#pragma mark Internal and testing methods
+
+// Methods reserved for internal and testing
+- (NSMutableArray *)listenersForMessageType:(NSString *)messageType
+{
+ return listenersByEvent[messageType];
+}
+
+- (void)fireEvent:(NSString *)messageType withPayload:(NSDictionary *)payload
+{
+ NSArray *listeners = [self listenersForMessageType:messageType];
+ for (JSListener listener in listeners) {
+ listener(messageType, payload);
+ }
+}
+
+#pragma mark Private methods
+
+- (void)setupWebView
+{
+ NSString *path = [[NSBundle mainBundle] pathForResource:@"bridge-index"
ofType:@"html"];
+ NSURL *baseURL = [NSURL URLWithString:@"x-wikipedia-app:///"];
+ NSData *data = [NSData dataWithContentsOfFile:path];
+ [webView loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8"
baseURL:baseURL];
+}
+
+@end
diff --git a/Wikipedia-iOS/bridge-index.html b/Wikipedia-iOS/bridge-index.html
new file mode 100644
index 0000000..d9a305e
--- /dev/null
+++ b/Wikipedia-iOS/bridge-index.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <base href="https://wikipedia.org" /> <!-- Force links to resolve with
https as protocol, rather than file:// -->
+ <script>
+ ( function() {
+ var Bridge = function() {
+ this.eventHandlers = {};
+ };
+
+ Bridge.prototype.handleMessage = function( type, payload ) {
+ var that = this;
+ if ( this.eventHandlers.hasOwnProperty( type ) ) {
+ this.eventHandlers[type].forEach( function( callback ) {
+ callback.call( that, payload );
+ } );
+ }
+ };
+
+ Bridge.prototype.registerListener = function( messageType,
callback ) {
+ if ( this.eventHandlers.hasOwnProperty( messageType ) ) {
+ this.eventHandlers[messageType].push( callback );
+ } else {
+ this.eventHandlers[messageType] = [ callback ];
+ }
+ };
+
+ Bridge.prototype.sendMessage = function( messageType, payload ) {
+ var messagePack = { type: messageType, payload: payload };
+ return prompt( JSON.stringify( messagePack) );
+ };
+
+ window.bridge = new Bridge();
+ } )();
+ </script>
+ <script>
+ ( function() {
+ window.onload = function() {
+ bridge.sendMessage( "DOMLoaded", {} );
+ };
+
+ bridge.registerListener( "displayLeadSection", function( payload
) {
+ document.getElementById( "content" ).innerHTML =
payload.leadSectionHTML;
+ });
+
+ } )();
+ </script>
+ </head>
+ <body>
+ <h1 id="title"></h1>
+ <div id="content"></div>
+ </body>
+</html>
\ No newline at end of file
diff --git a/Wikipedia-iOSTests/CommunicationBridgeTests.m
b/Wikipedia-iOSTests/CommunicationBridgeTests.m
new file mode 100644
index 0000000..e1c8cde
--- /dev/null
+++ b/Wikipedia-iOSTests/CommunicationBridgeTests.m
@@ -0,0 +1,83 @@
+//
+// CommunicationBridgeTests.m
+// Wikipedia-iOS
+//
+// Created by Brion on 11/4/13.
+// Copyright (c) 2013 Wikimedia Foundation. All rights reserved.
+//
+
+#import <XCTest/XCTest.h>
+#import "CommunicationBridge.h"
+
+@interface CommunicationBridgeTests : XCTestCase
+
+@end
+
+@implementation CommunicationBridgeTests {
+ UIWindow *window;
+ UIWebView *webView;
+ CommunicationBridge *bridge;
+}
+
+- (void)setUp
+{
+ [super setUp];
+ window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
+ webView = [[UIWebView alloc] initWithFrame:window.frame];
+ [window addSubview:webView];
+ bridge = [[CommunicationBridge alloc] initWithWebView:webView];
+}
+
+- (void)tearDown
+{
+ window = nil;
+ [super tearDown];
+}
+
+- (void)testCreated
+{
+ XCTAssertNotNil(bridge);
+}
+
+- (void)testAddListener
+{
+ JSListener listener = [^(NSString *messageType, NSDictionary *payload) {
+ // whee!
+ } copy];
+ [bridge addListener:@"DOMLoaded" withBlock:listener];
+ NSArray *listeners = [bridge listenersForMessageType:@"DOMLoaded"];
+ XCTAssertNotNil(listeners);
+ XCTAssert(listeners.count > 0);
+ // note: can't check for the actual object as it gets automatically copied
due to ARC oddities
+}
+
+- (void)testFireEvent
+{
+ __block NSString *foundMessageType = @"<failed to fire>";
+ __block NSDictionary *foundPayload;
+ JSListener listener = [^(NSString *messageType, NSDictionary *payload) {
+ foundMessageType = messageType;
+ foundPayload = payload;
+ } copy];
+ [bridge addListener:@"TestEvent" withBlock:listener];
+ [bridge fireEvent:@"TestEvent" withPayload:@{}];
+ XCTAssertEqual(@"TestEvent", foundMessageType, @"got unexpected %@",
foundMessageType);
+ XCTAssertNotNil(foundPayload);
+}
+
+- (void)testDOMLoaded
+{
+ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
+
+ __block NSString *foundMessageType = @"<failed to fire>";
+
+ [bridge addListener:@"DOMLoaded" withBlock:^(NSString *messageType,
NSDictionary *payload) {
+ foundMessageType = messageType;
+ dispatch_semaphore_signal(semaphore);
+ }];
+ dispatch_semaphore_wait(semaphore, 5);
+
+ XCTAssertEqual(@"DOMLoaded", foundMessageType, @"got unexpected %@",
foundMessageType);
+}
+
+@end
--
To view, visit https://gerrit.wikimedia.org/r/93609
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I667314bad95e774539a93d17d794169c9cb224fb
Gerrit-PatchSet: 1
Gerrit-Project: apps/ios/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Brion VIBBER <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits