Merge pull request #2745 from conficient/master

Valerie: added new interfaces; Knockout: fixed .register overloads
This commit is contained in:
Igor Oleinikov
2014-09-26 15:03:13 -07:00
4 changed files with 393 additions and 27 deletions

View File

@@ -557,7 +557,13 @@ interface KnockoutBindingProvider {
}
interface KnockoutComponents {
register(componentName: string, definition: KnockoutComponentDefinition): void;
// overloads for register method:
register(componentName: string, config: KnockoutComponentRegister): void;
register(componentName: string, config: KnockoutComponentRegisterStringTemplate): void;
register(componentName: string, config: KnockoutComponentRegisterFnViewModel): void;
register(componentName: string, config: KnockoutComponentRegisterStringTemplateFnViewModel): void;
register(componentName: string, config: KnockoutComponentRegisterAMD): void;
isRegistered(componentName: string): boolean;
unregister(componentName: string): void;
get(componentName: string, callback: (definition: KnockoutComponentDefinition) => void): void;
@@ -567,6 +573,50 @@ interface KnockoutComponents {
getComponentNameForNode(node: Node): string;
}
/* interfaces for register overloads*/
interface KnockoutComponentRegister {
template: KnockoutComponentTemplate;
viewModel?: KnockoutComponentConfigViewModel;
}
interface KnockoutComponentRegisterAMD {
// load self-describing module using AMD module name
require: string;
}
interface KnockoutComponentRegisterFnViewModel {
template: KnockoutComponentTemplate;
viewModel?: (params: any) => any;
}
interface KnockoutComponentRegisterStringTemplate {
template: string;
viewModel?: KnockoutComponentConfigViewModel;
}
interface KnockoutComponentRegisterStringTemplateFnViewModel {
template: string;
viewModel?: (params: any) => any;
}
interface KnockoutComponentConfigViewModel {
instance?: any;
createViewModel? (params?: any, componentInfo?: KnockoutComponentInfo): any;
require?: string;
}
interface KnockoutComponentTemplate {
// specify element id (string) or a node
element?: any;
// AMD module load
require?: string;
}
interface KnockoutComponentInfo {
element: any;
}
/* end register overloads */
interface KnockoutComponentDefinition {
template: Node[];
createViewModel?(params: any, options: { element: Node; }): any;

View File

@@ -602,4 +602,49 @@ function test_allBindingsAccessor() {
var fnAccessorBinding = allBindingsAccessor().myBindingName;
}
};
}
function test_Components() {
function test_Register() {
// test all possible ko.components.register() overloads
var nodeArray = [new Node, new Node];
var singleNode = new Node;
// ------- string-templates with different viewmodel overloads:
// string template and inline function (commonly used in examples)
ko.components.register("name", { template: "string-template", viewModel: function (params) { return null; } });
// string template and instance vm
ko.components.register("name", { template: "string-template", viewModel: { instance: null } });
// string template and createViewModel factory method
ko.components.register("name", { template: "string-template", viewModel: { createViewModel: function (params: any, componentInfo: KnockoutComponentInfo) { return null; } } });
// string template and require module vm
ko.components.register("name", { template: "string-template", viewModel: { require: "module" } });
// ------- non-string templates
// viewmodel as function and four types of template
ko.components.register("name", { template: { element: "elementID" }, viewModel: function (params) { return null; } });
// Node template for element and inline function (commonly used in examples)
ko.components.register("name", { template: { element: singleNode }, viewModel: function (params) { return null; } });
// object template for element and inline function (commonly used in examples)
ko.components.register("name", { template: nodeArray, viewModel: function (params) { return null; } });
// object template for element and inline function (commonly used in examples)
ko.components.register("name", { template: { require: "module" }, viewModel: function (params) { return null; } });
// viewmodel as object, and four types of non-string tempalte
ko.components.register("name", { template: { element: "elementID" }, viewModel: { instance: null } });
// Node template for element and inline function (commonly used in examples)
ko.components.register("name", { template: { element: singleNode }, viewModel: { instance: null } });
// object template for element and inline function (commonly used in examples)
ko.components.register("name", { template: nodeArray, viewModel: { instance: null } });
// object template for element and inline function (commonly used in examples)
ko.components.register("name", { template: { require: "module" }, viewModel: { instance: null } });
//
}
}

View File

@@ -285,4 +285,51 @@ function RuleTests() {
.rule(() => { return anyValue; })
.end();
}
}
function ModelValidation() {
var model = {};
var validatedModel = valerie.validatableModel(model)
.validateAll()
.end();
}
function UtilsStaticTests() {
var t1 = valerie.utils.asArray(1);
var t2 = valerie.utils.asArray([1,2]);
var t3 = valerie.utils.asFunction(1);
var t4 = valerie.utils.asFunction(() => { return 1; });
var t5 = valerie.utils.isArray([1, 2]);
var t5 = valerie.utils.isArrayOrObject(1);
var t6 = valerie.utils.isFunction("x");
var t7 = valerie.utils.isMissing(null);
var t8 = valerie.utils.isObject({});
var t9 = valerie.utils.isString("test");
var opts: Valerie.ValidationOptions = {}; // all values are optional
var t10 = valerie.utils.mergeOptions(opts, opts);
}
function ValidationResultStaticTests() {
var t1 = valerie.ValidationResult.passedInstance;
var t2 = valerie.ValidationResult.createFailedResult("message");
}
function ValidationStateStaticTests() {
var t1 = valerie.validationState.findIn({});
var t2 = valerie.validationState.getFor({});
var t3 = valerie.validationState.has({});
var state = <Valerie.IValidationState>{};
var t4 = valerie.validationState.setFor({}, state);
}

274
valerie/valerie.d.ts vendored
View File

@@ -7,7 +7,10 @@
/**
*
* Extensions to KO functions to provide validation
* Extensions to KO functions to provide validation
*
* Version 1.2 - added more static methods to valerie object
*
*/
interface KnockoutObservable<T> {
// starts validation for observable
@@ -23,7 +26,6 @@ interface KnockoutObservableArray<T> {
validate(validationOptions?: Valerie.ValidationOptions): Valerie.PropertyValidationState<KnockoutObservableArray<T>>;
}
interface KnockoutObservableArrayFunctions<T> {
/**
* Creates and sets a model validation state on a Knockout observable array.<br/>
@@ -198,8 +200,6 @@ interface KnockoutBindingHandlers {
visibleWhenValid: KnockoutBindingHandler;
}
//
// root valerie namespace - static methods
//
@@ -208,12 +208,10 @@ declare var valerie: Valerie.Static;
// additional types for Valerie (all inside this namespace)
declare module Valerie {
//
// Static methods on valerie namespace
//
interface Static {
/**
* Maps a source model to a destination model, including only applicable properties
* @param {Object|Array} sourceModel the source model
@@ -248,9 +246,78 @@ declare module Valerie {
// (value should be observable or computed)
validatableProperty<T>(value: T, options?: ValidationOptions): PropertyValidationState<T>;
// Validation result class
ValidationResult: ValidationResultStatic;
// additional namespaces for static methods:
converters: ConvertersStatic;
/*
//TODO: additional namespaces/statics not yet used
dom: DomStatic;
formatting: FormattingStatic;
koBindingsHelper: KoBindingsHelperStatic;
koExtras: KoExtrasStatic;
rules: RulesStatic;
*/
utils: UtilsStatic;
validationState: ValidationState;
}
interface ValidationResultStatic {
passedInstance: ValidationResult;
// static method to create validatio failed message
createFailedResult(message: string): ValidationResult;
}
// Contains converters, always singletons.
interface ConvertersStatic {
//TODO: other converters to be added
passThrough: Valerie.IConverter;
}
interface UtilsStatic {
// Creates a function that returns the given value as an array of one item, or simply returns the given value if it is already an array.
asArray<T>(value: any): any[];
// Creates a function that returns the given value, or simply returns the given value if it is already a function
asFunction<T>(value: T): () => T;
asFunction<T>(fn: () => T): () => T;
// Tests whether the given value is an array
isArray(value: any): boolean;
// Tests whether the given value is an array or object.
isArrayOrObject(value: any): boolean;
// Tests whether the given value is a function.
isFunction(value: any): boolean;
// Tests whether the given value is "missing".undefined, null, an empty string or an empty array are considered to be "missing".
isMissing(value: any): boolean;
// Tests whether the given value is an object.
isObject(value: any): boolean;
// Tests whether the give value is a string.
isString(value: any): boolean;
//Merges the given default options with the given options.
// - either parameter can be omitted and a clone of the other parameter will be returned
// - the merge is shallow
// - array properties are shallow cloned
mergeOptions(defaultOptions: ValidationOptions, options:any): ValidationOptions;
}
// callback interface (see mapModel above)
@@ -263,10 +330,175 @@ declare module Valerie {
// ctor
new: (model: any, options?: ModelValidationStateOptions) => ModelValidationState;
addValidationStates(validationStateOrStates: any): void;
model: any;
options?: ModelValidationStateOptions
// methods
/**
* Adds validation states to this validation state.<br/>
* <i>[fluent]</i>
* @name valerie.ModelValidationState#addValidationStates
* @fluent
* @param {object|array.<valerie.IValidationState>} validationStateOrStates the validation states to add
* @return {valerie.ModelValidationState}
*/
addValidationStates(validationStateOrStates: any): ModelValidationState;
/**
* Sets the value or function used to determine if the model is applicable.<br/>
* <i>[fluent]</i>
* @name valerie.ModelValidationState#applicable
* @fluent
* @param {boolean|function} [valueOrFunction = true] the value or function to use
* @return {valerie.ModelValidationState}
*/
applicable(valueOrFunction: any): ModelValidationState;
/**
* Clears the static summary of validation states that are in a failure state.<br/>
* <i>[fluent]</i>
* @name valerie.ModelValidationState#clearSummary
* @fluent
* @param {boolean} [clearSubModelSummaries = false] whether to clear the static summaries for sub-models
* @return {valerie.ModelValidationState}
*/
clearSummary(valueOrFunction: any): ModelValidationState;
/***
* Gets whether the model has failed validation.
* @return {boolean}
*/
failed(): boolean;
/***
* Gets the validation states that belong to the model that are in a failure state.
* @return {Valerie.IValidationState[]}
*/
failedStates(): Valerie.IValidationState[];
/***
* Gets the name of the model.
* @return {string}
*/
getName(): string;
isApplicable(): boolean;
message(): string;
passed(): boolean;
/***
* Gets or sets whether the computation that updates the validation result has been paused.
* @param {boolean} [value = false] true if the computation should be paused, false if the computation should not be paused
* @return {boolean} true if computation is paused, false otherwise
*/
paused(value: boolean): boolean;
pending(): boolean;
pendingStates(): IValidationState[];
refresh(): void;
result(): ValidationResult;
summary(): summaryItem[]
/***
* Gets or sets whether the model has been 'touched' by user action
*/
touched(value: boolean): boolean;
validationStates(): IValidationState[];
/**
* Includes any validation failures for this model in a validation summary.<br/>
* <i>[fluent]</i>
* @fluent
* @return {valerie.ModelValidationState}
*/
includeInSummary(): ModelValidationState;
/**
* Sets the value or function used to determine the name of the model.<br/>
* <i>[fluent]</i>
* @fluent
* @param {string|function} valueOrFunction the value or function to use
* @return {valerie.ModelValidationState}
*/
name(valueOrFunction: any): ModelValidationState;
/**
* Removes validation states.<br/>
* <i>[fluent]</i>
* @fluent
* @param {object|array.<valerie.IValidationState>} validationStateOrStates the validation states to remove
* @return {valerie.ModelValidationState}
*/
removeValidationStates(validationStateOrStates: any): ModelValidationState;
/**
* Stops validating the given sub-model by adding the validation state that belongs to it.
* @param {*} validatableSubModel the sub - model to start validating
* @return {valerie.ModelValidationState }
*/
startValidatingSubModel(validatableSubModel: any): ModelValidationState;
/**
* Stops validating the given sub-model by removing the validation state that belongs to it.
* @param {*} validatableSubModel the sub-model to stop validating
* @return {valerie.ModelValidationState}
*/
stopValidatingSubModel(validatableSubModel: any): ModelValidationState;
/**
* Updates the static summary of validation states that are in a failure state.<br/>
* <i>[fluent]</i>
* @fluent
* @param {boolean} [updateSubModelSummaries = false] whether to update the static summaries for sub-models
* @return {valerie.ModelValidationState}
*/
updateSummary(updateSubModelSummaries: boolean): ModelValidationState;
/**
* Adds the validation states for all the descendant properties and sub-models that belong to the model.<br/>
* <i>[fluent]</i>
* @fluent
* @return {valerie.ModelValidationState}
*/
validateAll(): ModelValidationState;
/**
* Adds the validation states for all the descendant properties that belong to the model.<br/>
* <i>[fluent]</i>
* @fluent
* @return {valerie.ModelValidationState}
*/
validateAllProperties(): ModelValidationState;
/**
* Adds the validation states for all the child properties that belong to the model.<br/>
* <i>[fluent]</i>
* @fluent
* @return {valerie.ModelValidationState}
*/
validateChildProperties(): ModelValidationState;
/**
* Adds the validation states for all the child properties and sub-models that belong to the model.<br/>
* <i>[fluent]</i>
* @fluent
* @return {valerie.ModelValidationState}
*/
validateChildPropertiesAndSubModels(): ModelValidationState;
/**
* Ends a chain of fluent method calls on this model validation state.
* @return {function} the model the validation state is for
*/
end(): any;
}
// Construction options for a model validation state.
@@ -282,7 +514,6 @@ declare module Valerie {
// PropertyValidationState
//
interface PropertyValidationState<T> {
// properties:
// the observable or computed the validation state is for
@@ -310,12 +541,12 @@ declare module Valerie {
during(earliest: () => Date, latest: Date, options?: ValidationOptions): PropertyValidationState<T>; // dateFN + date
during(earliest: Date, latest: () => Date, options?: ValidationOptions): PropertyValidationState<T>; // date + dateFN
during(earliest: () => Date, latest: () => Date, options?: ValidationOptions): PropertyValidationState<T>; // dateFN + dateFN
earliest(earliest: Date, options?: ValidationOptions): PropertyValidationState<T>; // date value
earliest(earliest: Date, options?: ValidationOptions): PropertyValidationState<T>; // date value
earliest(earliest: () => Date, options?: ValidationOptions): PropertyValidationState<T>; // date function
email(): PropertyValidationState<T>;
entryFormat(format: string): PropertyValidationState<T>;
excludeFromSummary(): PropertyValidationState<T>;
expression(regularExpression: RegExp, options?: ValidationOptions): PropertyValidationState<T>; // regex
expression(regularExpression: RegExp, options?: ValidationOptions): PropertyValidationState<T>; // regex
expression(regularExpressionString: string, options?: ValidationOptions): PropertyValidationState<T>; // regex string
float(options?: ValidationOptions): PropertyValidationState<T>;
integer(options?: ValidationOptions): PropertyValidationState<T>;
@@ -377,7 +608,6 @@ declare module Valerie {
touched(): boolean; // get touched state
touched(value: boolean): boolean; // set touched state
result(): ValidationResult;
}
interface ValidationResult {
@@ -387,10 +617,6 @@ declare module Valerie {
pending: boolean; //true if the activity hasn't yet completed
message: string; //a message from the activity
new: (state: any, message?: string) => ValidationResult;
//TODO: not added static members/methods
createFailedResult(message: string): ValidationResult;
}
interface IRule {
@@ -411,7 +637,7 @@ declare module Valerie {
}
interface ValidatableModel<T> {
name: (value:string) => PropertyValidationState<T>;
name: (value: string) => PropertyValidationState<T>;
// return original observableArray
end: () => T;
@@ -438,7 +664,6 @@ declare module Valerie {
// A helper for parsing and formatting numeric values.
interface NumericHelper {
// Adds thousands separators to the given numeric string.
addThousandsSeparator(numericString: string): string;
@@ -468,13 +693,10 @@ declare module Valerie {
// Unformats a numeric string; removes currency signs, thousands separators and normalises decimal separators.
unformat(numericString: string): string;
}
interface ValidationState {
// Finds and returns the validation states
// Finds and returns the validation states
findIn(model: any,
includeSubModels?: boolean,
recurse?: boolean,
@@ -486,18 +708,20 @@ declare module Valerie {
// nforms if the given model, observable or computed has a validation state.
has(modelOrObservableOrComputed: any): boolean;
// Sets the validation state for the given model, observable or computed.
setFor(modelOrObservableOrComputed: any, state: IValidationState): void;
}
interface summaryItem {
name: string;
message: string;
}
}
declare module Valerie.Rules {
/*
Todo: add classes in valerie.rules namespace
*/
}
}