From b817cf5b7d529eecfe64321f6bb06396290f55e5 Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Fri, 19 Jun 2015 18:53:55 -0700 Subject: [PATCH 1/9] Applies a fix for encoding issues --- caravel-test.xcodeproj/project.pbxproj | 12 ++++ caravel-test/Base.lproj/Main.storyboard | 72 +++++++++++++++++++--- caravel-test/HazardousDataController.swift | 32 ++++++++++ caravel-test/html/hazardous_data.html | 5 ++ caravel-test/js/basic_triggering.js | 2 +- caravel-test/js/hazardous_data.js | 2 + caravel/ArgumentParser.swift | 48 +++------------ caravel/Caravel.swift | 22 +++---- caravel/js/caravel.coffee | 6 +- caravel/js/caravel.min.js | 4 +- 10 files changed, 141 insertions(+), 64 deletions(-) create mode 100644 caravel-test/HazardousDataController.swift create mode 100644 caravel-test/html/hazardous_data.html create mode 100644 caravel-test/js/hazardous_data.js diff --git a/caravel-test.xcodeproj/project.pbxproj b/caravel-test.xcodeproj/project.pbxproj index e1d03fc..97f8ede 100644 --- a/caravel-test.xcodeproj/project.pbxproj +++ b/caravel-test.xcodeproj/project.pbxproj @@ -19,6 +19,9 @@ A75AD4071B191ADF00404C06 /* TwoBusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75AD4061B191ADF00404C06 /* TwoBusController.swift */; }; A75AD4091B191C7A00404C06 /* two_buses.js in Resources */ = {isa = PBXBuildFile; fileRef = A75AD4081B191C7A00404C06 /* two_buses.js */; }; A75AD40B1B191C8000404C06 /* two_buses.html in Resources */ = {isa = PBXBuildFile; fileRef = A75AD40A1B191C8000404C06 /* two_buses.html */; }; + A79486C21B34F3300010D419 /* HazardousDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79486C11B34F3300010D419 /* HazardousDataController.swift */; }; + A79486C41B34F3D10010D419 /* hazardous_data.js in Resources */ = {isa = PBXBuildFile; fileRef = A79486C31B34F3D10010D419 /* hazardous_data.js */; }; + A79486C61B34F5BD0010D419 /* hazardous_data.html in Resources */ = {isa = PBXBuildFile; fileRef = A79486C51B34F5BD0010D419 /* hazardous_data.html */; }; A797628D1B198B98006D94CB /* event_name.html in Resources */ = {isa = PBXBuildFile; fileRef = A797628C1B198B98006D94CB /* event_name.html */; }; A797628F1B198B9F006D94CB /* event_name.js in Resources */ = {isa = PBXBuildFile; fileRef = A797628E1B198B9F006D94CB /* event_name.js */; }; A79762911B198BA7006D94CB /* EventNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79762901B198BA7006D94CB /* EventNameController.swift */; }; @@ -61,6 +64,9 @@ A75AD4061B191ADF00404C06 /* TwoBusController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoBusController.swift; sourceTree = ""; }; A75AD4081B191C7A00404C06 /* two_buses.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = two_buses.js; path = js/two_buses.js; sourceTree = ""; }; A75AD40A1B191C8000404C06 /* two_buses.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = two_buses.html; path = html/two_buses.html; sourceTree = ""; }; + A79486C11B34F3300010D419 /* HazardousDataController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HazardousDataController.swift; sourceTree = ""; }; + A79486C31B34F3D10010D419 /* hazardous_data.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = hazardous_data.js; path = js/hazardous_data.js; sourceTree = ""; }; + A79486C51B34F5BD0010D419 /* hazardous_data.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = hazardous_data.html; path = html/hazardous_data.html; sourceTree = ""; }; A797628C1B198B98006D94CB /* event_name.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = event_name.html; path = html/event_name.html; sourceTree = ""; }; A797628E1B198B9F006D94CB /* event_name.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = event_name.js; path = js/event_name.js; sourceTree = ""; }; A79762901B198BA7006D94CB /* EventNameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventNameController.swift; sourceTree = ""; }; @@ -108,6 +114,7 @@ children = ( A79762961B19954A006D94CB /* event_data.html */, A797628C1B198B98006D94CB /* event_name.html */, + A79486C51B34F5BD0010D419 /* hazardous_data.html */, A75AD40A1B191C8000404C06 /* two_buses.html */, A75AD4041B191A1800404C06 /* two_events.html */, A75AD3FC1B1917BE00404C06 /* multiple_subscribers.html */, @@ -122,6 +129,7 @@ children = ( A7AC9F291B349BB40041EB0B /* caravel.min.js */, A79762941B199541006D94CB /* event_data.js */, + A79486C31B34F3D10010D419 /* hazardous_data.js */, A75AD4081B191C7A00404C06 /* two_buses.js */, A797628E1B198B9F006D94CB /* event_name.js */, A7C869071B18CF450070AF5A /* basic_triggering.js */, @@ -169,6 +177,7 @@ A75AD4061B191ADF00404C06 /* TwoBusController.swift */, A79762901B198BA7006D94CB /* EventNameController.swift */, A79762921B19904C006D94CB /* EventDataController.swift */, + A79486C11B34F3300010D419 /* HazardousDataController.swift */, ); path = "caravel-test"; sourceTree = ""; @@ -294,6 +303,8 @@ A75AD3F71B1914FB00404C06 /* initialization.js in Resources */, A75AD4091B191C7A00404C06 /* two_buses.js in Resources */, A75AD3F91B19150200404C06 /* initialization.html in Resources */, + A79486C61B34F5BD0010D419 /* hazardous_data.html in Resources */, + A79486C41B34F3D10010D419 /* hazardous_data.js in Resources */, A75AD3FF1B1917C300404C06 /* multiple_subscribers.js in Resources */, A7C869081B18CF450070AF5A /* basic_triggering.js in Resources */, ); @@ -314,6 +325,7 @@ buildActionMask = 2147483647; files = ( A75AD3FB1B19169200404C06 /* MultipleSubscriberController.swift in Sources */, + A79486C21B34F3300010D419 /* HazardousDataController.swift in Sources */, A7F1DE2B1B18045C001E9B94 /* ViewController.swift in Sources */, A75AD3F51B1913B600404C06 /* InitializationController.swift in Sources */, A79762911B198BA7006D94CB /* EventNameController.swift in Sources */, diff --git a/caravel-test/Base.lproj/Main.storyboard b/caravel-test/Base.lproj/Main.storyboard index 66f4392..2c7d610 100644 --- a/caravel-test/Base.lproj/Main.storyboard +++ b/caravel-test/Base.lproj/Main.storyboard @@ -52,7 +52,7 @@ - + @@ -135,6 +135,15 @@ + @@ -195,7 +204,7 @@ - + @@ -244,7 +253,7 @@ - + @@ -293,7 +302,56 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -342,7 +400,7 @@ - + @@ -391,7 +449,7 @@ - + @@ -440,7 +498,7 @@ - + diff --git a/caravel-test/HazardousDataController.swift b/caravel-test/HazardousDataController.swift new file mode 100644 index 0000000..5cc730d --- /dev/null +++ b/caravel-test/HazardousDataController.swift @@ -0,0 +1,32 @@ +// +// HazardousDataController.swift +// caravel-test +// +// Created by Adrien on 19/06/15. +// Copyright (c) 2015 Coshx Labs. All rights reserved. +// + +import Foundation +import UIKit +import Caravel + +public class HazardousDataController: UIViewController { + + @IBOutlet weak var _webView: UIWebView! + + public override func viewDidLoad() { + super.viewDidLoad() + + Caravel.get("@D@ngerousBus@", webView: _webView).whenReady() { bus in + bus.register("@D@ngerousEvent") { name, data in + var s = data as! String + + if s != "@@@" { + NSException(name: "@@@", reason: "", userInfo: nil) + } + } + } + + _webView.loadRequest(NSURLRequest(URL: NSBundle.mainBundle().URLForResource("hazardous_data", withExtension: "html")!)) + } +} \ No newline at end of file diff --git a/caravel-test/html/hazardous_data.html b/caravel-test/html/hazardous_data.html new file mode 100644 index 0000000..bbe3541 --- /dev/null +++ b/caravel-test/html/hazardous_data.html @@ -0,0 +1,5 @@ +

Hazardous data

+ + + + \ No newline at end of file diff --git a/caravel-test/js/basic_triggering.js b/caravel-test/js/basic_triggering.js index 104b2cf..d826da6 100644 --- a/caravel-test/js/basic_triggering.js +++ b/caravel-test/js/basic_triggering.js @@ -1,5 +1,5 @@ Caravel.getDefault().register("From iOS", function(name, data) { - $('body').append('

Received From iOS!'); + $('body').append('

Received From iOS!

'); }); Caravel.getDefault().post("From JS"); diff --git a/caravel-test/js/hazardous_data.js b/caravel-test/js/hazardous_data.js new file mode 100644 index 0000000..4e42f97 --- /dev/null +++ b/caravel-test/js/hazardous_data.js @@ -0,0 +1,2 @@ +Caravel.get('@D@ngerousBus').post('@D@ngerousEvent', '@@@'); +Caravel.get('@D@ngerousBus').post('@D@ngerousBusWith@rgument'); \ No newline at end of file diff --git a/caravel/ArgumentParser.swift b/caravel/ArgumentParser.swift index 8c89dad..dafdeeb 100644 --- a/caravel/ArgumentParser.swift +++ b/caravel/ArgumentParser.swift @@ -14,49 +14,21 @@ import Foundation */ internal class ArgumentParser { - internal class func parse(input: String) -> [String] { - var outcome = [String]() - var prev: Character? - var buffer = String() + internal class func parse(input: String) -> (busName: String, eventName: String, eventData: String?) { + var queryPairs = input.componentsSeparatedByString("&") + var outcome: (busName: String, eventName: String, eventData: String?) = (busName: "", eventName: "", eventData: nil) - if count(input) == 0 { // No arg - return outcome - } - - for current in input { - if current == "@" { - if prev != nil && prev != "\\" { - // Arguments are split using "@" symbol - // Existing "@" have been escaped before - outcome.append(buffer) - buffer = "" - } else if prev != nil && prev == "\\" { - // Escaped "@" symbol - // Let's unescape it - var i = 0, size = count(buffer) - var s = "" - - for c in buffer { - if i < size - 1 { - s.append(c) - } - i++ - } - - buffer = s - buffer.append(current) - } - // A "@" symbol cannot be first as it has been escaped, so no else condition + for p in queryPairs { + var keyValue = p.componentsSeparatedByString("=") + if keyValue[0] == "busName" { + outcome.busName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! + } else if keyValue[1] == "eventName" { + outcome.eventName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! } else { - buffer.append(current) + outcome.eventData = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding) } - - prev = current } - // Add latest buffer - outcome.append(buffer) - return outcome } } \ No newline at end of file diff --git a/caravel/Caravel.swift b/caravel/Caravel.swift index f10a3d1..5aac349 100644 --- a/caravel/Caravel.swift +++ b/caravel/Caravel.swift @@ -89,18 +89,14 @@ public class Caravel: NSObject, UIWebViewDelegate { * int, float, double, string */ public func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { - if let lastPathComponent: String = request.URL?.lastPathComponent { - - // The last path of the URL needs to contains at least the "caravel" word - if count(lastPathComponent) > count("caravel") && (lastPathComponent as NSString).substringToIndex(count("caravel")) == "caravel" { - var args = ArgumentParser.parse(lastPathComponent) - var busName = args[1] - var eventName = args[2] + if let scheme: String = request.URL?.scheme { + if scheme == "caravel" { + var args = ArgumentParser.parse(request.URL!.query!) // All buses are notified about that incoming event. Then, they need to investigate first if they // are potential receivers - if _name == busName { - if eventName == "CaravelInit" { // Reserved event name. Triggers whenReady + if _name == args.busName { + if args.eventName == "CaravelInit" { // Reserved event name. Triggers whenReady objc_sync_enter(_initializationLock) _isInitialized = true @@ -114,14 +110,14 @@ public class Caravel: NSObject, UIWebViewDelegate { } else { var eventData: AnyObject? = nil - if args.count > 3 { // Arg is optional - eventData = DataSerializer.deserialize(args[3]) + if let d = args.eventData { // Data are optional + eventData = DataSerializer.deserialize(d) } for s in _subscribers { - if s.name == eventName { + if s.name == args.eventName { dispatch_async(dispatch_get_main_queue()) { - s.callback(eventName, eventData) + s.callback(args.eventName, eventData) } } } diff --git a/caravel/js/caravel.coffee b/caravel/js/caravel.coffee index 102a87c..88de9d9 100644 --- a/caravel/js/caravel.coffee +++ b/caravel/js/caravel.coffee @@ -12,12 +12,12 @@ class Caravel _post: (eventName, data) -> # TODO: Improve that code using an AJAX request iframe = document.createElement 'iframe' - src = "caravel@#{@name}@#{eventName}" + src = "caravel://host.com?busName=#{encodeURIComponent(@name)}&eventName=#{encodeURIComponent(eventName)}" if data? if data instanceof Array or data instanceof Object - src += "@#{JSON.stringify(data)}" + src += "&eventData=#{encodeURIComponent(JSON.stringify(data))}" else - src += "@#{data}" + src += "&eventData=#{encodeURIComponent(data)}" iframe.setAttribute 'src', src document.documentElement.appendChild iframe iframe.parentNode.removeChild iframe diff --git a/caravel/js/caravel.min.js b/caravel/js/caravel.min.js index 9d0b76a..69cc9f5 100644 --- a/caravel/js/caravel.min.js +++ b/caravel/js/caravel.min.js @@ -1,2 +1,2 @@ -/** Caravel 0.3.1 - https://github.com/coshx/caravel */ -var Caravel;Caravel=function(){function Caravel(name){this.name=name,this.subscribers=[]}return Caravel["default"]=null,Caravel.buses=[],Caravel.prototype._post=function(eventName,data){var iframe,src;return iframe=document.createElement("iframe"),src="caravel@"+this.name+"@"+eventName,null!=data&&(src+=data instanceof Array||data instanceof Object?"@"+JSON.stringify(data):"@"+data),iframe.setAttribute("src",src),document.documentElement.appendChild(iframe),iframe.parentNode.removeChild(iframe)},Caravel.prototype.getName=function(){return this.name},Caravel.prototype.post=function(name,data){return this._post(name,data)},Caravel.prototype.register=function(name,callback){return this.subscribers.push({name:name,callback:callback})},Caravel.prototype.raise=function(name,data){var e,i,len,parsedData,ref,results;for(parsedData=data instanceof Array||data instanceof Object||"string"==typeof data||data instanceof String?data:JSON.parse(data),ref=this.subscribers,results=[],i=0,len=ref.length;len>i;i++)e=ref[i],e.name===name?results.push(e.callback(name,parsedData)):results.push(void 0);return results},Caravel.getDefault=function(){return null==Caravel["default"]&&(Caravel["default"]=new Caravel("default"),Caravel["default"].post("CaravelInit")),Caravel["default"]},Caravel.get=function(name){var b,i,len,ref;for(ref=Caravel.buses,i=0,len=ref.length;len>i;i++)if(b=ref[i],b.getName()===name)return b;return b=new Caravel(name),Caravel.buses.push(b),b.post("CaravelInit"),b},Caravel}(); \ No newline at end of file +/** Caravel 0.3.2 - https://github.com/coshx/caravel */ +var Caravel;Caravel=function(){function Caravel(name){this.name=name,this.subscribers=[]}return Caravel["default"]=null,Caravel.buses=[],Caravel.prototype._post=function(eventName,data){var iframe,src;return iframe=document.createElement("iframe"),src="caravel://host.com?busName="+encodeURIComponent(this.name)+"&eventName="+encodeURIComponent(eventName),null!=data&&(src+=data instanceof Array||data instanceof Object?"&eventData="+encodeURIComponent(JSON.stringify(data)):"&eventData="+encodeURIComponent(data)),iframe.setAttribute("src",src),document.documentElement.appendChild(iframe),iframe.parentNode.removeChild(iframe)},Caravel.prototype.getName=function(){return this.name},Caravel.prototype.post=function(name,data){return this._post(name,data)},Caravel.prototype.register=function(name,callback){return this.subscribers.push({name:name,callback:callback})},Caravel.prototype.raise=function(name,data){var e,i,len,parsedData,ref,results;for(parsedData=data instanceof Array||data instanceof Object||"string"==typeof data||data instanceof String?data:JSON.parse(data),ref=this.subscribers,results=[],i=0,len=ref.length;len>i;i++)e=ref[i],e.name===name?results.push(e.callback(name,parsedData)):results.push(void 0);return results},Caravel.getDefault=function(){return null==Caravel["default"]&&(Caravel["default"]=new Caravel("default"),Caravel["default"].post("CaravelInit")),Caravel["default"]},Caravel.get=function(name){var b,i,len,ref;for(ref=Caravel.buses,i=0,len=ref.length;len>i;i++)if(b=ref[i],b.getName()===name)return b;return b=new Caravel(name),Caravel.buses.push(b),b.post("CaravelInit"),b},Caravel}(); \ No newline at end of file From 7735a2f2954a60e75f6ca08d2b7b9187f820b271 Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Fri, 19 Jun 2015 19:03:26 -0700 Subject: [PATCH 2/9] Adds hints to existing tests --- caravel-test/html/basic_triggering.html | 2 ++ caravel-test/html/event_name.html | 2 ++ caravel-test/html/initialization.html | 2 ++ caravel-test/html/multiple_subscribers.html | 2 ++ caravel-test/html/two_buses.html | 2 ++ caravel-test/html/two_events.html | 2 ++ 6 files changed, 12 insertions(+) diff --git a/caravel-test/html/basic_triggering.html b/caravel-test/html/basic_triggering.html index c9f714d..0e629a0 100644 --- a/caravel-test/html/basic_triggering.html +++ b/caravel-test/html/basic_triggering.html @@ -1,5 +1,7 @@

Basic triggering

+

You should see:

Received From iOS!

+ \ No newline at end of file diff --git a/caravel-test/html/event_name.html b/caravel-test/html/event_name.html index a536d29..27b3ce6 100644 --- a/caravel-test/html/event_name.html +++ b/caravel-test/html/event_name.html @@ -1,5 +1,7 @@

Event name

+

You should only see

You should see me

+ \ No newline at end of file diff --git a/caravel-test/html/initialization.html b/caravel-test/html/initialization.html index 66c2d52..fb1d0a0 100644 --- a/caravel-test/html/initialization.html +++ b/caravel-test/html/initialization.html @@ -1,5 +1,7 @@

Initialization

+

You should see

Before
After

+ \ No newline at end of file diff --git a/caravel-test/html/multiple_subscribers.html b/caravel-test/html/multiple_subscribers.html index a007dfa..590a2ca 100644 --- a/caravel-test/html/multiple_subscribers.html +++ b/caravel-test/html/multiple_subscribers.html @@ -1,5 +1,7 @@

Multiple subscribers

+

You should see:

First!
Second!

+ \ No newline at end of file diff --git a/caravel-test/html/two_buses.html b/caravel-test/html/two_buses.html index 1f27e13..1c21eb3 100644 --- a/caravel-test/html/two_buses.html +++ b/caravel-test/html/two_buses.html @@ -1,5 +1,7 @@

Two buses

+

You should see

You should see me first and only once
You should see me after and only once

+ \ No newline at end of file diff --git a/caravel-test/html/two_events.html b/caravel-test/html/two_events.html index 0cf7b0b..177e977 100644 --- a/caravel-test/html/two_events.html +++ b/caravel-test/html/two_events.html @@ -1,5 +1,7 @@

Two events

+

You should only see

You should see me and only me

+ \ No newline at end of file From 539c69514e825962605775b7e1aff435ef5c8c0f Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Fri, 19 Jun 2015 19:03:36 -0700 Subject: [PATCH 3/9] Fixes index trouble --- caravel/ArgumentParser.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caravel/ArgumentParser.swift b/caravel/ArgumentParser.swift index dafdeeb..8f44a8b 100644 --- a/caravel/ArgumentParser.swift +++ b/caravel/ArgumentParser.swift @@ -22,7 +22,7 @@ internal class ArgumentParser { var keyValue = p.componentsSeparatedByString("=") if keyValue[0] == "busName" { outcome.busName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! - } else if keyValue[1] == "eventName" { + } else if keyValue[0] == "eventName" { outcome.eventName = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! } else { outcome.eventData = keyValue[1].stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding) From a7ee23a5f89c8a6618868d8b779bedab3cd6689b Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Fri, 19 Jun 2015 19:10:28 -0700 Subject: [PATCH 4/9] Night stashing - TOFIX --- caravel-test/js/event_data.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/caravel-test/js/event_data.js b/caravel-test/js/event_data.js index dc87f2b..e76f8f5 100644 --- a/caravel-test/js/event_data.js +++ b/caravel-test/js/event_data.js @@ -3,6 +3,9 @@ function ok(name) { } function fail(name, data) { + if ((data instanceof Array) || (data instanceof Object)) { + data = JSON.stringify(data); + } $('body').append('

Failed for ' + name + ': received ' + data + '

'); } @@ -62,6 +65,22 @@ Caravel.getDefault().register("Array", function(name, data) { } }); +Caravel.getDefault().register("ComplexArray", function(name, data) { + if (JSON.stringify(data) == JSON.stringify([{name: "Alice", age: 24}, {name: "Bob", age: 23}])) { + ok(name); + } else { + fail(name, data); + } +}); + +Caravel.getDefault().register("ComplexDictionary", function(name, data) { + if (JSON.stringify(data) == JSON.stringify({name: "Cesar", address: { street: "Parrot", city: "Perigueux" }, games: ["Fifa", "Star Wars"]})) { + ok(name); + } else { + fail(name, data); + } +}); + Caravel.getDefault().register("Dictionary", function(name, data) { if (JSON.stringify(data) == JSON.stringify({ foo: 45, bar: 89 })) { ok(name); From ea6998625db7c32f746a51766c7aff2d4233d9b7 Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Mon, 22 Jun 2015 09:32:35 -0700 Subject: [PATCH 5/9] Fixes event data test --- caravel-test/js/event_data.js | 48 +++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/caravel-test/js/event_data.js b/caravel-test/js/event_data.js index e76f8f5..b2e9cf0 100644 --- a/caravel-test/js/event_data.js +++ b/caravel-test/js/event_data.js @@ -65,27 +65,53 @@ Caravel.getDefault().register("Array", function(name, data) { } }); -Caravel.getDefault().register("ComplexArray", function(name, data) { - if (JSON.stringify(data) == JSON.stringify([{name: "Alice", age: 24}, {name: "Bob", age: 23}])) { +Caravel.getDefault().register("Dictionary", function(name, data) { + if (JSON.stringify(data) == JSON.stringify({ foo: 45, bar: 89 })) { ok(name); } else { fail(name, data); } }); -Caravel.getDefault().register("ComplexDictionary", function(name, data) { - if (JSON.stringify(data) == JSON.stringify({name: "Cesar", address: { street: "Parrot", city: "Perigueux" }, games: ["Fifa", "Star Wars"]})) { - ok(name); - } else { +Caravel.getDefault().register("ComplexArray", function(name, data) { + var expectedData = [{name: "Alice", age: 24}, {name: "Bob", age: 23}]; + var customFail = function() { fail(name, data); + }; + + if (data.length == 2) { + if (data[0].name == expectedData[0].name && data[0].age == expectedData[0].age) { + if (data[1].name == expectedData[1].name && data[1].age == expectedData[1].age) { + ok(name); + } else { + customFail(); + } + } else { + customFail(); + } + } else { + customFail(); } }); -Caravel.getDefault().register("Dictionary", function(name, data) { - if (JSON.stringify(data) == JSON.stringify({ foo: 45, bar: 89 })) { - ok(name); - } else { +Caravel.getDefault().register("ComplexDictionary", function(name, data) { + var expectedData = {name: "Cesar", address: { street: "Parrot", city: "Perigueux" }, games: ["Fifa", "Star Wars"]}; + var customFail = function() { fail(name, data); + }; + + if (data.name == expectedData.name) { + if (data.address.street == expectedData.address.street && data.address.city == expectedData.address.city) { + if (data.length == expectedData.length && data.games[0] == expectedData.games[0] && data.games[1] == expectedData.games[1]) { + ok(name); + } else { + customFail(); + } + } else { + customFail(); + } + } else { + customFail(); } }); @@ -94,4 +120,4 @@ Caravel.getDefault().post("Float", 19.89); Caravel.getDefault().post("Double", 15.15); Caravel.getDefault().post("String", "Napoleon"); Caravel.getDefault().post("Array", [3, 1, 4]); -Caravel.getDefault().post("Dictionary", { "movie": "Once upon a time in the West", "actor": "Charles Bronson" }); \ No newline at end of file +Caravel.getDefault().post("Dictionary", { "movie": "Once upon a time in the West", "actor": "Charles Bronson" }); From 249a0321bcb1ab5df4fedce9d16be12eec1877b3 Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Mon, 22 Jun 2015 10:10:24 -0700 Subject: [PATCH 6/9] Tests if complex arrays and dictionaries are supported --- caravel-test.xcodeproj/project.pbxproj | 12 ----- caravel-test/Base.lproj/Main.storyboard | 58 ---------------------- caravel-test/EventDataController.swift | 51 +++++++++++++++++++ caravel-test/HazardousDataController.swift | 32 ------------ caravel-test/html/hazardous_data.html | 5 -- caravel-test/js/event_data.js | 3 ++ caravel-test/js/hazardous_data.js | 2 - 7 files changed, 54 insertions(+), 109 deletions(-) delete mode 100644 caravel-test/HazardousDataController.swift delete mode 100644 caravel-test/html/hazardous_data.html delete mode 100644 caravel-test/js/hazardous_data.js diff --git a/caravel-test.xcodeproj/project.pbxproj b/caravel-test.xcodeproj/project.pbxproj index 97f8ede..e1d03fc 100644 --- a/caravel-test.xcodeproj/project.pbxproj +++ b/caravel-test.xcodeproj/project.pbxproj @@ -19,9 +19,6 @@ A75AD4071B191ADF00404C06 /* TwoBusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75AD4061B191ADF00404C06 /* TwoBusController.swift */; }; A75AD4091B191C7A00404C06 /* two_buses.js in Resources */ = {isa = PBXBuildFile; fileRef = A75AD4081B191C7A00404C06 /* two_buses.js */; }; A75AD40B1B191C8000404C06 /* two_buses.html in Resources */ = {isa = PBXBuildFile; fileRef = A75AD40A1B191C8000404C06 /* two_buses.html */; }; - A79486C21B34F3300010D419 /* HazardousDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79486C11B34F3300010D419 /* HazardousDataController.swift */; }; - A79486C41B34F3D10010D419 /* hazardous_data.js in Resources */ = {isa = PBXBuildFile; fileRef = A79486C31B34F3D10010D419 /* hazardous_data.js */; }; - A79486C61B34F5BD0010D419 /* hazardous_data.html in Resources */ = {isa = PBXBuildFile; fileRef = A79486C51B34F5BD0010D419 /* hazardous_data.html */; }; A797628D1B198B98006D94CB /* event_name.html in Resources */ = {isa = PBXBuildFile; fileRef = A797628C1B198B98006D94CB /* event_name.html */; }; A797628F1B198B9F006D94CB /* event_name.js in Resources */ = {isa = PBXBuildFile; fileRef = A797628E1B198B9F006D94CB /* event_name.js */; }; A79762911B198BA7006D94CB /* EventNameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79762901B198BA7006D94CB /* EventNameController.swift */; }; @@ -64,9 +61,6 @@ A75AD4061B191ADF00404C06 /* TwoBusController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoBusController.swift; sourceTree = ""; }; A75AD4081B191C7A00404C06 /* two_buses.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = two_buses.js; path = js/two_buses.js; sourceTree = ""; }; A75AD40A1B191C8000404C06 /* two_buses.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = two_buses.html; path = html/two_buses.html; sourceTree = ""; }; - A79486C11B34F3300010D419 /* HazardousDataController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HazardousDataController.swift; sourceTree = ""; }; - A79486C31B34F3D10010D419 /* hazardous_data.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = hazardous_data.js; path = js/hazardous_data.js; sourceTree = ""; }; - A79486C51B34F5BD0010D419 /* hazardous_data.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = hazardous_data.html; path = html/hazardous_data.html; sourceTree = ""; }; A797628C1B198B98006D94CB /* event_name.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = event_name.html; path = html/event_name.html; sourceTree = ""; }; A797628E1B198B9F006D94CB /* event_name.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = event_name.js; path = js/event_name.js; sourceTree = ""; }; A79762901B198BA7006D94CB /* EventNameController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventNameController.swift; sourceTree = ""; }; @@ -114,7 +108,6 @@ children = ( A79762961B19954A006D94CB /* event_data.html */, A797628C1B198B98006D94CB /* event_name.html */, - A79486C51B34F5BD0010D419 /* hazardous_data.html */, A75AD40A1B191C8000404C06 /* two_buses.html */, A75AD4041B191A1800404C06 /* two_events.html */, A75AD3FC1B1917BE00404C06 /* multiple_subscribers.html */, @@ -129,7 +122,6 @@ children = ( A7AC9F291B349BB40041EB0B /* caravel.min.js */, A79762941B199541006D94CB /* event_data.js */, - A79486C31B34F3D10010D419 /* hazardous_data.js */, A75AD4081B191C7A00404C06 /* two_buses.js */, A797628E1B198B9F006D94CB /* event_name.js */, A7C869071B18CF450070AF5A /* basic_triggering.js */, @@ -177,7 +169,6 @@ A75AD4061B191ADF00404C06 /* TwoBusController.swift */, A79762901B198BA7006D94CB /* EventNameController.swift */, A79762921B19904C006D94CB /* EventDataController.swift */, - A79486C11B34F3300010D419 /* HazardousDataController.swift */, ); path = "caravel-test"; sourceTree = ""; @@ -303,8 +294,6 @@ A75AD3F71B1914FB00404C06 /* initialization.js in Resources */, A75AD4091B191C7A00404C06 /* two_buses.js in Resources */, A75AD3F91B19150200404C06 /* initialization.html in Resources */, - A79486C61B34F5BD0010D419 /* hazardous_data.html in Resources */, - A79486C41B34F3D10010D419 /* hazardous_data.js in Resources */, A75AD3FF1B1917C300404C06 /* multiple_subscribers.js in Resources */, A7C869081B18CF450070AF5A /* basic_triggering.js in Resources */, ); @@ -325,7 +314,6 @@ buildActionMask = 2147483647; files = ( A75AD3FB1B19169200404C06 /* MultipleSubscriberController.swift in Sources */, - A79486C21B34F3300010D419 /* HazardousDataController.swift in Sources */, A7F1DE2B1B18045C001E9B94 /* ViewController.swift in Sources */, A75AD3F51B1913B600404C06 /* InitializationController.swift in Sources */, A79762911B198BA7006D94CB /* EventNameController.swift in Sources */, diff --git a/caravel-test/Base.lproj/Main.storyboard b/caravel-test/Base.lproj/Main.storyboard index 2c7d610..56d9679 100644 --- a/caravel-test/Base.lproj/Main.storyboard +++ b/caravel-test/Base.lproj/Main.storyboard @@ -135,15 +135,6 @@ - @@ -304,55 +295,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/caravel-test/EventDataController.swift b/caravel-test/EventDataController.swift index 3e5200f..9f9e9d1 100644 --- a/caravel-test/EventDataController.swift +++ b/caravel-test/EventDataController.swift @@ -107,6 +107,57 @@ public class EventDataController: UIViewController { self._raise("Dictionary - bad type") } } + + bus.register("ComplexArray") { name, data in + if let a = data as? NSArray { + if a.count != 3 { + self._raise("ComplexArray - bad length") + } + if a[0] as! Int != 87 { + self._raise("ComplexArray - bad first element") + } + if let d = a[1] as? NSDictionary { + if d.valueForKey("name") as! String != "Bruce Willis" { + self._raise("ComplexArray - bad second element") + } + } else { + self._raise("ComplexArray - bad typed second element") + } + if a[2] as! String != "left-handed" { + self._raise("ComplexArray - bad third element") + } + } else { + self._raise("ComplexArray - bad type") + } + } + + bus.register("ComplexDictionary") { name, data in + if let d = data as? NSDictionary { + if d.valueForKey("name") as! String != "John Malkovich" { + self._raise("ComplexDictionary - bad first pair") + } + + if let a = d.valueForKey("movies") as? NSArray { + if a.count != 2 { + self._raise("ComplexDictionary - bad length") + } + if a[0] as! String != "Dangerous Liaisons" { + self._raise("ComplexDictionary - bad first element in array") + } + if a[1] as! String != "Burn after reading" { + self._raise("ComplexDictionary - bad second element in array") + } + } else { + self._raise("ComplexDictionary - bad typed second element") + } + + if d.valueForKey("kids") as! Int != 2 { + self._raise("ComplexDictionary - bad third pair") + } + } else { + self._raise("ComplexDictionary - bad type") + } + } } _webView.loadRequest(NSURLRequest(URL: NSBundle.mainBundle().URLForResource("event_data", withExtension: "html")!)) diff --git a/caravel-test/HazardousDataController.swift b/caravel-test/HazardousDataController.swift deleted file mode 100644 index 5cc730d..0000000 --- a/caravel-test/HazardousDataController.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// HazardousDataController.swift -// caravel-test -// -// Created by Adrien on 19/06/15. -// Copyright (c) 2015 Coshx Labs. All rights reserved. -// - -import Foundation -import UIKit -import Caravel - -public class HazardousDataController: UIViewController { - - @IBOutlet weak var _webView: UIWebView! - - public override func viewDidLoad() { - super.viewDidLoad() - - Caravel.get("@D@ngerousBus@", webView: _webView).whenReady() { bus in - bus.register("@D@ngerousEvent") { name, data in - var s = data as! String - - if s != "@@@" { - NSException(name: "@@@", reason: "", userInfo: nil) - } - } - } - - _webView.loadRequest(NSURLRequest(URL: NSBundle.mainBundle().URLForResource("hazardous_data", withExtension: "html")!)) - } -} \ No newline at end of file diff --git a/caravel-test/html/hazardous_data.html b/caravel-test/html/hazardous_data.html deleted file mode 100644 index bbe3541..0000000 --- a/caravel-test/html/hazardous_data.html +++ /dev/null @@ -1,5 +0,0 @@ -

Hazardous data

- - - - \ No newline at end of file diff --git a/caravel-test/js/event_data.js b/caravel-test/js/event_data.js index b2e9cf0..728612e 100644 --- a/caravel-test/js/event_data.js +++ b/caravel-test/js/event_data.js @@ -121,3 +121,6 @@ Caravel.getDefault().post("Double", 15.15); Caravel.getDefault().post("String", "Napoleon"); Caravel.getDefault().post("Array", [3, 1, 4]); Caravel.getDefault().post("Dictionary", { "movie": "Once upon a time in the West", "actor": "Charles Bronson" }); + +Caravel.getDefault().post("ComplexArray", [87, {"name": "Bruce Willis"}, "left-handed" ]); +Caravel.getDefault().post("ComplexDictionary", {name: "John Malkovich", movies: ["Dangerous Liaisons", "Burn after reading"], kids: 2}); \ No newline at end of file diff --git a/caravel-test/js/hazardous_data.js b/caravel-test/js/hazardous_data.js deleted file mode 100644 index 4e42f97..0000000 --- a/caravel-test/js/hazardous_data.js +++ /dev/null @@ -1,2 +0,0 @@ -Caravel.get('@D@ngerousBus').post('@D@ngerousEvent', '@@@'); -Caravel.get('@D@ngerousBus').post('@D@ngerousBusWith@rgument'); \ No newline at end of file From f050c90c565b268db7f6067d32a52b75b25b277c Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Mon, 22 Jun 2015 10:22:11 -0700 Subject: [PATCH 7/9] Comments code before release --- caravel/ArgumentParser.swift | 2 +- caravel/Caravel.swift | 2 +- caravel/DataSerializer.swift | 7 ++++--- caravel/UIWebViewDelegateMediator.swift | 10 +++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/caravel/ArgumentParser.swift b/caravel/ArgumentParser.swift index 8f44a8b..2c80e7a 100644 --- a/caravel/ArgumentParser.swift +++ b/caravel/ArgumentParser.swift @@ -10,7 +10,7 @@ import Foundation /** * @class ArgumentParser - * @brief Parses JS input to a list of arguments + * @brief Parses JS input to a list of arguments. Expected pattern: busName=*&eventName=*&eventData=*. Data are optional */ internal class ArgumentParser { diff --git a/caravel/Caravel.swift b/caravel/Caravel.swift index 5aac349..8a0bf66 100644 --- a/caravel/Caravel.swift +++ b/caravel/Caravel.swift @@ -83,7 +83,7 @@ public class Caravel: NSObject, UIWebViewDelegate { /** * Caravel expects the following pattern: - * caravel@bus_name@event_name@extra_arg + * caravel://host.com?busName=*&eventName=*&eventData=* * * Followed argument types are supported: * int, float, double, string diff --git a/caravel/DataSerializer.swift b/caravel/DataSerializer.swift index ad0eb41..9183301 100644 --- a/caravel/DataSerializer.swift +++ b/caravel/DataSerializer.swift @@ -10,7 +10,7 @@ import Foundation /** * @class DataSerializer - * @brief Serializes iOS data for JS + * @brief Serializes data to JS format and parses data coming from JS */ internal class DataSerializer { @@ -32,12 +32,13 @@ internal class DataSerializer { output = "\(f)" case .String: var s = input as! String + // As string is going to be unwrapped from quotes, when passed to JS, all quotes need to be escaped s = s.stringByReplacingOccurrencesOfString("\"", withString: "\\\"", options: NSStringCompareOptions(), range: nil) s = s.stringByReplacingOccurrencesOfString("'", withString: "\'", options: NSStringCompareOptions(), range: nil) output = "\"\(s)\"" case .Array, .Dictionary: // Array and Dictionary are serialized to JSON. - // They should wrap only basic data (same types than supported ones) + // They should wrap only "basic" data (same types than supported ones) var json = NSJSONSerialization.dataWithJSONObject(input, options: NSJSONWritingOptions(), error: NSErrorPointer())! var s = NSString(data: json, encoding: NSUTF8StringEncoding)! output = s as String @@ -48,7 +49,7 @@ internal class DataSerializer { internal static func deserialize(input: String) -> AnyObject { if count(input) > 0 { - if input[0] == "[" || input[0] == "{" { + if input[0] == "[" || input[0] == "{" { // Array or Dictionary, matching JSON format var json = input.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! return NSJSONSerialization.JSONObjectWithData(json, options: NSJSONReadingOptions(), error: NSErrorPointer())! } diff --git a/caravel/UIWebViewDelegateMediator.swift b/caravel/UIWebViewDelegateMediator.swift index b3a78cc..42f572a 100644 --- a/caravel/UIWebViewDelegateMediator.swift +++ b/caravel/UIWebViewDelegateMediator.swift @@ -22,10 +22,10 @@ internal class UIWebViewDelegateMediator: NSObject, UIWebViewDelegate { /** * All the subscribers. They are sorted by webview's hash */ - private lazy var _webViews: [Int: [UIWebViewDelegate]] = [Int: [UIWebViewDelegate]]() + private lazy var _webViewSubscribers: [Int: [UIWebViewDelegate]] = [Int: [UIWebViewDelegate]]() private func iterateOverDelegates(webView: UIWebView, callback: (UIWebViewDelegate) -> Void) { - var array = UIWebViewDelegateMediator._singleton._webViews[webView.hash]! + var array = UIWebViewDelegateMediator._singleton._webViewSubscribers[webView.hash]! for e in array { callback(e) @@ -38,16 +38,16 @@ internal class UIWebViewDelegateMediator: NSObject, UIWebViewDelegate { var delegates = [UIWebViewDelegate]() delegates.append(webView.delegate!) - _singleton._webViews[webView.hash] = delegates + _singleton._webViewSubscribers[webView.hash] = delegates webView.delegate = _singleton } else if webView.delegate == nil { // No delegate, just initialize - _singleton._webViews[webView.hash] = [UIWebViewDelegate]() + _singleton._webViewSubscribers[webView.hash] = [UIWebViewDelegate]() webView.delegate = _singleton } - _singleton._webViews[webView.hash]!.append(subscriber) + _singleton._webViewSubscribers[webView.hash]!.append(subscriber) } // About methods below: From c1210434c4ef78a0303527f0ccc253b74250acbf Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Mon, 22 Jun 2015 10:27:09 -0700 Subject: [PATCH 8/9] Sets up release --- Caravel.podspec | 6 ++++-- README.md | 4 ++-- caravel/js/Gruntfile.js | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Caravel.podspec b/Caravel.podspec index c30c8b8..8d43eb0 100644 --- a/Caravel.podspec +++ b/Caravel.podspec @@ -15,8 +15,10 @@ Pod::Spec.new do |s| # summary should be tweet-length, and the description more in depth. # + version = "0.3.3" + s.name = "Caravel" - s.version = "0.3.2" + s.version = version s.summary = "A Swift event bus for UIWebView and JS" s.description = <<-DESC @@ -73,7 +75,7 @@ Pod::Spec.new do |s| # Supports git, hg, bzr, svn and HTTP. # - s.source = { :git => "https://github.com/coshx/caravel.git", :tag => "v0.3.2" } + s.source = { :git => "https://github.com/coshx/caravel.git", :tag => "v#{version}" } # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # diff --git a/README.md b/README.md index 8c97c6d..346b6bc 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ - `Int` - `Double` - `String` - - `Array` - - `Object` + - `Array` (available as a `NSArray`) + - `Object` (available as a `NSDictionary`) ## Installation diff --git a/caravel/js/Gruntfile.js b/caravel/js/Gruntfile.js index 4615136..8d8000a 100644 --- a/caravel/js/Gruntfile.js +++ b/caravel/js/Gruntfile.js @@ -1,7 +1,7 @@ module.exports = function (grunt) { 'use strict'; - var version = '0.3.2'; + var version = '0.3.3'; // Project configuration grunt.initConfig({ From 3bb2e14ca00b7891757a0cdd243b120f36cf0dc2 Mon Sep 17 00:00:00 2001 From: Adrien Cadet Date: Mon, 22 Jun 2015 10:30:50 -0700 Subject: [PATCH 9/9] Updates JS file --- caravel/js/caravel.min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caravel/js/caravel.min.js b/caravel/js/caravel.min.js index 69cc9f5..e9f13a6 100644 --- a/caravel/js/caravel.min.js +++ b/caravel/js/caravel.min.js @@ -1,2 +1,2 @@ -/** Caravel 0.3.2 - https://github.com/coshx/caravel */ +/** Caravel 0.3.3 - https://github.com/coshx/caravel */ var Caravel;Caravel=function(){function Caravel(name){this.name=name,this.subscribers=[]}return Caravel["default"]=null,Caravel.buses=[],Caravel.prototype._post=function(eventName,data){var iframe,src;return iframe=document.createElement("iframe"),src="caravel://host.com?busName="+encodeURIComponent(this.name)+"&eventName="+encodeURIComponent(eventName),null!=data&&(src+=data instanceof Array||data instanceof Object?"&eventData="+encodeURIComponent(JSON.stringify(data)):"&eventData="+encodeURIComponent(data)),iframe.setAttribute("src",src),document.documentElement.appendChild(iframe),iframe.parentNode.removeChild(iframe)},Caravel.prototype.getName=function(){return this.name},Caravel.prototype.post=function(name,data){return this._post(name,data)},Caravel.prototype.register=function(name,callback){return this.subscribers.push({name:name,callback:callback})},Caravel.prototype.raise=function(name,data){var e,i,len,parsedData,ref,results;for(parsedData=data instanceof Array||data instanceof Object||"string"==typeof data||data instanceof String?data:JSON.parse(data),ref=this.subscribers,results=[],i=0,len=ref.length;len>i;i++)e=ref[i],e.name===name?results.push(e.callback(name,parsedData)):results.push(void 0);return results},Caravel.getDefault=function(){return null==Caravel["default"]&&(Caravel["default"]=new Caravel("default"),Caravel["default"].post("CaravelInit")),Caravel["default"]},Caravel.get=function(name){var b,i,len,ref;for(ref=Caravel.buses,i=0,len=ref.length;len>i;i++)if(b=ref[i],b.getName()===name)return b;return b=new Caravel(name),Caravel.buses.push(b),b.post("CaravelInit"),b},Caravel}(); \ No newline at end of file