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

Reply via email to