blob: f6f89b5d6ab757fa97d05f43d8ac7dafb5a9de7d [file] [log] [blame]
/**
* Copyright 2018 Alibaba Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "EBWXOldModule.h"
#import <WeexSDK/WeexSDK.h>
#import "EBExpressionHandler.h"
#import <pthread/pthread.h>
#import <WeexPluginLoader/WeexPluginLoader.h>
#import "EBBindData.h"
#import "EBUtility+WX.h"
#import "EBWXUtils.h"
WX_PlUGIN_EXPORT_MODULE(expressionBinding, EBWXOldModule)
@interface EBWXOldModule ()
@property (nonatomic, strong) EBBindData *bindData;
@end
@implementation EBWXOldModule {
pthread_mutex_t mutex;
pthread_mutexattr_t mutexAttr;
}
@synthesize weexInstance;
WX_EXPORT_METHOD_SYNC(@selector(enableBinding:eventType:))
WX_EXPORT_METHOD_SYNC(@selector(createBinding:eventType:exitExpression:targetExpression:callback:))
WX_EXPORT_METHOD_SYNC(@selector(disableBinding:eventType:))
WX_EXPORT_METHOD_SYNC(@selector(disableAll))
WX_EXPORT_METHOD_SYNC(@selector(supportFeatures))
WX_EXPORT_METHOD_SYNC(@selector(getComputedStyle:))
- (instancetype)init {
if (self = [super init]) {
pthread_mutexattr_init(&mutexAttr);
pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &mutexAttr);
_bindData = [EBBindData new];
}
return self;
}
- (void)dealloc {
[self disableAll];
pthread_mutex_destroy(&mutex);
pthread_mutexattr_destroy(&mutexAttr);
}
- (void)enableBinding:(NSString *)sourceRef
eventType:(NSString *)eventType {
if ([WXUtility isBlankString:sourceRef] || [WXUtility isBlankString:eventType]) {
WX_LOG(WXLogFlagWarning, @"enableBinding params error");
return;
}
if (![EBEventHandlerFactory containsEvent:eventType]) {
WX_LOG(WXLogFlagWarning, @"enableBinding params error");
return;
}
__weak typeof(self) welf = self;
WXPerformBlockOnComponentThread(^{
// find sourceRef & targetRef
WXComponent *sourceComponent = [weexInstance componentForRef:sourceRef];
if (!sourceComponent) {
WX_LOG(WXLogFlagWarning, @"enableBinding can't find component");
return;
}
pthread_mutex_lock(&mutex);
EBExpressionHandler *handler = [welf.bindData handlerForToken:sourceRef eventType:eventType];
if (!handler) {
// create handler for key
handler = [EBEventHandlerFactory createHandlerWithEvent:eventType source:sourceComponent];
[welf.bindData putHandler:handler forToken:sourceRef eventType:eventType];
}
pthread_mutex_unlock(&mutex);
});
}
- (void)createBinding:(NSString *)sourceRef
eventType:(NSString *)eventType
exitExpression:(NSString *)exitExpression
targetExpression:(NSArray *)targetExpression
callback:(WXKeepAliveCallback)callback {
if ([WXUtility isBlankString:sourceRef] || [WXUtility isBlankString:eventType] || !targetExpression || targetExpression.count == 0) {
WX_LOG(WXLogFlagWarning, @"createBinding params error");
callback(@{@"state":@"error",@"msg":@"createBinding params error"}, NO);
return;
}
if (![EBEventHandlerFactory containsEvent:eventType]) {
WX_LOG(WXLogFlagWarning, @"createBinding params handler error");
callback(@{@"state":@"error",@"msg":@"createBinding params handler error"}, NO);
return;
}
__weak typeof(self) welf = self;
WXPerformBlockOnComponentThread(^{
// find sourceRef & targetRef
WXComponent *sourceComponent = [weexInstance componentForRef:sourceRef];
if (!sourceComponent) {
WX_LOG(WXLogFlagWarning, @"createBinding can't find source component");
callback(@{@"state":@"error",@"msg":@"createBinding can't find source component"}, NO);
return;
}
NSMapTable<id, NSDictionary *> *targetExpressionMap = [NSMapTable weakToStrongObjectsMapTable];
for (NSDictionary *targetDic in targetExpression) {
NSString *targetRef = targetDic[@"element"];
NSString *property = targetDic[@"property"];
NSString *expression = targetDic[@"expression"];
WXComponent *targetComponent = [weexInstance componentForRef:targetRef];
if (targetComponent) {
if ([targetComponent isViewLoaded]) {
WXPerformBlockOnMainThread(^{
[targetComponent.view.layer removeAllAnimations];
});
}
NSMutableDictionary *propertyDic = [[targetExpressionMap objectForKey:targetComponent] mutableCopy];
if (!propertyDic) {
propertyDic = [NSMutableDictionary dictionary];
}
NSMutableDictionary *expDict = [NSMutableDictionary dictionary];
expDict[@"expression"] = [EBBindData parseExpression:expression];
if( targetDic[@"config"] )
{
expDict[@"config"] = targetDic[@"config"];
}
propertyDic[property] = expDict;
[targetExpressionMap setObject:propertyDic forKey:targetComponent];
}
}
// find handler for key
pthread_mutex_lock(&mutex);
EBExpressionHandler *handler = [welf.bindData handlerForToken:sourceRef eventType:eventType];
if (!handler) {
// create handler for key
handler = [EBEventHandlerFactory createHandlerWithEvent:eventType source:sourceComponent];
[welf.bindData putHandler:handler forToken:sourceRef eventType:eventType];
}
[handler updateTargetExpression:targetExpressionMap
options:nil
exitExpression:[EBBindData parseExpression:exitExpression]
callback:^(id _Nonnull source, id _Nonnull result, BOOL keepAlive) {
callback(result,keepAlive);
}];
pthread_mutex_unlock(&mutex);
});
}
- (void)disableBinding:(NSString *)sourceRef
eventType:(NSString *)eventType {
if ([WXUtility isBlankString:sourceRef] || [WXUtility isBlankString:eventType]) {
WX_LOG(WXLogFlagWarning, @"disableBinding params error");
return;
}
if (![EBEventHandlerFactory containsEvent:eventType]) {
WX_LOG(WXLogFlagWarning, @"disableBinding params handler error");
return;
}
pthread_mutex_lock(&mutex);
EBExpressionHandler *handler = [self.bindData handlerForToken:sourceRef eventType:eventType];
if (!handler) {
WX_LOG(WXLogFlagWarning, @"disableBinding can't find handler handler");
pthread_mutex_unlock(&mutex);
return;
}
[handler removeExpressionBinding];
[self.bindData removeHandler:handler forToken:sourceRef eventType:eventType];
pthread_mutex_unlock(&mutex);
}
- (void)disableAll {
pthread_mutex_lock(&mutex);
[self.bindData unbindAll];
pthread_mutex_unlock(&mutex);
}
- (NSArray *)supportFeatures {
return EBsupportFeatures;
}
- (NSDictionary *)getComputedStyle:(NSString *)sourceRef {
if (![sourceRef isKindOfClass:NSString.class] || [WXUtility isBlankString:sourceRef]) {
WX_LOG(WXLogFlagWarning, @"getComputedStyle params error");
return nil;
}
__block NSMutableDictionary *styles = [NSMutableDictionary new];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
WXPerformBlockOnComponentThread(^{
// find sourceRef & targetRef
WXComponent *sourceComponent = [weexInstance componentForRef:sourceRef];
if (!sourceComponent) {
WX_LOG(WXLogFlagWarning, @"getComputedStyle can't find source component");
return;
}
NSDictionary* mapping = [EBWXUtils cssPropertyMapping];
for (NSString* key in mapping) {
id value = sourceComponent.styles[key];
if (value) {
if ([value isKindOfClass:NSString.class]) {
NSString *string = (NSString *)value;
if ([string hasSuffix:@"px"]) {
NSString *number = [string substringToIndex:(string.length-2)];
[styles setValue:@([number floatValue]) forKey:mapping[key]];
} else {
[styles setValue:string forKey:mapping[key]];
}
} else if([value isKindOfClass:NSNumber.class]) {
[styles setValue:value forKey:mapping[key]];
}
}
}
if (sourceComponent.styles[@"borderRadius"]) {
[styles setValue:sourceComponent.styles[@"borderRadius"] forKey:@"border-top-left-radius"];
[styles setValue:sourceComponent.styles[@"borderRadius"] forKey:@"border-top-right-radius"];
[styles setValue:sourceComponent.styles[@"borderRadius"] forKey:@"border-bottom-left-radius"];
[styles setValue:sourceComponent.styles[@"borderRadius"] forKey:@"border-bottom-right-radius"];
}
WXPerformBlockOnMainThread(^{
CALayer *layer = sourceComponent.view.layer;
styles[@"translateX"] = [EBUtility transformFactor:@"transform.translation.x" layer:layer];
styles[@"translateY"] = [EBUtility transformFactor:@"transform.translation.y" layer:layer];
styles[@"scaleX"] = [layer valueForKeyPath:@"transform.scale.x"];
styles[@"scaleY"] = [layer valueForKeyPath:@"transform.scale.y"];
styles[@"rotateX"] = [layer valueForKeyPath:@"transform.rotation.x"];
styles[@"rotateY"] = [layer valueForKeyPath:@"transform.rotation.y"];
styles[@"rotateZ"] = [layer valueForKeyPath:@"transform.rotation.z"];
styles[@"opacity"] = [layer valueForKeyPath:@"opacity"];
dispatch_semaphore_signal(semaphore);
});
});
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)));
return styles;
}
@end