mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Added named parameters support for xml binding definition.
This commit is contained in:
@@ -302,6 +302,7 @@
|
||||
<TypeScriptCompile Include="trace\trace.ts">
|
||||
<DependentUpon>trace.d.ts</DependentUpon>
|
||||
</TypeScriptCompile>
|
||||
<TypeScriptCompile Include="ui\builder\binding-builder.ts" />
|
||||
<TypeScriptCompile Include="ui\list-picker\list-picker-common.ts">
|
||||
<DependentUpon>list-picker.d.ts</DependentUpon>
|
||||
</TypeScriptCompile>
|
||||
|
||||
@@ -9,6 +9,7 @@ import buttonModule = require("ui/button");
|
||||
import utils = require("utils/utils");
|
||||
import pageModule = require("ui/page");
|
||||
import stackLayoutModule = require("ui/layouts/stack-layout");
|
||||
import bindingBuilder = require("ui/builder/binding-builder");
|
||||
|
||||
// <snippet module="ui/core/bindable" title="bindable">
|
||||
// For information and examples how to use bindings please refer to special [**Data binding**](../../../../bindings.md) topic.
|
||||
@@ -383,7 +384,7 @@ export var test_Bindable_BindingContext_String_DoesNotThrow = function () {
|
||||
|
||||
export var test_getBindableOptionsFromStringFullFormat = function () {
|
||||
var bindingExpression = "bindProperty, bindProperty * 2, false";
|
||||
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
@@ -393,7 +394,7 @@ export var test_getBindableOptionsFromStringFullFormat = function () {
|
||||
|
||||
export var test_getBindableOptionsFromStringShortFormatExpression = function () {
|
||||
var bindingExpression = "bindProperty * 2";
|
||||
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
@@ -403,17 +404,56 @@ export var test_getBindableOptionsFromStringShortFormatExpression = function ()
|
||||
|
||||
export var test_getBindableOptionsFromStringShortFormatProperty = function () {
|
||||
var bindingExpression = "bindProperty";
|
||||
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
TKUnit.assert(bindOptions.expression === null, "Expected: null, Actual: " + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.expression === undefined, "Expected: null, Actual: " + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
|
||||
}
|
||||
|
||||
export var test_getBindableOptionsFromStringTwoParamsFormat = function () {
|
||||
var bindingExpression = "bindProperty, bindProperty * 2";
|
||||
var bindOptions = bindable.Bindable._getBindingOptions("targetBindProperty", bindingExpression);
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual:" + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
|
||||
}
|
||||
|
||||
export var test_getBindableOptionsFromStringFullNamedFormat = function () {
|
||||
var bindingExpression = "bindProperty, expression = bindProperty * 2, twoWay = false";
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual:" + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.twoWay === false, "Expected: false, Actual: " + bindOptions.twoWay);
|
||||
}
|
||||
|
||||
export var test_getBindableOptionsFromStringShortNamedFormatExpression = function () {
|
||||
var bindingExpression = "sourceProperty = bindProperty, expression = bindProperty * 2";
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
TKUnit.assert(bindOptions.expression === "bindProperty * 2", "Expected: bindProperty * 2, Actual: " + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
|
||||
}
|
||||
|
||||
export var test_getBindableOptionsFromStringShortNamedFormatProperty = function () {
|
||||
var bindingExpression = "sourceProperty = bindProperty";
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
TKUnit.assert(bindOptions.expression === undefined, "Expected: null, Actual: " + bindOptions.expression);
|
||||
TKUnit.assert(bindOptions.twoWay === true, "Expected: true, Actual: " + bindOptions.twoWay);
|
||||
}
|
||||
|
||||
export var test_getBindableOptionsFromStringTwoParamsNamedFormat = function () {
|
||||
var bindingExpression = "bindProperty, expression = bindProperty * 2";
|
||||
var bindOptions = bindingBuilder.getBindingOptions("targetBindProperty", bindingExpression);
|
||||
|
||||
TKUnit.assert(bindOptions.sourceProperty === "bindProperty", "Expected: bindProperty, Actual: " + bindOptions.sourceProperty);
|
||||
TKUnit.assert(bindOptions.targetProperty === "targetBindProperty", "Expected: targetBindProperty, Actual: " + bindOptions.targetProperty);
|
||||
|
||||
154
ui/builder/binding-builder.ts
Normal file
154
ui/builder/binding-builder.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
var expressionSymbolsRegex = /[ \+\-\*%\?:<>=!\|&\(\)\[\]]/;
|
||||
|
||||
export module bindingConstants {
|
||||
export var sourceProperty = "sourceProperty";
|
||||
export var targetProperty = "targetProperty";
|
||||
export var expression = "expression";
|
||||
export var twoWay = "twoWay";
|
||||
export var source = "source";
|
||||
};
|
||||
|
||||
var hasEqualSignRegex = /=+/;
|
||||
var equalSignComparisionOperatorsRegex = /(==|===|>=|<=|!=|!==)/;
|
||||
function isNamedParam(value) {
|
||||
var equalSignIndex = value.search(hasEqualSignRegex);
|
||||
if (equalSignIndex > -1) {
|
||||
var equalSignSurround = value.substr(equalSignIndex > 0 ? equalSignIndex - 1 : 0, 3);
|
||||
if (equalSignSurround.search(equalSignComparisionOperatorsRegex) === -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function areNamedParams(params: Array<any>) {
|
||||
var i;
|
||||
for (i = 0; i < params.length; i++) {
|
||||
if (isNamedParam(params[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var namedParamConstants = {
|
||||
propName: "propName",
|
||||
propValue: "propValue"
|
||||
}
|
||||
|
||||
function getPropertyNameValuePair(param, knownOptions, callback) {
|
||||
var nameValuePair = {};
|
||||
var propertyName = param.substr(0, param.indexOf("=")).trim();
|
||||
var propertyValue = param.substr(param.indexOf("=") + 1).trim();
|
||||
if (knownOptions) {
|
||||
if (!propertyName) {
|
||||
propertyName = knownOptions.defaultProperty;
|
||||
}
|
||||
else {
|
||||
propertyName = propertyName in knownOptions ? propertyName : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (propertyName) {
|
||||
if (callback) {
|
||||
nameValuePair = callback(propertyName, propertyValue);
|
||||
}
|
||||
else {
|
||||
nameValuePair[namedParamConstants.propName] = propertyName;
|
||||
nameValuePair[namedParamConstants.propValue] = propertyValue;
|
||||
}
|
||||
return nameValuePair;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseNamedProperties(parameterList, knownOptions, callback) {
|
||||
var result = {};
|
||||
var i;
|
||||
for (i = 0; i < parameterList.length; i++) {
|
||||
var nameValuePair = getPropertyNameValuePair(parameterList[i], knownOptions, callback);
|
||||
if (nameValuePair) {
|
||||
result[nameValuePair[namedParamConstants.propName]] = nameValuePair[namedParamConstants.propValue];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function extractPropertyNameFromExpression(expression: string): string {
|
||||
var firstExpressionSymbolIndex = expression.search(expressionSymbolsRegex);
|
||||
if (firstExpressionSymbolIndex > -1) {
|
||||
return expression.substr(0, firstExpressionSymbolIndex).trim();
|
||||
}
|
||||
else {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
export function getBindingOptions(name: string, value: string): any {
|
||||
var namedParams = [];
|
||||
var params = value.split(",");
|
||||
if (!areNamedParams(params)) {
|
||||
if (params.length === 1) {
|
||||
namedParams.push(bindingConstants.sourceProperty + " = " + extractPropertyNameFromExpression(params[0].trim()));
|
||||
var expression = params[0].search(expressionSymbolsRegex) > -1 ? params[0].trim() : null;
|
||||
if (expression) {
|
||||
namedParams.push(bindingConstants.expression + " = " + expression);
|
||||
}
|
||||
namedParams.push(bindingConstants.twoWay + " = true");
|
||||
}
|
||||
else {
|
||||
namedParams.push(bindingConstants.sourceProperty + " = " + extractPropertyNameFromExpression(params[0].trim()));
|
||||
namedParams.push(bindingConstants.expression + " = " + params[1].trim());
|
||||
var twoWay = params[2] ? params[2].toLowerCase().trim() === "true" : true;
|
||||
namedParams.push(bindingConstants.twoWay + " = " + twoWay);
|
||||
}
|
||||
}
|
||||
else {
|
||||
namedParams = params;
|
||||
}
|
||||
|
||||
var bindingPropertyHandler = function (prop, value) {
|
||||
var result = {};
|
||||
result[namedParamConstants.propName] = prop;
|
||||
if (prop === bindingConstants.twoWay) {
|
||||
// create a real boolean value
|
||||
if (value === "true") {
|
||||
result[namedParamConstants.propValue] = true;
|
||||
}
|
||||
else {
|
||||
result[namedParamConstants.propValue] = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result[namedParamConstants.propValue] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var bindingOptionsParameters = parseNamedProperties(namedParams, xmlBindingProperties, bindingPropertyHandler);
|
||||
var bindOptions = {
|
||||
targetProperty: name
|
||||
};
|
||||
|
||||
for (var prop in bindingOptionsParameters) {
|
||||
if (bindingOptionsParameters.hasOwnProperty(prop)) {
|
||||
bindOptions[prop] = bindingOptionsParameters[prop];
|
||||
}
|
||||
}
|
||||
|
||||
if (bindOptions[bindingConstants.twoWay] === undefined) {
|
||||
bindOptions[bindingConstants.twoWay] = true;
|
||||
}
|
||||
|
||||
return bindOptions;
|
||||
}
|
||||
|
||||
var xmlBindingProperties = {
|
||||
sourceProperty: true,
|
||||
expression: true,
|
||||
twoWay: true,
|
||||
source: true,
|
||||
defaultProperty: bindingConstants.sourceProperty
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import types = require("utils/types");
|
||||
import definition = require("ui/builder/component-builder");
|
||||
import fs = require("file-system");
|
||||
import gestures = require("ui/gestures");
|
||||
import bindingBuilder = require("ui/builder/binding-builder");
|
||||
|
||||
var KNOWNEVENTS = "knownEvents";
|
||||
var UI_PATH = "ui/";
|
||||
@@ -76,7 +77,13 @@ export function getComponentModule(elementName: string, namespace: string, attri
|
||||
if (isKnownEvent(attr, instanceModule)) {
|
||||
attachEventBinding(instance, attr, attrValue);
|
||||
} else {
|
||||
instance.bind(getBinding(instance, attr, attrValue));
|
||||
var bindOptions = bindingBuilder.getBindingOptions(attr, getBindingExpressionFromAttribute(attrValue));
|
||||
instance.bind({
|
||||
sourceProperty : bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
||||
targetProperty: bindOptions[bindingBuilder.bindingConstants.targetProperty],
|
||||
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
||||
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
||||
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
||||
}
|
||||
} else if (isKnownEvent(attr, instanceModule)) {
|
||||
// Get the event handler from page module exports.
|
||||
@@ -160,10 +167,6 @@ function isKnownEvent(name: string, exports: any): boolean {
|
||||
(KNOWNEVENTS in view && name in view[KNOWNEVENTS]);
|
||||
}
|
||||
|
||||
function getBinding(instance: view.View, name: string, value: string): bindable.BindingOptions {
|
||||
return bindable.Bindable._getBindingOptions(name, getBindingExpressionFromAttribute(value));
|
||||
}
|
||||
|
||||
function getBindingExpressionFromAttribute(value: string): string {
|
||||
return value.replace("{{", "").replace("}}", "").trim();
|
||||
}
|
||||
@@ -177,4 +180,4 @@ function isBinding(value: string): boolean {
|
||||
}
|
||||
|
||||
return isBinding;
|
||||
}
|
||||
}
|
||||
1
ui/core/bindable.d.ts
vendored
1
ui/core/bindable.d.ts
vendored
@@ -66,7 +66,6 @@
|
||||
unbind(property: string);
|
||||
|
||||
//@private
|
||||
static _getBindingOptions(name: string, bindingExpression: string): BindingOptions;
|
||||
_updateTwoWayBinding(propertyName: string, value: any);
|
||||
_onBindingContextChanged(oldValue: any, newValue: any);
|
||||
//@endprivate
|
||||
|
||||
@@ -6,8 +6,6 @@ import types = require("utils/types");
|
||||
import trace = require("trace");
|
||||
import polymerExpressions = require("js-libs/polymer-expressions");
|
||||
|
||||
var expressionSymbolsRegex = /[ \+\-\*%\?:<>=!\|&\(\)\[\]]/;
|
||||
|
||||
var bindingContextProperty = new dependencyObservable.Property(
|
||||
"bindingContext",
|
||||
"Bindable",
|
||||
@@ -116,38 +114,6 @@ export class Bindable extends dependencyObservable.DependencyObservable implemen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static extractPropertyNameFromExpression(expression: string): string {
|
||||
var firstExpressionSymbolIndex = expression.search(expressionSymbolsRegex);
|
||||
if (firstExpressionSymbolIndex > -1) {
|
||||
return expression.substr(0, firstExpressionSymbolIndex).trim();
|
||||
}
|
||||
else {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
public static _getBindingOptions(name: string, bindingExpression: string): definition.BindingOptions {
|
||||
var result: definition.BindingOptions;
|
||||
result = {
|
||||
targetProperty: name,
|
||||
sourceProperty: ""
|
||||
};
|
||||
if (types.isString(bindingExpression)) {
|
||||
var params = bindingExpression.split(",");
|
||||
if (params.length === 1) {
|
||||
result.sourceProperty = Bindable.extractPropertyNameFromExpression(params[0].trim());
|
||||
result.expression = params[0].search(expressionSymbolsRegex) > -1 ? params[0].trim() : null;
|
||||
result.twoWay = true;
|
||||
}
|
||||
else {
|
||||
result.sourceProperty = Bindable.extractPropertyNameFromExpression(params[0].trim());
|
||||
result.expression = params[1].trim();
|
||||
result.twoWay = params[2] ? params[2].toLowerCase().trim() === "true" : true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export class Binding {
|
||||
|
||||
Reference in New Issue
Block a user