You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ji...@apache.org on 2017/01/24 08:18:33 UTC
[18/50] [abbrv] incubator-weex git commit: + [ios] iOS init.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
new file mode 100644
index 0000000..1ad5fcf
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
@@ -0,0 +1,91 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WXBridgeMethod;
+
+@interface WXBridgeContext : NSObject
+
+/**
+ * Create Instance Method
+ * @param instance : instance id
+ * @param template : template data
+ * @param options : parameters
+ * @param data : external data
+ **/
+- (void)createInstance:(NSString *)instance
+ template:(NSString *)temp
+ options:(NSDictionary *)options
+ data:(id)data;
+
+/**
+ * Destroy Instance Method
+ * @param instance : instance id
+ **/
+- (void)destroyInstance:(NSString *)instance;
+
+/**
+ * Refresh Instance Method
+ * @param instance : instance id
+ * @param data : external data
+ **/
+- (void)refreshInstance:(NSString *)instance
+ data:(id)data;
+
+/**
+ * Update Instacne State Method
+ * @param instance : instance id
+ * @param data : parameters
+ **/
+- (void)updateState:(NSString *)instance
+ data:(id)data;
+
+/**
+ * Execute JSFramework Script
+ * @param script : script code
+ **/
+- (void)executeJsFramework:(NSString *)script;
+
+/**
+ * Execute JS Method
+ * @param method : object of bridge method
+ **/
+- (void)executeJsMethod:(WXBridgeMethod *)method;
+
+/**
+ * Register Modules Method
+ * @param modules : module list
+ **/
+- (void)registerModules:(NSDictionary *)modules;
+
+/**
+ * Register Components Method
+ * @param components: component list
+ **/
+- (void)registerComponents:(NSArray *)components;
+
+/**
+ * Connect To WebSocket
+ * @param url : url to connect
+ **/
+- (void)connectToWebSocket:(NSURL *)url;
+
+/**
+ * Log To WebSocket
+ * @param flag : the tag to indentify
+ * @param message : message to output
+ **/
+- (void)logToWebSocket:(NSString *)flag message:(NSString *)message;
+
+/**
+ * Reset Environment
+ **/
+- (void)resetEnvironment;
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
new file mode 100644
index 0000000..ced9330
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -0,0 +1,372 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeContext.h"
+#import "WXBridgeProtocol.h"
+#import "WXJSCoreBridge.h"
+#import "WXWebSocketBridge.h"
+#import "WXLog.h"
+#import "WXUtility.h"
+#import "WXBridgeMethod.h"
+#import "WXModuleFactory.h"
+#import "WXModuleProtocol.h"
+#import "WXUtility.h"
+#import "WXSDKError.h"
+#import "WXAssert.h"
+#import "WXSDKManager.h"
+
+@interface WXBridgeContext ()
+
+@property (nonatomic, strong) id<WXBridgeProtocol> jsBridge;
+@property (nonatomic, strong) WXWebSocketBridge *socketBridge;
+@property (nonatomic, assign) BOOL debugJS;
+//store the methods which will be executed from native to js
+@property (nonatomic, strong) NSMutableDictionary *sendQueue;
+//the instance stack
+@property (nonatomic, strong) NSMutableArray *insStack;
+//identify if the JSFramework has been loaded
+@property (nonatomic) BOOL frameworkLoadFinished;
+//store some methods temporarily before JSFramework is loaded
+@property (nonatomic, strong) NSMutableArray *methodQueue;
+
+@end
+
+@implementation WXBridgeContext
+
+- (instancetype) init
+{
+ self = [super init];
+ if (self) {
+ _methodQueue = [NSMutableArray new];
+ _frameworkLoadFinished = NO;
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jsError:) name:WX_JS_ERROR_NOTIFICATION_NAME object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_JS_ERROR_NOTIFICATION_NAME object:nil];
+}
+
+- (void)jsError:(NSNotification *)note
+{
+ NSString *errorMessage = @"";
+ if (note.userInfo) {
+ errorMessage = note.userInfo[@"message"];
+ }
+
+ NSURL *url;
+ if (self.insStack.count > 0) {
+ WXSDKInstance *topInstance = [WXSDKManager instanceForID:[self.insStack firstObject]];
+ url = topInstance.scriptURL;
+ }
+
+ [WXSDKError monitorAlarm:NO errorCode:WX_ERR_JS_EXECUTE errorMessage:errorMessage withURL:url];
+}
+
+- (id<WXBridgeProtocol>)jsBridge
+{
+ WXAssertBridgeThread();
+
+ Class bridgeClass = _debugJS ? [WXWebSocketBridge class] : [WXJSCoreBridge class];
+
+ if (_jsBridge && [_jsBridge isKindOfClass:bridgeClass]) {
+ return _jsBridge;
+ }
+
+ if (_jsBridge) {
+ [_methodQueue removeAllObjects];
+ _frameworkLoadFinished = NO;
+ }
+
+ _jsBridge = _debugJS ? self.socketBridge : [[WXJSCoreBridge alloc] init];
+ __weak typeof(self) weakSelf = self;
+ [_jsBridge registerCallNative:^(NSString *instance, NSArray *tasks, NSString *callback) {
+ [weakSelf invokeNative:instance tasks:tasks callback:callback];
+ }];
+
+ return _jsBridge;
+}
+
+- (NSMutableArray *)insStack
+{
+ WXAssertBridgeThread();
+
+ if (_insStack) return _insStack;
+
+ _insStack = [NSMutableArray array];
+
+ return _insStack;
+}
+
+- (NSMutableDictionary *)sendQueue
+{
+ WXAssertBridgeThread();
+
+ if (_sendQueue) return _sendQueue;
+
+ _sendQueue = [NSMutableDictionary dictionary];
+
+ return _sendQueue;
+}
+
+#pragma mark JS Bridge Management
+
+- (void)invokeNative:(NSString *)instance tasks:(NSArray *)tasks callback:(NSString *)callback
+{
+ WXAssertBridgeThread();
+
+ if (!instance || !tasks) {
+ [WXSDKError monitorAlarm:NO errorCode:WX_ERR_JSFUNC_PARAM msg:@"JS call Native params error !"];
+ return;
+ }
+ [WXSDKError monitorAlarm:YES errorCode:WX_ERR_JSFUNC_PARAM msg:@""];
+
+ for (NSDictionary *task in tasks) {
+ WXBridgeMethod *method = [[WXBridgeMethod alloc] initWihData:task];
+ method.instance = instance;
+ [[WXSDKManager moduleMgr] dispatchMethod:method];
+ }
+
+ NSMutableArray *sendQueue = [self.sendQueue valueForKey:instance];
+ if (!sendQueue) {
+ WXLogError(@"No send queue for instance:%@", instance);
+ return;
+ }
+
+ if (callback && ![callback isEqualToString:@"-1"]) {
+ WXBridgeMethod *method = [self _methodWithCallback:callback];
+ method.instance = instance;
+ [sendQueue addObject:method];
+ }
+
+ [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+}
+
+- (void)createInstance:(NSString *)instance
+ template:(NSString *)temp
+ options:(NSDictionary *)options
+ data:(id)data
+{
+ WXAssertBridgeThread();
+ WXAssertParam(instance);
+
+ if (![self.insStack containsObject:instance]) {
+ if ([options[@"RENDER_IN_ORDER"] boolValue]) {
+ [self.insStack addObject:instance];
+ } else {
+ [self.insStack insertObject:instance atIndex:0];
+ }
+ }
+
+ //create a sendQueue bind to the current instance
+ NSMutableArray *sendQueue = [NSMutableArray array];
+ [self.sendQueue setValue:sendQueue forKey:instance];
+
+ NSArray *args = nil;
+ if (data){
+ args = @[instance, temp, options, data];
+ } else {
+ args = @[instance, temp, options];
+ }
+
+ WXSDKInstance *sdkInstance = [WXSDKManager instanceForID:instance] ;
+ [WXBridgeContext _timeSince:^() {
+ [self callJSMethod:@"createInstance" args:args];
+ WXLogInfo(@"CreateInstance Finish...%f", -[sdkInstance.renderStartDate timeIntervalSinceNow]);
+ } endBlock:^(NSTimeInterval time) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ sdkInstance.communicateTime = time;
+ });
+ }];
+}
+
+- (void)destroyInstance:(NSString *)instance
+{
+ WXAssertBridgeThread();
+ WXAssertParam(instance);
+
+ //remove instance from stack
+ if([self.insStack containsObject:instance]){
+ [self.insStack removeObject:instance];
+ }
+
+ if(self.sendQueue[instance]){
+ [self.sendQueue removeObjectForKey:instance];
+ }
+
+ [self callJSMethod:@"destroyInstance" args:@[instance]];
+}
+
+- (void)refreshInstance:(NSString *)instance
+ data:(id)data
+{
+ WXAssertBridgeThread();
+ WXAssertParam(instance);
+
+ [self callJSMethod:@"refreshInstance" args:@[instance, data]];
+}
+
+- (void)updateState:(NSString *)instance data:(id)data
+{
+ WXAssertBridgeThread();
+ WXAssertParam(instance);
+
+ //[self.jsBridge callJSMethod:@"updateState" args:@[instance, data]];
+}
+
+- (void)executeJsFramework:(NSString *)script
+{
+ WXAssertBridgeThread();
+ WXAssertParam(script);
+
+ __weak __typeof__(self) weakSelf = self;
+ [WXBridgeContext _timeSince:^() {
+ WXLogVerbose(@"JSFramework starts executing...");
+ [self.jsBridge executeJSFramework:script];
+ WXLogVerbose(@"JSFramework ends executing...");
+ if ([self.jsBridge exception]) {
+ [WXSDKError monitorAlarm:NO errorCode:WX_ERR_LOAD_JSLIB msg:@"JSFramework executes error !"];
+ }
+ else {
+ [WXSDKError monitorAlarm:YES errorCode:WX_ERR_LOAD_JSLIB msg:@""];
+
+ //the JSFramework has been load successfully.
+ weakSelf.frameworkLoadFinished = YES;
+
+ //execute methods which has been stored in methodQueue temporarily.
+ for (NSDictionary *method in _methodQueue) {
+ [self callJSMethod:method[@"method"] args:method[@"args"]];
+ }
+ [_methodQueue removeAllObjects];
+ }
+ } endBlock:^(NSTimeInterval time) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ JSLibInitTime = time;
+ });
+ }];
+}
+
+- (void)executeJsMethod:(WXBridgeMethod *)method
+{
+ WXAssertBridgeThread();
+
+ if (!method.instance) {
+ WXLogError(@"Instance doesn't exist!");
+ return;
+ }
+
+ NSMutableArray *sendQueue = self.sendQueue[method.instance];
+ if (!sendQueue) {
+ WXLogInfo(@"No send queue for instance:%@, may it has been destroyed so method:%@ is ignored", method.instance, method.method);
+ return;
+ }
+
+ [sendQueue addObject:method];
+ [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+}
+
+- (void)registerModules:(NSDictionary *)modules
+{
+ WXAssertBridgeThread();
+
+ if(!modules) return;
+
+ [self callJSMethod:@"registerModules" args:@[modules]];
+}
+
+- (void)registerComponents:(NSArray *)components
+{
+ WXAssertBridgeThread();
+
+ if(!components) return;
+
+ [self callJSMethod:@"registerComponents" args:@[components]];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+ if (self.frameworkLoadFinished) {
+ [self.jsBridge callJSMethod:method args:args];
+ }
+ else {
+ [_methodQueue addObject:@{@"method":method, @"args":args}];
+ }
+}
+
+- (void)resetEnvironment
+{
+ [_jsBridge resetEnvironment];
+}
+
+#pragma mark JS Debug Management
+
+- (void)connectToWebSocket:(NSURL *)url
+{
+ _socketBridge = [[WXWebSocketBridge alloc] initWithURL:url];
+}
+
+- (void)logToWebSocket:(NSString *)flag message:(NSString *)message
+{
+ [_socketBridge callJSMethod:@"__logger" args:@[flag, message]];
+}
+
+#pragma mark Private Mehtods
+
+- (WXBridgeMethod *)_methodWithCallback:(NSString *)callback
+{
+ WXAssertBridgeThread();
+
+ if (!callback) return nil;
+
+ NSDictionary *method = @{@"module":@"jsBridge", @"method":@"callback", @"args":@[callback]};
+
+ return [[WXBridgeMethod alloc] initWihData:method];
+}
+
+- (void)_sendQueueLoop
+{
+ WXAssertBridgeThread();
+
+ BOOL hasTask = NO;
+ NSMutableArray *methods = [NSMutableArray array];
+ NSString *execIns = nil;
+
+ for (NSString *instance in self.insStack) {
+ NSMutableArray *sendQueue = self.sendQueue[instance];
+ if(sendQueue.count > 0){
+ hasTask = YES;
+ for(WXBridgeMethod *method in sendQueue){
+ [methods addObject:[method dataDesc]];
+ }
+ [sendQueue removeAllObjects];
+ execIns = instance;
+ break;
+ }
+ }
+
+ if ([methods count] > 0 && execIns) {
+ [self callJSMethod:@"callJS" args:@[execIns, methods]];
+ }
+
+ if (hasTask) {
+ [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+ }
+}
+
++ (void)_timeSince:(void(^)())startBlock endBlock:(void(^)(NSTimeInterval))endBlock
+{
+ NSDate *startDate = [NSDate new];
+ startBlock();
+ NSDate *endDate = [NSDate new];
+ NSTimeInterval time = [endDate timeIntervalSinceDate:startDate];
+ endBlock(time);
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
new file mode 100644
index 0000000..b3c604c
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeProtocol.h"
+
+@interface WXJSCoreBridge : NSObject <WXBridgeProtocol>
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
new file mode 100644
index 0000000..0d9a73a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
@@ -0,0 +1,133 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXJSCoreBridge.h"
+#import "WXDefine.h"
+#import "WXAssert.h"
+#import "WXLog.h"
+#import "WXUtility.h"
+#import "WXSDKEngine.h"
+#import "WXSDKError.h"
+#import <sys/utsname.h>
+#import <JavaScriptCore/JavaScriptCore.h>
+
+@interface WXJSCoreBridge ()
+
+@property (nonatomic, strong) JSContext *jsContext;
+
+@end
+
+@implementation WXJSCoreBridge
+
+- (instancetype)init
+{
+ self = [super init];
+
+ if(self){
+ _jsContext = [[JSContext alloc] init];
+
+ __weak typeof(self) weakSelf = self;
+
+ NSDictionary *data = [WXUtility getEnvironment];
+ _jsContext[@"WXEnvironment"] = data;
+
+ _jsContext[@"setTimeout"] = ^(JSValue* function, JSValue* timeout) {
+ [weakSelf performSelector: @selector(triggerTimeout:) withObject:^() {
+ [function callWithArguments:@[]];
+ } afterDelay:[timeout toDouble] / 1000];
+ };
+
+ _jsContext[@"nativeLog"] = ^() {
+ static NSDictionary *levelMap;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ levelMap = @{
+ @"__ERROR":@(WXLogFlagError),
+ @"__WARN": @(WXLogFlagWarning),
+ @"__INFO": @(WXLogFlagInfo),
+ @"__DEBUG": @(WXLogFlagDebug),
+ @"__VERBOSE": @(WXLogFlagVerbose)
+ };
+ });
+
+ NSMutableString *string = [NSMutableString string];
+ [string appendString:@"jsLog: "];
+ NSArray *args = [JSContext currentArguments];
+
+ [args enumerateObjectsUsingBlock:^(JSValue *jsVal, NSUInteger idx, BOOL *stop) {
+ if (idx == args.count - 1) {
+ NSNumber *flag = levelMap[[jsVal toString]];
+ if (flag) {
+ WX_LOG([flag unsignedIntegerValue], @"%@", string);
+ } else {
+ [string appendFormat:@"%@ ", jsVal];
+ WXLogInfo(@"%@", string);
+ }
+ }
+ [string appendFormat:@"%@ ", jsVal ];
+ }];
+ };
+
+ _jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){
+ context.exception = exception;
+ NSString *message = [NSString stringWithFormat:@"[%@:%@:%@] %@\n%@", exception[@"sourceURL"], exception[@"line"], exception[@"column"], exception, [exception[@"stack"] toObject]];
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:WX_JS_ERROR_NOTIFICATION_NAME object:weakSelf userInfo:message ? @{@"message":message} : nil];
+ };
+ }
+ return self;
+}
+
+#pragma mark - WXBridgeProtocol
+
+- (void)executeJSFramework:(NSString *)frameworkScript
+{
+ WXAssertParam(frameworkScript);
+
+ [_jsContext evaluateScript:frameworkScript];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+ WXLogVerbose(@"Calling JS... method:%@, args:%@", method, args);
+
+ [[_jsContext globalObject] invokeMethod:method withArguments:args];
+}
+
+- (void)registerCallNative:(WXJSCallNative)callNative
+{
+ void (^callNativeBlock)(JSValue *, JSValue *, JSValue *) = ^(JSValue *instance, JSValue *tasks, JSValue *callback){
+ NSString *instanceId = [instance toString];
+ NSArray *tasksArray = [tasks toArray];
+ NSString *callbackId = [callback toString];
+ WXLogVerbose(@"Calling native... instance:%@, tasks:%@, callback:%@", instanceId, tasksArray, callbackId);
+ callNative(instanceId, tasksArray, callbackId);
+ };
+
+ _jsContext[@"callNative"] = callNativeBlock;
+}
+
+- (JSValue*)exception
+{
+ return _jsContext.exception;
+}
+
+- (void)resetEnvironment
+{
+ NSDictionary *data = [WXUtility getEnvironment];
+ _jsContext[@"WXEnvironment"] = data;
+}
+
+#pragma mark - Private
+
+- (void)triggerTimeout:(void(^)())block
+{
+ block();
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
new file mode 100644
index 0000000..116c3c4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
@@ -0,0 +1,15 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeProtocol.h"
+
+@interface WXWebSocketBridge : NSObject <WXBridgeProtocol>
+
+- (instancetype)initWithURL:(NSURL *) URL;
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
new file mode 100644
index 0000000..2059909
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
@@ -0,0 +1,203 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXWebSocketBridge.h"
+#import "SRWebSocket.h"
+#import "WXSDKManager.h"
+#import "WXUtility.h"
+#import "WXLog.h"
+
+/**
+ * call format:
+ * {
+ * id:1234,
+ * method:(__logger/__hotReload/__inspector/evalFramework...),
+ * arguments:[arg1,arg2,..],
+ * }
+ *
+ * callback format:
+ * {
+ * callbackID:1234,(same as call id)
+ * result:{a:1,b:2}
+ * }
+ */
+@interface WXWebSocketBridge()<SRWebSocketDelegate>
+
+@end
+
+@implementation WXWebSocketBridge
+{
+ BOOL _isConnect;
+ SRWebSocket *_webSocket;
+ NSMutableArray *_msgAry;
+ WXJSCallNative _nativeCallBlock;
+ NSThread *_curThread;
+}
+
+- (void)dealloc
+{
+ _nativeCallBlock = nil;
+ [self _disconnect];
+}
+
+- (instancetype)initWithURL:(NSURL *) URL
+{
+ self = [super init];
+
+ _isConnect = NO;
+ _curThread = [NSThread currentThread];
+
+ [self _connect:URL];
+
+ return self;
+}
+
+- (void)_initEnvironment
+{
+ [self callJSMethod:@"setEnvironment" args:@[[WXUtility getEnvironment]]];
+}
+
+- (void)_disconnect
+{
+ _msgAry = nil;
+ _isConnect = NO;
+ _webSocket.delegate = nil;
+ [_webSocket close];
+ _webSocket = nil;
+}
+
+- (void)_connect:(NSURL *)URL
+{
+ _msgAry = nil;
+ _msgAry = [NSMutableArray array];
+ _webSocket.delegate = nil;
+ [_webSocket close];
+
+ _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:URL]];
+ _webSocket.delegate = self;
+
+ [_webSocket open];
+}
+
+-(void)_executionMsgAry
+{
+ if (!_isConnect) return;
+
+ for (NSString *msg in _msgAry) {
+ [_webSocket send:msg];
+ }
+ [_msgAry removeAllObjects];
+}
+
+-(void)_evaluateNative:(NSString *)data
+{
+ NSDictionary *dict = [WXUtility objectFromJSON:data];
+ NSString *method = [dict objectForKey:@"method"];
+ NSArray *args = [dict objectForKey:@"arguments"];
+
+ if ([method isEqualToString:@"callNative"]) {
+ // call native
+ NSString *instanceId = args[0];
+ NSArray *methods = args[1];
+ NSString *callbackId = args[2];
+
+ // params parse
+ if(!methods || methods.count <= 0){
+ return;
+ }
+ //call native
+ WXLogVerbose(@"Calling native... instancdId:%@, methods:%@, callbackId:%@", instanceId, [WXUtility JSONString:methods], callbackId);
+ _nativeCallBlock(instanceId, methods, callbackId);
+ } else if ([method isEqualToString:@"setLogLevel"]) {
+ NSString *levelString = [args firstObject];
+ [WXLog setLogLevelString:levelString];
+ }
+}
+
+#pragma mark - WXBridgeProtocol
+
+- (void)executeJSFramework:(NSString *)frameworkScript
+{
+ [self callJSMethod:@"evalFramework" args:@[frameworkScript]];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+ if (![method isEqualToString:@"__logger"]) {
+ // prevent recursion
+ WXLogVerbose(@"Calling JS... method:%@, args:%@", method, [WXUtility JSONString:args]);
+ }
+
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+ [dict setObject:method forKey:@"method"];
+ [dict setObject:args forKey:@"arguments"];
+
+ [_msgAry addObject:[WXUtility JSONString:dict]];
+ [self _executionMsgAry];
+}
+
+- (void)registerCallNative:(WXJSCallNative)callNative
+{
+ _nativeCallBlock = callNative;
+}
+
+- (JSValue*) exception
+{
+ return nil;
+}
+
+- (void)resetEnvironment
+{
+ [self _initEnvironment];
+}
+
+- (void)executeBridgeThead:(dispatch_block_t)block
+{
+ if([NSThread currentThread] == _curThread){
+ block();
+ } else {
+ [self performSelector:@selector(executeBridgeThead:)
+ onThread:_curThread
+ withObject:[block copy]
+ waitUntilDone:NO];
+ }
+}
+
+#pragma mark - SRWebSocketDelegate
+
+- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
+{
+ WXLogWarning(@"Websocket Connected:%@", webSocket.url);
+ _isConnect = YES;
+ [self _initEnvironment];
+ __weak typeof(self) weakSelf = self;
+ [self executeBridgeThead:^() {
+ [weakSelf _executionMsgAry];
+ }];
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
+{
+ WXLogError(@":( Websocket Failed With Error %@", error);
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
+{
+ __weak typeof(self) weakSelf = self;
+ [self executeBridgeThead:^() {
+ [weakSelf _evaluateNative:message];
+ }];
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
+{
+ WXLogInfo(@"Websocket closed with code: %ld, reason:%@, wasClean: %d", (long)code, reason, wasClean);
+ _isConnect = NO;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
new file mode 100644
index 0000000..5ebf7a0
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXAComponent : WXComponent <UIGestureRecognizerDelegate>
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
new file mode 100644
index 0000000..c916b0d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
@@ -0,0 +1,75 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXAComponent.h"
+#import "WXNavigationProtocol.h"
+#import "WXHandlerFactory.h"
+#import "WXLog.h"
+#import "WXComponent+Events.h"
+
+@interface WXAComponent()
+
+@property (nonatomic, strong) UITapGestureRecognizer *tap;
+@property (nonatomic, strong) NSString *href;
+
+@end
+
+@implementation WXAComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+ if (self) {
+ _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openURL)];
+ _tap.delegate = self;
+ if (attributes[@"href"]) {
+ _href = attributes[@"href"];
+ }
+ }
+ return self;
+}
+
+- (void)viewDidLoad
+{
+ [self.view addGestureRecognizer:_tap];
+}
+
+- (void)openURL
+{
+ if (_href && [_href length] > 0) {
+ id<WXNavigationProtocol> navigationHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXNavigationProtocol)];
+ if ([navigationHandler respondsToSelector:@selector(pushViewControllerWithParam:
+ completion:
+ withContainer:)]) {
+ __weak typeof(self) weexSelf = self;
+ [navigationHandler pushViewControllerWithParam:@{@"url":_href} completion:^(NSString *code, NSDictionary *responseData) {
+ WXLogVerbose(@"Push success -> %@", weexSelf.href);
+ } withContainer:self.weexInstance.viewController];
+ } else {
+ WXLogError(@"Event handler of class %@ does not respond to pushViewControllerWithParam", NSStringFromClass([navigationHandler class]));
+ }
+ }
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
+{
+ if (gestureRecognizer == _tap) return YES;
+
+ if (otherGestureRecognizer == _tap) return YES;
+
+ return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+ if (attributes[@""]) {
+ _href = attributes[@"href"];
+ }
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
new file mode 100644
index 0000000..d016117
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
@@ -0,0 +1,18 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+@class WXListComponent;
+
+@interface WXCellComponent : WXComponent
+
+@property (nonatomic, strong) NSIndexPath *indexPath;
+@property (nonatomic, strong) NSString *scope;
+@property (nonatomic, weak) WXListComponent *list;
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
new file mode 100644
index 0000000..02a7e84
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
@@ -0,0 +1,93 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXSDKInstance.h"
+#import "WXLog.h"
+#import "WXCellComponent.h"
+#import "WXListComponent.h"
+#import "WXComponent_internal.h"
+
+@implementation WXCellComponent
+{
+ NSIndexPath *_indexPathBeforeMove;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+
+ if (self) {
+ _async = YES;
+ _lazyCreateView = YES;
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+
+}
+
+- (void)layoutDidFinish
+{
+ [self.list cellDidLayout:self];
+}
+
+- (WXDisplayCompeletionBlock)displayCompeletionBlock
+{
+ return ^(CALayer *layer, BOOL finished) {
+ if ([super displayCompeletionBlock]) {
+ [super displayCompeletionBlock](layer, finished);
+ [self.list cellDidRendered:self];
+ }
+ };
+}
+
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+ _indexPathBeforeMove = self.indexPath;
+ [super _moveToSupercomponent:newSupercomponent atIndex:index];
+}
+
+- (void)moveToSuperview:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+ if (newSupercomponent == self.list) {
+ [self.list cell:self didMoveFromIndexPath:_indexPathBeforeMove toIndexPath:_indexPath];
+ } else {
+ [super moveToSuperview:newSupercomponent atIndex:index];
+ }
+}
+
+- (void)_removeFromSupercomponent
+{
+ [super _removeFromSupercomponent];
+
+ [self.list cellWillRemove:self];
+}
+
+- (void)removeFromSuperview
+{
+ [self.list cellDidRemove:self];
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+ if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) && self.list) {
+ self.cssNode->style.dimensions[CSS_WIDTH] = self.list.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+ }
+
+ if ([self needsLayout]) {
+ layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+// print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
+ }
+
+ [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+}
+@end
+
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
new file mode 100644
index 0000000..4d1ecdb
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -0,0 +1,163 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXScrollerProtocol.h"
+#import "WXComponent.h"
+#import "WXConvert.h"
+@class WXTouchGestureRecognizer;
+@class WXThreadSafeCounter;
+
+
+/**
+ * The following variables and methods are used in Weex INTERNAL logic.
+ * @warning These variables and methods must never be called or overridden.
+ */
+@interface WXComponent ()
+{
+@package
+ NSString *_type;
+ /**
+ * Layout
+ */
+ css_node_t *_cssNode;
+ BOOL _isLayoutDirty;
+ CGRect _calculatedFrame;
+ CGPoint _absolutePosition;
+ WXPositionType _positionType;
+
+ /**
+ * View
+ */
+ UIColor *_backgroundColor;
+ WXClipType _clipToBounds;
+ UIView *_view;
+ CGFloat _opacity;
+ WXVisibility _visibility;
+
+ /**
+ * Events
+ */
+ BOOL _appearEvent;
+ BOOL _disappearEvent;
+ UITapGestureRecognizer *_tapGesture;
+ NSMutableArray *_swipeGestures;
+ UILongPressGestureRecognizer *_longPressGesture;
+ UIPanGestureRecognizer *_panGesture;
+ BOOL _listenPanStart;
+ BOOL _listenPanMove;
+ BOOL _listenPanEnd;
+ WXTouchGestureRecognizer* _touchGesture;
+
+ /**
+ * Display
+ */
+ CALayer *_layer;
+ BOOL _composite;
+ BOOL _compositingChild;
+ WXThreadSafeCounter *_displayCounter;
+
+ UIColor *_borderTopColor;
+ UIColor *_borderRightColor;
+ UIColor *_borderLeftColor;
+ UIColor *_borderBottomColor;
+
+ CGFloat _borderTopWidth;
+ CGFloat _borderRightWidth;
+ CGFloat _borderLeftWidth;
+ CGFloat _borderBottomWidth;
+
+ CGFloat _borderTopLeftRadius;
+ CGFloat _borderTopRightRadius;
+ CGFloat _borderBottomLeftRadius;
+ CGFloat _borderBottomRightRadius;
+
+ WXBorderStyle _borderTopStyle;
+ WXBorderStyle _borderRightStyle;
+ WXBorderStyle _borderBottomStyle;
+ WXBorderStyle _borderLeftStyle;
+
+
+ BOOL _isFixed;
+ BOOL _async;
+ BOOL _isNeedJoinLayoutSystem;
+ BOOL _lazyCreateView;
+
+ NSString *_transform;
+ NSString *_transformOrigin;
+}
+
+///--------------------------------------
+/// @name Package Internal Methods
+///--------------------------------------
+
+- (void)_layoutDidFinish;
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
+ gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents;
+
+
+- (void)_willDisplayLayer:(CALayer *)layer;
+
+- (void)_unloadView;
+
+- (id<WXScrollerProtocol>)ancestorScroller;
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index;
+- (void)_removeFromSupercomponent;
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index;
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles;
+- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes;
+- (void)_updateStylesOnMainThread:(NSDictionary *)styles;
+- (void)_updateAttributesOnMainThread:(NSDictionary *)attributes;
+
+- (void)_addEventOnComponentThread:(NSString *)eventName;
+- (void)_removeEventOnComponentThread:(NSString *)eventName;
+- (void)_addEventOnMainThread:(NSString *)eventName;
+- (void)_removeEventOnMainThread:(NSString *)eventName;
+
+///--------------------------------------
+/// @name Protected Methods
+///--------------------------------------
+
+- (BOOL)_needsDrawBorder;
+
+- (void)_drawBorderWithContext:(CGContextRef)context size:(CGSize)size;
+
+- (void)_calculatedFrameDidChange;
+
+- (NSUInteger)_childrenCountForLayout;
+
+- (void)_fillAbsolutePositions;
+
+///--------------------------------------
+/// @name Private Methods
+///--------------------------------------
+
+- (void)_initCSSNodeWithStyles:(NSDictionary *)styles;
+
+- (void)_updateCSSNodeStyles:(NSDictionary *)styles;
+
+- (void)_recomputeCSSNodeChildren;
+
+- (void)_recomputeBorderRadius;
+
+- (void)_handleBorders:(NSDictionary *)styles isUpdating:(BOOL)updating;
+
+- (void)_initViewPropertyWithStyles:(NSDictionary *)styles;
+
+- (void)_updateViewStyles:(NSDictionary *)styles;
+
+- (void)_initEvents:(NSArray *)events;
+
+- (void)_removeAllEvents;
+
+- (void)_setupNavBarWithStyles:(NSMutableDictionary *)styles attributes:(NSMutableDictionary *)attributes;
+
+- (void)_updateNavBarAttributes:(NSDictionary *)attributes;
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
new file mode 100644
index 0000000..677eae2
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXDivComponent : WXComponent
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
new file mode 100644
index 0000000..c07f1c4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
@@ -0,0 +1,16 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXDivComponent.h"
+
+@interface WXDivComponent ()
+@end
+
+@implementation WXDivComponent
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
new file mode 100644
index 0000000..9e28ece
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
@@ -0,0 +1,15 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXEmbedComponent : WXComponent
+
+- (void)refreshWeex;
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
new file mode 100644
index 0000000..5b70f03
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
@@ -0,0 +1,175 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXEmbedComponent.h"
+#import "WXComponent_internal.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent+Navigation.h"
+#import "WXSDKInstance.h"
+#import "WXConvert.h"
+
+@interface WXEmbedComponent ()
+
+@property (nonatomic, strong) WXSDKInstance *embedInstance;
+@property (nonatomic, strong) UIView *embedView;
+@property (nonatomic, assign) BOOL renderFinished;
+@property (nonatomic, assign) WXVisibility visible;
+@property (nonatomic, strong) NSURL *sourceURL;
+
+@end
+
+@implementation WXEmbedComponent
+
+#pragma mark Life Cycle
+
+- (void)dealloc
+{
+ if (self.weexInstance) {
+ [self.weexInstance removeObserver:self forKeyPath:@"state"];
+ }
+
+ if (self.embedInstance) {
+ [self.embedInstance destroyInstance];
+ }
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+ _sourceURL = [NSURL URLWithString: attributes[@"src"]];
+ _visible = [WXConvert WXVisibility:styles[@"visibility"]];
+
+ [self.weexInstance addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
+ }
+
+ return self;
+}
+
+- (void)viewDidLoad {
+
+ [super viewDidLoad];
+
+ [self _layoutEmbedView];
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+ [super updateStyles:styles];
+
+ if (styles[@"visibility"]) {
+ WXVisibility visible = [WXConvert WXVisibility:styles[@"visibility"]];
+ if (_visible != visible) {
+ _visible = visible;
+ [self _layoutEmbedView];
+ }
+ }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+ [super updateAttributes:attributes];
+
+ if (attributes[@"src"]) {
+ NSURL *sourceURL = [NSURL URLWithString:attributes[@"src"]];
+ if (!sourceURL|| ![[sourceURL absoluteString] isEqualToString:[_sourceURL absoluteString]]) {
+ _sourceURL = sourceURL;
+ [self _layoutEmbedView];
+ }
+ }
+}
+
+- (void)refreshWeex
+{
+ [self _renderWithURL:_sourceURL];
+}
+
+- (void)_layoutEmbedView
+{
+ if (_visible == WXVisibilityShow) {
+ if (!_renderFinished && !CGRectEqualToRect(CGRectZero, self.calculatedFrame)) {
+ [self _renderWithURL:_sourceURL];
+ }
+ [self _updateState:WeexInstanceAppear];
+ }
+ else {
+ [self _updateState:WeexInstanceDisappear];
+ }
+}
+
+- (void)_renderWithURL:(NSURL *)sourceURL
+{
+ if (!sourceURL || [[sourceURL absoluteString] length] == 0) {
+ return;
+ }
+
+ [_embedInstance destroyInstance];
+ _embedInstance = [[WXSDKInstance alloc] init];
+ _embedInstance.parentInstance = self.weexInstance;
+ _embedInstance.parentNodeRef = self.ref;
+ _embedInstance.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height);
+ _embedInstance.pageName = [sourceURL absoluteString];
+ _embedInstance.pageObject = self.weexInstance.viewController;
+ _embedInstance.viewController = self.weexInstance.viewController;
+
+ NSString *newURL = nil;
+
+ if ([sourceURL.absoluteString rangeOfString:@"?"].location != NSNotFound) {
+ newURL = [NSString stringWithFormat:@"%@&random=%d", sourceURL.absoluteString, arc4random()];
+ }
+ else {
+ newURL = [NSString stringWithFormat:@"%@?random=%d", sourceURL.absoluteString, arc4random()];
+ }
+
+ [_embedInstance renderWithURL:[NSURL URLWithString:newURL] options:@{@"bundleUrl":[sourceURL absoluteString]} data:nil];
+
+ __weak typeof(self) weakSelf = self;
+ _embedInstance.onCreate = ^(UIView *view) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [weakSelf.embedView removeFromSuperview];
+ weakSelf.embedView = view;
+ weakSelf.renderFinished = YES;
+ [weakSelf.view addSubview:weakSelf.embedView];
+ });
+ };
+}
+
+- (void)_updateState:(WXState)state
+{
+ if (!_embedInstance) {
+ return;
+ }
+
+ _embedInstance.state = state;
+
+ if (state == WeexInstanceAppear || state == WeexInstanceForeground )
+ {
+ [self setNavigationWithStyles:self.embedInstance.naviBarStyles];
+ }
+}
+
+-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+ if ([keyPath isEqualToString:@"state"]) {
+ WXState state = [change[@"new"] longValue];
+ if (_visible == WXVisibilityHidden) {
+ switch (state) {
+ case WeexInstanceBackground:
+ [self _updateState:WeexInstanceBackground];
+ break;
+ default:
+ [self _updateState:WeexInstanceDisappear];
+ break;
+ }
+ }
+ else {
+ [self _updateState:state];
+ }
+ }
+}
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
new file mode 100644
index 0000000..749bd17
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXImageComponent : WXComponent
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
new file mode 100644
index 0000000..57b373b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
@@ -0,0 +1,234 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXImageComponent.h"
+#import "WXHandlerFactory.h"
+#import "WXComponent_internal.h"
+#import "WXImgLoaderProtocol.h"
+#import "WXLayer.h"
+#import "WXType.h"
+#import "WXConvert.h"
+
+@interface WXImageView : UIImageView
+
+@end
+
+@implementation WXImageView
+
++ (Class)layerClass
+{
+ return [WXLayer class];
+}
+
+@end
+
+static dispatch_queue_t WXImageUpdateQueue;
+
+@interface WXImageComponent ()
+
+@property (nonatomic, strong) NSString *imageSrc;
+@property (nonatomic, assign) UIViewContentMode resizeMode;
+@property (nonatomic, assign) WXImageQuality imageQuality;
+@property (nonatomic, assign) WXImageSharp imageSharp;
+@property (nonatomic, strong) UIImage *image;
+@property (nonatomic, strong) id<WXImageOperationProtocol> imageOperation;
+
+@end
+
+@implementation WXImageComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+ _async = YES;
+ if (!WXImageUpdateQueue) {
+ WXImageUpdateQueue = dispatch_queue_create("com.taobao.weex.ImageUpdateQueue", DISPATCH_QUEUE_SERIAL);
+ }
+
+ _imageSrc = [WXConvert NSString:attributes[@"src"]];
+ _resizeMode = [WXConvert UIViewContentMode:attributes[@"resize"]];
+ _imageQuality = [WXConvert WXImageQuality:styles[@"quality"]];
+ _imageSharp = [WXConvert WXImageSharp:styles[@"sharpen"]];
+ }
+
+ return self;
+}
+
+- (UIView *)loadView
+{
+ return [[WXImageView alloc] init];
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+ if (styles[@"quality"]) {
+ _imageQuality = [WXConvert WXImageQuality:styles[@"quality"]];
+ [self updateImage];
+ }
+
+ if (styles[@"sharpen"]) {
+ _imageSharp = [WXConvert WXImageSharp:styles[@"sharpen"]];
+ [self updateImage];
+ }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+ if (attributes[@"src"]) {
+ _imageSrc = [WXConvert NSString:attributes[@"src"]];
+ [self updateImage];
+ }
+
+ if (attributes[@"resize"]) {
+ _resizeMode = [WXConvert UIViewContentMode:attributes[@"resize"]];
+ self.view.contentMode = _resizeMode;
+ }
+}
+
+- (void)viewDidLoad
+{
+ UIImageView *imageView = (UIImageView *)self.view;
+ imageView.contentMode = _resizeMode;
+ imageView.userInteractionEnabled = YES;
+ imageView.clipsToBounds = YES;
+ imageView.exclusiveTouch = YES;
+
+ if (_image) {
+ imageView.image = _image;
+ _image = nil;
+ } else {
+ [self updateImage];
+ }
+}
+
+- (WXDisplayBlock)displayBlock
+{
+ if ([self isViewLoaded]) {
+ // if has a image view, image is setted by image view, displayBlock is not needed
+ return nil;
+ }
+
+ __weak typeof(self) weakSelf = self;
+ return ^UIImage *(CGRect bounds, BOOL(^isCancelled)(void)) {
+ if (isCancelled()) {
+ return nil;
+ }
+
+ if (!weakSelf.image) {
+ [weakSelf updateImage];
+ return nil;
+ }
+
+ if (isCancelled && isCancelled()) {
+ return nil;
+ }
+
+ UIGraphicsBeginImageContextWithOptions(bounds.size, self.layer.opaque, 1.0);
+
+ [weakSelf.image drawInRect:bounds];
+
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ return image;
+ };
+}
+
+- (void)viewWillUnload
+{
+ [super viewWillUnload];
+ [self cancelImage];
+ _image = nil;
+}
+
+- (void)setImageSrc:(NSString*)src
+{
+ if (![src isEqualToString:_imageSrc]) {
+ _imageSrc = src;
+ [self updateImage];
+ }
+}
+
+- (void)updateImage
+{
+ __weak typeof(self) weakSelf = self;
+ dispatch_async(WXImageUpdateQueue, ^{
+ [self cancelImage];
+
+ if (CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
+ return;
+ }
+
+ if (weakSelf.imageSrc) {
+ NSString *imageSrc = weakSelf.imageSrc;
+ NSDictionary *userInfo = @{@"imageQuality":@(weakSelf.imageQuality), @"imageSharp":@(weakSelf.imageSharp)};
+ WXLogVerbose(@"Updating image, component:%@, image source:%@, userInfo:%@", self.ref, imageSrc, userInfo);
+ weakSelf.imageOperation = [[weakSelf imageLoader] downloadImageWithURL:imageSrc imageFrame:weakSelf.calculatedFrame userInfo:userInfo completed:^(UIImage *image, NSError *error, BOOL finished) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ __strong typeof(self) strongSelf = weakSelf;
+ if (error) {
+ WXLogError(@"Error downloading image:%@, detail:%@", imageSrc, [error localizedDescription]);
+ if ([strongSelf isViewLoaded]) {
+ ((UIImageView *)(strongSelf.view)).image = nil;
+ }
+ return ;
+ }
+
+ if (![imageSrc isEqualToString:strongSelf.imageSrc]) {
+ return ;
+ }
+ if ([strongSelf isViewLoaded]) {
+ ((UIImageView *)strongSelf.view).image = image;
+ } else {
+ //TODO: Need this?
+ strongSelf.image = image;
+ [strongSelf setNeedsDisplay];
+ }
+ });
+ }];
+ } else {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ self.layer.contents = nil;
+ });
+ }
+ });
+}
+
+- (void)cancelImage
+{
+ [_imageOperation cancel];
+ _imageOperation = nil;
+}
+
+- (id<WXImgLoaderProtocol>)imageLoader
+{
+ static id<WXImgLoaderProtocol> imageLoader;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ imageLoader = [WXHandlerFactory handlerForProtocol:@protocol(WXImgLoaderProtocol)];
+ });
+ return imageLoader;
+}
+
+- (BOOL)_needsDrawBorder
+{
+ return NO;
+}
+
+#ifdef UITEST
+- (NSString *)description
+{
+ NSString *superDescription = super.description;
+ NSRange semicolonRange = [superDescription rangeOfString:@";"];
+ NSString *replacement = [NSString stringWithFormat:@"; imageSrc: %@; imageQuality: %@; imageSharp: %@; ",_imageSrc,_imageQuality,_imageSharp];
+ return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
+}
+#endif
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
new file mode 100644
index 0000000..faeae40
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
@@ -0,0 +1,33 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+typedef enum
+{
+ WXPointIndicatorAlignCenter, // point indicator align center
+ WXPointIndicatorAlignLeft, // point indicator align left
+ WXPointIndicatorAlignRight, // point indicator align right
+} WXPointIndicatorAlignStyle;
+
+@interface WXIndicatorView : UIView
+
+@property (nonatomic, assign) NSInteger pointCount; // total count point of point indicator
+@property (nonatomic, assign) NSInteger currentPoint; // current light index of point at point indicator
+@property (nonatomic, strong) UIColor *pointColor; // normal point color of point indicator
+@property (nonatomic, strong) UIColor *lightColor; // highlight point color of point indicator
+@property (nonatomic, assign) WXPointIndicatorAlignStyle alignStyle; //align style of point indicator
+@property (nonatomic, assign) CGFloat pointSize; // point size of point indicator
+@property (nonatomic, assign) CGFloat pointSpace; // point space of point indicator
+
+@end
+
+
+@interface WXIndicatorComponent : WXComponent
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
new file mode 100644
index 0000000..c903c2a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
@@ -0,0 +1,186 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXIndicatorComponent.h"
+#import "WXSliderComponent.h"
+#import "WXConvert.h"
+
+@implementation WXIndicatorView
+
+@synthesize pointCount = _pointCount;
+@synthesize currentPoint = _currentPoint;
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ self.pointSpace = 5.0f;
+ }
+ return self;
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+ [super setBackgroundColor:backgroundColor];
+}
+
+- (void)setPointCount:(NSInteger)pointCount
+{
+ _pointCount = pointCount;
+ [self setNeedsDisplay];
+}
+
+- (void)setCurrentPoint:(NSInteger)currentPoint
+{
+ if (currentPoint < _pointCount && currentPoint >= 0) {
+ _currentPoint = currentPoint;
+ [self setNeedsDisplay];
+ }
+}
+
+- (void)setPointSize:(CGFloat)pointSize
+{
+ _pointSize = pointSize;
+ [self setNeedsDisplay];
+}
+
+- (void)setPointSpace:(CGFloat)pointSpace
+{
+ _pointSpace = pointSpace;
+ [self setNeedsDisplay];
+}
+
+- (void)drawRect:(CGRect)rect
+{
+ if (self.alignStyle == WXPointIndicatorAlignCenter) {
+ CGFloat startX = 0.0f, centerX = self.frame.size.width / 2.0f;
+ if (self.pointCount % 2) {
+ startX = centerX - (self.pointSize + self.pointSpace) * (int)(self.pointCount / 2.0f) - self.pointSize / 2.0f;
+ } else {
+ startX = centerX - (self.pointSize + self.pointSpace) * (int)(self.pointCount / 2.0f) + self.pointSpace / 2.0f;
+ }
+
+ CGContextRef context=UIGraphicsGetCurrentContext();
+ CGContextBeginPath(context);
+
+ for (int i = 0; i < self.pointCount; i++) {
+ if (self.currentPoint == i) {
+ CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ } else {
+ CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ }
+ startX += self.pointSize + self.pointSpace;
+ }
+ } else if (self.alignStyle == WXPointIndicatorAlignRight) {
+ CGFloat startX = self.frame.size.width - self.pointSize * self.pointCount - self.pointSpace * (self.pointCount - 1) - 10; //10 right margin
+ CGContextRef context=UIGraphicsGetCurrentContext();
+ CGContextBeginPath(context);
+
+ for(int i = 0; i < self.pointCount; i++) {
+ if (self.currentPoint == i) {
+ CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ } else {
+ CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ }
+ startX += self.pointSize + self.pointSpace;
+ }
+ } else if (self.alignStyle == WXPointIndicatorAlignLeft) {
+ CGFloat startX = 10.0f; //10 left margin
+ CGContextRef context=UIGraphicsGetCurrentContext();
+ CGContextBeginPath(context);
+ for(int i = 0; i < self.pointCount; i++) {
+ if (self.currentPoint == i) {
+ CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ } else {
+ CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+ CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+ CGContextFillPath(context);
+ }
+ startX += self.pointSize + self.pointSpace;
+ }
+ }
+}
+
+@end
+
+@interface WXIndicatorComponent()
+
+@property (nonatomic, strong) WXIndicatorView *indicatorView;
+
+@property (nonatomic, strong) UIColor *itemColor;
+@property (nonatomic, strong) UIColor *itemSelectedColor;
+@property (nonatomic) CGFloat itemSize;
+
+@end
+
+@implementation WXIndicatorComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+ _itemColor = styles[@"itemColor"] ? [WXConvert UIColor:styles[@"itemColor"]]:[UIColor colorWithRed:0xff/255.0f green:0xff/255.0f blue:0xff/255.0f alpha:0.5f];
+ _itemSelectedColor = styles[@"itemSelectedColor"] ? [WXConvert UIColor:styles[@"itemSelectedColor"]]:[UIColor colorWithRed:0xff/255.0f green:0xd5/255.0f blue:0x45/255.0f alpha:1.0f];
+ _itemSize = styles[@"itemSize"] ? [WXConvert CGFloat:styles[@"itemSize"]]: 5.0f;
+ }
+ return self;
+}
+
+- (UIView *)loadView
+{
+ return [[WXIndicatorView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ _indicatorView = (WXIndicatorView *)self.view;
+ _indicatorView.alignStyle = WXPointIndicatorAlignCenter;
+ _indicatorView.userInteractionEnabled = NO;
+ _indicatorView.pointColor = _itemColor;
+ _indicatorView.lightColor = _itemSelectedColor;
+ _indicatorView.pointSize = _itemSize;
+
+ WXComponent *parent = self.supercomponent;
+ if([parent isKindOfClass:[WXSliderComponent class]]) {
+ WXSliderComponent *parentSlider = (WXSliderComponent *)parent;
+ [parentSlider setIndicatorView:_indicatorView];
+ }
+ else {
+ NSAssert(NO, @"");
+ }
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+ if (styles[@"itemColor"]) {
+ _itemColor = [WXConvert UIColor:styles[@"itemColor"]];
+ [_indicatorView setPointColor:_itemColor];
+ }
+ else if (styles[@"itemSelectedColor"]) {
+ _itemSelectedColor = [WXConvert UIColor:styles[@"itemSelectedColor"]];
+ [_indicatorView setLightColor:_itemSelectedColor];
+ }
+ else if (styles[@"itemSize"]) {
+ _itemSize = [WXConvert WXPixelType:styles[@"itemSelectedColor"]];
+ [_indicatorView setPointSize:_itemSize];
+ }
+}
+
+@end
+
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
new file mode 100644
index 0000000..2a62c0b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
@@ -0,0 +1,24 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXCellComponent.h"
+#import "WXScrollerComponent.h"
+
+@interface WXListComponent : WXScrollerComponent
+
+- (void)cellWillRemove:(WXCellComponent *)cell;
+
+- (void)cellDidRemove:(WXCellComponent *)cell;
+
+- (void)cellDidLayout:(WXCellComponent *)cell;
+
+- (void)cellDidRendered:(WXCellComponent *)cell;
+
+- (void)cell:(WXCellComponent *)cell didMoveFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
new file mode 100644
index 0000000..f4fbfd9
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
@@ -0,0 +1,296 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXListComponent.h"
+#import "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "NSArray+Weex.h"
+#import "WXAssert.h"
+#import "WXUtility.h"
+#import "WXSDKInstance.h"
+
+@interface WXTableView : UITableView
+
+@end
+
+@implementation WXTableView
+
++ (BOOL) requiresConstraintBasedLayout
+{
+ return NO;
+}
+
+- (void)layoutSubviews
+{
+ [super layoutSubviews];
+ [self.wx_component layoutDidFinish];
+}
+
+@end
+
+@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate>
+
+@end
+
+@implementation WXListComponent
+{
+ __weak UITableView * _tableView;
+ NSMutableArray * _cellComponents;
+ NSMutableArray * _completedCells;
+ NSUInteger _previousLoadMoreRowNumber;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+
+ _cellComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+ _completedCells = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+ }
+
+ return self;
+}
+
+- (UIView *)loadView
+{
+ return [[WXTableView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ _tableView = (UITableView *)self.view;
+ _tableView.allowsSelection = NO;
+ _tableView.allowsMultipleSelection = NO;
+ _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+ _tableView.delegate = self;
+ _tableView.dataSource = self;
+ _tableView.userInteractionEnabled = YES;
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+ // Do Nothing
+}
+
+- (NSUInteger)childrenCountForScrollerLayout
+{
+ return [super childrenCountForScrollerLayout] - _cellComponents.count;
+}
+
+#pragma mark - Inheritance
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+ [super _insertSubcomponent:subcomponent atIndex:index];
+
+ if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
+ WXCellComponent *cellComponent = (WXCellComponent *)subcomponent;
+ cellComponent.list = self;
+
+ NSInteger insertIndex = index;
+ for (int j = 0; j <= index && j < self.subcomponents.count; j++) {
+ WXComponent *child = self.subcomponents[j];
+ if (![child isKindOfClass:[WXCellComponent class]]) {
+ insertIndex--;
+ }
+ }
+
+ cellComponent.indexPath = [NSIndexPath indexPathForRow:insertIndex inSection:0];
+ [_cellComponents insertObject:subcomponent atIndex:insertIndex];
+ }
+}
+
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+ //List View insert cell's view by - cellForRowAtIndexPath:, so here will not insert cell's view again
+ if (![subcomponent isKindOfClass:[WXCellComponent class]]) {
+ [super insertSubview:subcomponent atIndex:index];
+ }
+}
+
+- (void)cellWillRemove:(WXCellComponent *)cell
+{
+ WXAssertComponentThread();
+
+ [_cellComponents removeObject:cell];
+}
+
+- (void)cellDidRemove:(WXCellComponent *)cell
+{
+ WXAssertMainThread();
+
+ NSIndexPath *indexPath = cell.indexPath;
+ WXAssert(indexPath, @"Removing cell:%@ has not been inserted to cell list before", cell);
+
+ [_completedCells removeObject:cell];
+
+ [UIView performWithoutAnimation:^{
+ [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+ }];
+}
+
+- (void)cellDidLayout:(WXCellComponent *)cell
+{
+ WXAssertMainThread();
+
+ NSIndexPath *indexPath = cell.indexPath;
+ WXAssert(indexPath, @"Laid out cell:%@ has not been inserted to cell list before", cell);
+
+ if (indexPath.row == 0) {
+ cell.absolutePosition = CGPointZero;
+ } else {
+ WXCellComponent *previousCell = _cellComponents[indexPath.row - 1];
+ CGPoint previousCellPostion = previousCell.absolutePosition;
+ cell.absolutePosition = CGPointMake(previousCellPostion.x, previousCellPostion.y + previousCell.calculatedFrame.size.height);
+ }
+
+ [cell _fillAbsolutePositions];
+
+ if (![_completedCells containsObject:cell]) {
+ [_completedCells addObject:cell];
+ WXLogVerbose(@"Insert cell at row:%ld", (long)indexPath.row);
+ [UIView performWithoutAnimation:^{
+ [_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+ }];
+ } else {
+ WXLogVerbose(@"Reload cell at row:%ld", (long)indexPath.row);
+ [UIView performWithoutAnimation:^{
+ [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+ }];
+ }
+}
+
+- (void)cellDidRendered:(WXCellComponent *)cell
+{
+ WXAssertMainThread();
+
+ NSIndexPath *indexPath = cell.indexPath;
+ WXAssert(indexPath, @"Rendered cell:%@ has not been inserted to cell list before", cell);
+
+ CGRect cellRect = [_tableView rectForRowAtIndexPath:indexPath];
+ if (cellRect.origin.y + cellRect.size.height >= _tableView.frame.size.height) {
+ if (self.weexInstance.screenRenderTime == 0) {
+ self.weexInstance.screenRenderTime = [[NSDate new] timeIntervalSinceDate:self.weexInstance.renderStartDate];
+ }
+ }
+
+ if (self.weexInstance.onRenderProgress) {
+ CGRect renderRect = CGRectMake(self.absolutePosition.x + cellRect.origin.x,
+ self.absolutePosition.y + cellRect.origin.y,
+ cellRect.size.width, cellRect.size.height);
+
+ self.weexInstance.onRenderProgress(renderRect);
+ }
+
+}
+
+- (void)cell:(WXCellComponent *)cell didMoveFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
+{
+ WXAssert(fromIndexPath, @"Moved cell:%@ has not been inserted to cell list before", cell);
+
+ [UIView performWithoutAnimation:^{
+ [_tableView moveRowAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
+ }];
+}
+
+#pragma mark - TableView delegate
+
+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+
+}
+
+- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
+ if (![visibleIndexPaths containsObject:indexPath]) {
+ WXCellComponent *component = [_cellComponents wx_safeObjectAtIndex:indexPath.row];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [component _unloadView];
+ });
+ }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ WXCellComponent *cell = _cellComponents[indexPath.row];
+ return cell.calculatedFrame.size.height;
+}
+
+#pragma mark - TableView Data Source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ return [_completedCells count];
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ static NSString *reuseIdentifier = @"WXTableViewCell";
+
+ WXCellComponent *cell = _cellComponents[indexPath.row];
+ if (cell.scope.length > 0) {
+ // reuseIdentifier = cell.scope;
+ }
+
+ UITableViewCell *cellView = [_tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
+ if (!cellView) {
+ cellView = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
+ cellView.backgroundColor = [UIColor clearColor];
+ } else {
+ }
+
+ if (cell.view.superview == cellView.contentView) {
+ return cellView;
+ }
+
+ for (UIView *view in cellView.contentView.subviews) {
+ [view removeFromSuperview];
+ }
+
+ [cellView.contentView addSubview:cell.view];
+
+ double time = -[self.weexInstance.renderStartDate timeIntervalSinceNow] * 1000;
+ WXLogInfo(@"View Create Finish...%ld, %f", (long)indexPath.row, time);
+
+ return cellView;
+}
+
+#pragma mark - Load More Event
+
+- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
+{
+ if (loadmoreretry > self.loadmoreretry) {
+ _previousLoadMoreRowNumber = 0;
+ }
+
+ [super setLoadmoreretry:loadmoreretry];
+}
+
+- (void)loadMore
+{
+ [super loadMore];
+ _previousLoadMoreRowNumber = [self tableView:_tableView numberOfRowsInSection:0];
+}
+
+- (BOOL)isNeedLoadMore
+{
+ BOOL superNeedLoadMore = [super isNeedLoadMore];
+ return superNeedLoadMore && _previousLoadMoreRowNumber != [self tableView:_tableView numberOfRowsInSection:0];
+}
+
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
new file mode 100644
index 0000000..6a78b04
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXLoadingComponent : WXComponent
+
+- (void)resizeFrame;
+- (void)loading;
+- (BOOL)displayState;
+
+@end
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
new file mode 100644
index 0000000..78006ef
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
@@ -0,0 +1,137 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXLoadingComponent.h"
+#import "WXScrollerComponent.h"
+#import "WXLoadingIndicator.h"
+#import "WXComponent_internal.h"
+#import "WXLog.h"
+
+@interface WXLoadingComponent()
+
+@property (nonatomic) BOOL initFinished;
+@property (nonatomic) BOOL loadingEvent;
+@property (nonatomic) BOOL displayState;
+
+@property (nonatomic, weak) WXLoadingIndicator *indicator;
+
+@end
+
+@implementation WXLoadingComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+ self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+ if (self) {
+ if (attributes[@"display"]) {
+ if ([attributes[@"display"] isEqualToString:@"show"]) {
+ _displayState = YES;
+ } else if ([attributes[@"display"] isEqualToString:@"hide"]){
+ _displayState = NO;
+ } else {
+ WXLogError(@"");
+ }
+ }
+ self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
+ }
+ return self;
+}
+
+- (void)viewWillUnload
+{
+ _displayState = NO;
+ _loadingEvent = NO;
+ _initFinished = NO;
+}
+
+-(void)updateAttributes:(NSDictionary *)attributes
+{
+ if (attributes[@"display"]) {
+ if ([attributes[@"display"] isEqualToString:@"show"]) {
+ _displayState = YES;
+
+ } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+ _displayState = NO;
+ } else {
+ WXLogError(@"");
+ }
+ [self setDisplay];
+ }
+}
+
+- (void)viewDidLoad
+{
+ _initFinished = YES;
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+ if ([eventName isEqualToString:@"loading"]) {
+ _loadingEvent = YES;
+ }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+ if ([eventName isEqualToString:@"loading"]) {
+ _loadingEvent = NO;
+ }
+}
+
+- (void)loading
+{
+ if (!_loadingEvent)
+ return;
+
+ [self fireEvent:@"loading" params:nil];
+}
+
+- (void)setDisplay
+{
+ id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+ if (scrollerProtocol == nil || !_initFinished)
+ return;
+
+ WXComponent *scroller = (WXComponent*)scrollerProtocol;
+ CGPoint contentOffset = [scrollerProtocol contentOffset];
+ if (_displayState) {
+ contentOffset.y = [scrollerProtocol contentSize].height - scroller.calculatedFrame.size.height + self.view.frame.size.height;
+ [scrollerProtocol setContentOffset:contentOffset animated:YES];
+ [_indicator start];
+ } else {
+ UIEdgeInsets insets = [scrollerProtocol contentInset];
+ insets.bottom = 0;
+
+ [scrollerProtocol setContentInset:insets];
+ [_indicator stop];
+ }
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+ if (subcomponent) {
+ [super _insertSubcomponent:subcomponent atIndex:index];
+ if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
+ _indicator = (WXLoadingIndicator*)subcomponent;
+ }
+ }
+}
+
+- (void)resizeFrame
+{
+ CGRect rect = self.view.frame;
+
+ id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+ if (scrollerProtocol) {
+ rect.origin.y = [scrollerProtocol contentSize].height;
+ }
+
+ [self.view setFrame:rect];
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
new file mode 100644
index 0000000..8cc9990
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXLoadingIndicator : WXComponent
+
+- (void)start;
+- (void)stop;
+- (void)setFrame:(CGRect)frame;
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
new file mode 100644
index 0000000..16af357
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
@@ -0,0 +1,78 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXLoadingIndicator.h"
+#import "WXConvert.h"
+
+@interface WXLoadingIndicator()
+
+@property (nonatomic, strong) UIActivityIndicatorView* indicator;
+
+@end
+
+@implementation WXLoadingIndicator
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance {
+ self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+ if (self) {
+ _indicator = [[UIActivityIndicatorView alloc] init];
+ if (styles[@"color"]) {
+ [self setColor:[WXConvert UIColor:styles[@"color"]]];
+ }
+ }
+
+ return self;
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+ if (styles[@"color"]) {
+ [self setColor:[WXConvert UIColor:styles[@"color"]]];
+ }
+}
+
+- (UIView *)loadView
+{
+ return _indicator;
+}
+
+#pragma mark - lifeCircle
+- (void)viewWillUnload
+{
+ [_indicator stopAnimating];
+ _indicator = nil;
+
+}
+
+- (void)viewDidLoad
+{
+ [self setFrame:self.calculatedFrame];
+}
+
+- (void)setColor:(UIColor *)color
+{
+ _indicator.color = color;
+}
+
+- (void)start
+{
+ [_indicator startAnimating];
+}
+
+- (void)stop
+{
+ [_indicator stopAnimating];
+}
+
+- (void)setFrame:(CGRect)frame
+{
+ [_indicator setFrame:frame];
+}
+
+@end
+
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
new file mode 100644
index 0000000..46275f5
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXRefreshComponent : WXComponent
+
+- (void)refresh;
+
+- (BOOL)displayState;
+
+@end