mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 13:43:09 +00:00
Merge branch 'open-master' into open702
Merge latest from master branch into topic branch for separating out Couch adapter from persistence cache, in support of reusing the latter for the WARP persistence adapter, WTD-702.
This commit is contained in:
commit
3df82775b5
@ -1,4 +1,7 @@
|
||||
<div ng-controller="ExampleFormController">
|
||||
<mct-toolbar structure="toolbar" ng-model="state" name="aToolbar">
|
||||
</mct-toolbar>
|
||||
|
||||
<mct-form structure="form" ng-model="state" name="aForm">
|
||||
</mct-form>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*global define*/
|
||||
/*global define,window*/
|
||||
|
||||
define(
|
||||
[],
|
||||
@ -10,6 +10,89 @@ define(
|
||||
|
||||
};
|
||||
|
||||
$scope.toolbar = {
|
||||
name: "An example toolbar.",
|
||||
sections: [
|
||||
{
|
||||
description: "First section",
|
||||
items: [
|
||||
{
|
||||
name: "X",
|
||||
description: "X coordinate",
|
||||
control: "textfield",
|
||||
pattern: "^\\d+$",
|
||||
disabled: true,
|
||||
size: 2,
|
||||
key: "x"
|
||||
},
|
||||
{
|
||||
name: "Y",
|
||||
description: "Y coordinate",
|
||||
control: "textfield",
|
||||
pattern: "^\\d+$",
|
||||
size: 2,
|
||||
key: "y"
|
||||
},
|
||||
{
|
||||
name: "W",
|
||||
description: "Cell width",
|
||||
control: "textfield",
|
||||
pattern: "^\\d+$",
|
||||
size: 2,
|
||||
key: "w"
|
||||
},
|
||||
{
|
||||
name: "H",
|
||||
description: "Cell height",
|
||||
control: "textfield",
|
||||
pattern: "^\\d+$",
|
||||
size: 2,
|
||||
key: "h"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
description: "Second section",
|
||||
items: [
|
||||
{
|
||||
control: "button",
|
||||
glyph: "1",
|
||||
description: "Button A",
|
||||
click: function () {
|
||||
window.alert("A");
|
||||
}
|
||||
},
|
||||
{
|
||||
control: "button",
|
||||
glyph: "2",
|
||||
description: "Button B",
|
||||
click: function () {
|
||||
window.alert("B");
|
||||
}
|
||||
},
|
||||
{
|
||||
control: "button",
|
||||
glyph: "3",
|
||||
description: "Button C",
|
||||
disabled: true,
|
||||
click: function () {
|
||||
window.alert("C");
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
{
|
||||
control: "color",
|
||||
key: "color"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
$scope.form = {
|
||||
name: "An example form.",
|
||||
sections: [
|
||||
|
@ -73,7 +73,7 @@
|
||||
{
|
||||
"key": "ViewSwitcherController",
|
||||
"implementation": "controllers/ViewSwitcherController.js",
|
||||
"depends": [ "$scope" ]
|
||||
"depends": [ "$scope", "$timeout" ]
|
||||
},
|
||||
{
|
||||
"key": "BottomBarController",
|
||||
|
@ -13,7 +13,7 @@ define(
|
||||
* of applicable views for a represented domain object.
|
||||
* @constructor
|
||||
*/
|
||||
function ViewSwitcherController($scope) {
|
||||
function ViewSwitcherController($scope, $timeout) {
|
||||
// If the view capability gets refreshed, try to
|
||||
// keep the same option chosen.
|
||||
function findMatchingOption(options, selected) {
|
||||
@ -32,10 +32,12 @@ define(
|
||||
|
||||
// Get list of views, read from capability
|
||||
function updateOptions(views) {
|
||||
$scope.ngModel.selected = findMatchingOption(
|
||||
views || [],
|
||||
($scope.ngModel || {}).selected
|
||||
);
|
||||
$timeout(function () {
|
||||
$scope.ngModel.selected = findMatchingOption(
|
||||
views || [],
|
||||
($scope.ngModel || {}).selected
|
||||
);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Update view options when the in-scope results of using the
|
||||
|
@ -10,12 +10,15 @@ define(
|
||||
|
||||
describe("The view switcher controller", function () {
|
||||
var mockScope,
|
||||
mockTimeout,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", [ "$watch" ]);
|
||||
mockTimeout = jasmine.createSpy("$timeout");
|
||||
mockTimeout.andCallFake(function (cb) { cb(); });
|
||||
mockScope.ngModel = {};
|
||||
controller = new ViewSwitcherController(mockScope);
|
||||
controller = new ViewSwitcherController(mockScope, mockTimeout);
|
||||
});
|
||||
|
||||
it("watches for changes in applicable views", function () {
|
||||
@ -71,6 +74,19 @@ define(
|
||||
expect(mockScope.ngModel.selected).not.toEqual(views[1]);
|
||||
});
|
||||
|
||||
// Use of a timeout avoids infinite digest problems when deeply
|
||||
// nesting switcher-driven views (e.g. in a layout.) See WTD-689
|
||||
it("updates initial selection on a timeout", function () {
|
||||
// Verify precondition
|
||||
expect(mockTimeout).not.toHaveBeenCalled();
|
||||
|
||||
// Invoke the watch for set of views
|
||||
mockScope.$watch.mostRecentCall.args[1]([]);
|
||||
|
||||
// Should have run on a timeout
|
||||
expect(mockTimeout).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -12,6 +12,11 @@ directive, e.g.:
|
||||
<mct-form ng-model="myModel" structure="myStructure" name="myForm">
|
||||
</mct-form>
|
||||
|
||||
Using toolbars is similar:
|
||||
|
||||
<mct-toolbar ng-model="myModel" structure="myStructure" name="myToolbar">
|
||||
</mct-toolbar>
|
||||
|
||||
The attributes utilized by this form are as follows:
|
||||
|
||||
* `ng-model`: The object which should contain the full form input. Individual
|
||||
@ -55,6 +60,44 @@ Note that `pattern` may be specified as a string, to simplify storing
|
||||
for structures as JSON when necessary. The string should be given in
|
||||
a form appropriate to pass to a `RegExp` constructor.
|
||||
|
||||
## Toolbar structure
|
||||
|
||||
A toolbar's structure is described similarly to forms, except that there
|
||||
is no notion of rows; instead, there are `items`.
|
||||
|
||||
{
|
||||
"name": ... title to display for the form, as a string ...,
|
||||
"sections": [
|
||||
{
|
||||
"name": ... title to display for the section ...,
|
||||
"items": [
|
||||
{
|
||||
"name": ... title to display for this row ...,
|
||||
"control": ... symbolic key for the control ...,
|
||||
"key": ... field name in ng-model ...
|
||||
"pattern": ... optional, reg exp to match against ...
|
||||
"required": ... optional boolean ...
|
||||
"options": [
|
||||
"name": ... name to display (e.g. in a select) ...,
|
||||
"value": ... value to store in the model ...
|
||||
],
|
||||
"disabled": ... true if control should be disabled ...
|
||||
"size": ... size of the control (for textfields) ...
|
||||
"click": ... function to invoke (for buttons) ...
|
||||
"glyph": ... glyph to display (for buttons) ...
|
||||
"text": ... text withiin control (for buttons) ...
|
||||
},
|
||||
... and other rows ...
|
||||
]
|
||||
},
|
||||
... and other sections ...
|
||||
]
|
||||
}
|
||||
|
||||
Note that `pattern` may be specified as a string, to simplify storing
|
||||
for structures as JSON when necessary. The string should be given in
|
||||
a form appropriate to pass to a `RegExp` constructor.
|
||||
|
||||
## Adding controls
|
||||
|
||||
Four standard control types are included in the forms bundle:
|
||||
@ -62,6 +105,8 @@ Four standard control types are included in the forms bundle:
|
||||
* `textfield`: An area to enter plain text.
|
||||
* `select`: A drop-down list of options.
|
||||
* `checkbox`: A box which may be checked/unchecked.
|
||||
* `color`: A color picker.
|
||||
* `button`: A button.
|
||||
* `datetime`: An input for UTC date/time entry; gives result as a
|
||||
UNIX timestamp, in milliseconds since start of 1970, UTC.
|
||||
|
||||
|
@ -7,6 +7,10 @@
|
||||
"key": "mctForm",
|
||||
"implementation": "MCTForm.js"
|
||||
},
|
||||
{
|
||||
"key": "mctToolbar",
|
||||
"implementation": "MCTToolbar.js"
|
||||
},
|
||||
{
|
||||
"key": "mctControl",
|
||||
"implementation": "MCTControl.js",
|
||||
@ -30,6 +34,14 @@
|
||||
"key": "textfield",
|
||||
"templateUrl": "templates/controls/textfield.html"
|
||||
},
|
||||
{
|
||||
"key": "button",
|
||||
"templateUrl": "templates/controls/button.html"
|
||||
},
|
||||
{
|
||||
"key": "color",
|
||||
"templateUrl": "templates/controls/color.html"
|
||||
},
|
||||
{
|
||||
"key": "composite",
|
||||
"templateUrl": "templates/controls/composite.html"
|
||||
@ -45,36 +57,6 @@
|
||||
"key": "CompositeController",
|
||||
"implementation": "controllers/CompositeController.js"
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"key": "_checkbox",
|
||||
"templateUrl": "templates/_checkbox.html"
|
||||
},
|
||||
{
|
||||
"key": "_checkboxes",
|
||||
"templateUrl": "templates/_checkboxes.html"
|
||||
},
|
||||
{
|
||||
"key": "_datetime",
|
||||
"templateUrl": "templates/_datetime.html"
|
||||
},
|
||||
{
|
||||
"key": "_select",
|
||||
"templateUrl": "templates/_select.html"
|
||||
},
|
||||
{
|
||||
"key": "_selects",
|
||||
"templateUrl": "templates/_selects.html"
|
||||
},
|
||||
{
|
||||
"key": "_textfield",
|
||||
"templateUrl": "templates/_textfield.html"
|
||||
},
|
||||
{
|
||||
"key": "_textfields",
|
||||
"templateUrl": "templates/_textfields.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
11
platform/forms/res/templates/controls/button.html
Normal file
11
platform/forms/res/templates/controls/button.html
Normal file
@ -0,0 +1,11 @@
|
||||
<a href=""
|
||||
class="t-btn l-btn s-btn s-icon-btn s-very-subtle"
|
||||
ng-class="{ labeled: structure.text }"
|
||||
ng-click="structure.click()">
|
||||
<span class="ui-symbol icon">
|
||||
{{structure.glyph}}
|
||||
</span>
|
||||
<span class="title-label" ng-if="structure.text">
|
||||
{{structure.text}}
|
||||
</span>
|
||||
</a>
|
3
platform/forms/res/templates/controls/color.html
Normal file
3
platform/forms/res/templates/controls/color.html
Normal file
@ -0,0 +1,3 @@
|
||||
<input type="color"
|
||||
name="mctControl"
|
||||
ng-model="ngModel[field]">
|
@ -4,6 +4,7 @@
|
||||
ng-required="ngRequired"
|
||||
ng-model="ngModel[field]"
|
||||
ng-pattern="ngPattern"
|
||||
size="{{structure.size}}"
|
||||
name="mctControl">
|
||||
</span>
|
||||
</span>
|
||||
|
32
platform/forms/res/templates/toolbar.html
Normal file
32
platform/forms/res/templates/toolbar.html
Normal file
@ -0,0 +1,32 @@
|
||||
<form name="tool-bar btn-bar contents" novalidate>
|
||||
|
||||
<div class="form">
|
||||
<span ng-repeat="section in structure.sections"
|
||||
class="control-group coordinates"
|
||||
title="{{section.description}}">
|
||||
|
||||
<ng-form ng-repeat="item in section.items"
|
||||
ng-class="{ 'input-labeled': item.name }"
|
||||
class="inline"
|
||||
title="{{item.description}}"
|
||||
name="mctFormInner">
|
||||
|
||||
<label ng-if="item.name">
|
||||
{{item.name}}:
|
||||
</label>
|
||||
<mct-control key="item.control"
|
||||
ng-class="{ disabled: item.disabled }"
|
||||
ng-model="ngModel"
|
||||
ng-required="item.required"
|
||||
ng-pattern="getRegExp(item.pattern)"
|
||||
options="item.options"
|
||||
structure="item"
|
||||
field="item.key">
|
||||
</mct-control>
|
||||
|
||||
</ng-form>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</form>
|
@ -4,13 +4,10 @@
|
||||
* Module defining MCTForm. Created by vwoeltje on 11/10/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
["./controllers/FormController"],
|
||||
function (FormController) {
|
||||
"use strict";
|
||||
|
||||
// Default ng-pattern; any non whitespace
|
||||
var NON_WHITESPACE = /\S/;
|
||||
|
||||
/**
|
||||
* The mct-form directive allows generation of displayable
|
||||
* forms based on a declarative description of the form's
|
||||
@ -37,45 +34,6 @@ define(
|
||||
"templates/form.html"
|
||||
].join("/");
|
||||
|
||||
function controller($scope) {
|
||||
var regexps = [];
|
||||
|
||||
// ng-pattern seems to want a RegExp, and not a
|
||||
// string (despite what documentation says) but
|
||||
// we want form structure to be JSON-expressible,
|
||||
// so we make RegExp's from strings as-needed
|
||||
function getRegExp(pattern) {
|
||||
// If undefined, don't apply a pattern
|
||||
if (!pattern) {
|
||||
return NON_WHITESPACE;
|
||||
}
|
||||
|
||||
// Just echo if it's already a regexp
|
||||
if (pattern instanceof RegExp) {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// Otherwise, assume a string
|
||||
// Cache for easy lookup later (so we don't
|
||||
// creat a new RegExp every digest cycle)
|
||||
if (!regexps[pattern]) {
|
||||
regexps[pattern] = new RegExp(pattern);
|
||||
}
|
||||
|
||||
return regexps[pattern];
|
||||
}
|
||||
|
||||
// Publish the form state under the requested
|
||||
// name in the parent scope
|
||||
$scope.$watch("mctForm", function (mctForm) {
|
||||
if ($scope.name) {
|
||||
$scope.$parent[$scope.name] = mctForm;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.getRegExp = getRegExp;
|
||||
}
|
||||
|
||||
return {
|
||||
// Only show at the element level
|
||||
restrict: "E",
|
||||
@ -83,9 +41,8 @@ define(
|
||||
// Load the forms template
|
||||
templateUrl: templatePath,
|
||||
|
||||
// Use the controller defined above to
|
||||
// populate/respond to changes in scope
|
||||
controller: controller,
|
||||
// Use FormController to populate/respond to changes in scope
|
||||
controller: FormController,
|
||||
|
||||
// Initial an isolate scope
|
||||
scope: {
|
||||
|
64
platform/forms/src/MCTToolbar.js
Normal file
64
platform/forms/src/MCTToolbar.js
Normal file
@ -0,0 +1,64 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining MCTForm. Created by vwoeltje on 11/10/14.
|
||||
*/
|
||||
define(
|
||||
["./controllers/FormController"],
|
||||
function (FormController) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The mct-toolbar directive allows generation of displayable
|
||||
* forms based on a declarative description of the form's
|
||||
* structure.
|
||||
*
|
||||
* This directive accepts three attributes:
|
||||
*
|
||||
* * `ng-model`: The model for the form; where user input
|
||||
* where be stored.
|
||||
* * `structure`: The declarative structure of the toolbar.
|
||||
* Describes what controls should be shown and where
|
||||
* their values should be read/written in the model.
|
||||
* * `name`: The name under which to expose the form's
|
||||
* dirty/valid state. This is similar to ng-form's use
|
||||
* of name, except this will be made available in the
|
||||
* parent scope.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTForm() {
|
||||
var templatePath = [
|
||||
"platform/forms", //MCTForm.bundle.path,
|
||||
"res", //MCTForm.bundle.resources,
|
||||
"templates/toolbar.html"
|
||||
].join("/");
|
||||
|
||||
return {
|
||||
// Only show at the element level
|
||||
restrict: "E",
|
||||
|
||||
// Load the forms template
|
||||
templateUrl: templatePath,
|
||||
|
||||
// Use FormController to populate/respond to changes in scope
|
||||
controller: FormController,
|
||||
|
||||
// Initial an isolate scope
|
||||
scope: {
|
||||
|
||||
// The model: Where form input will actually go
|
||||
ngModel: "=",
|
||||
|
||||
// Form structure; what sections/rows to show
|
||||
structure: "=",
|
||||
|
||||
// Name under which to publish the form
|
||||
name: "@"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTForm;
|
||||
}
|
||||
);
|
57
platform/forms/src/controllers/FormController.js
Normal file
57
platform/forms/src/controllers/FormController.js
Normal file
@ -0,0 +1,57 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
// Default ng-pattern; any non whitespace
|
||||
var NON_WHITESPACE = /\S/;
|
||||
|
||||
/**
|
||||
* Controller for mct-form and mct-toolbar directives.
|
||||
* @constructor
|
||||
*/
|
||||
function FormController($scope) {
|
||||
var regexps = [];
|
||||
|
||||
// ng-pattern seems to want a RegExp, and not a
|
||||
// string (despite what documentation says) but
|
||||
// we want form structure to be JSON-expressible,
|
||||
// so we make RegExp's from strings as-needed
|
||||
function getRegExp(pattern) {
|
||||
// If undefined, don't apply a pattern
|
||||
if (!pattern) {
|
||||
return NON_WHITESPACE;
|
||||
}
|
||||
|
||||
// Just echo if it's already a regexp
|
||||
if (pattern instanceof RegExp) {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// Otherwise, assume a string
|
||||
// Cache for easy lookup later (so we don't
|
||||
// creat a new RegExp every digest cycle)
|
||||
if (!regexps[pattern]) {
|
||||
regexps[pattern] = new RegExp(pattern);
|
||||
}
|
||||
|
||||
return regexps[pattern];
|
||||
}
|
||||
|
||||
// Publish the form state under the requested
|
||||
// name in the parent scope
|
||||
$scope.$watch("mctForm", function (mctForm) {
|
||||
if ($scope.name) {
|
||||
$scope.$parent[$scope.name] = mctForm;
|
||||
}
|
||||
});
|
||||
|
||||
// Expose the regexp lookup
|
||||
$scope.getRegExp = getRegExp;
|
||||
}
|
||||
|
||||
return FormController;
|
||||
}
|
||||
);
|
90
platform/forms/test/MCTToolbarSpec.js
Normal file
90
platform/forms/test/MCTToolbarSpec.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../src/MCTToolbar"],
|
||||
function (MCTToolbar) {
|
||||
"use strict";
|
||||
|
||||
describe("The mct-toolbar directive", function () {
|
||||
var mockScope,
|
||||
mctToolbar;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", [ "$watch" ]);
|
||||
mockScope.$parent = {};
|
||||
mctToolbar = new MCTToolbar();
|
||||
});
|
||||
|
||||
it("is restricted to elements", function () {
|
||||
expect(mctToolbar.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
it("watches for changes in form by name", function () {
|
||||
// mct-form needs to watch for the form by name
|
||||
// in order to convey changes in $valid, $dirty, etc
|
||||
// up to the parent scope.
|
||||
mctToolbar.controller(mockScope);
|
||||
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"mctForm",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("conveys form status to parent scope", function () {
|
||||
var someState = { someKey: "some value" };
|
||||
mockScope.name = "someName";
|
||||
|
||||
mctToolbar.controller(mockScope);
|
||||
|
||||
mockScope.$watch.mostRecentCall.args[1](someState);
|
||||
|
||||
expect(mockScope.$parent.someName).toBe(someState);
|
||||
});
|
||||
|
||||
it("allows strings to be converted to RegExps", function () {
|
||||
// This is needed to support ng-pattern in the template
|
||||
mctToolbar.controller(mockScope);
|
||||
|
||||
// Should have added getRegExp to the scope,
|
||||
// to convert strings to regular expressions
|
||||
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
|
||||
});
|
||||
|
||||
it("returns the same regexp instance for the same string", function () {
|
||||
// Don't want new instances each digest cycle, for performance
|
||||
var strRegExp = "^[a-z]\\d+$",
|
||||
regExp;
|
||||
|
||||
// Add getRegExp to scope
|
||||
mctToolbar.controller(mockScope);
|
||||
regExp = mockScope.getRegExp(strRegExp);
|
||||
|
||||
// Same object instance each time...
|
||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||
});
|
||||
|
||||
it("passes RegExp objects through untouched", function () {
|
||||
// Permit using forms to simply provide their own RegExp object
|
||||
var regExp = /^\d+[a-d]$/;
|
||||
|
||||
// Add getRegExp to scope
|
||||
mctToolbar.controller(mockScope);
|
||||
|
||||
// Should have added getRegExp to the scope,
|
||||
// to convert strings to regular expressions
|
||||
expect(mockScope.getRegExp(regExp)).toBe(regExp);
|
||||
});
|
||||
|
||||
it("passes a non-whitespace regexp when no pattern is defined", function () {
|
||||
// If no pattern is supplied, ng-pattern should match anything
|
||||
mctToolbar.controller(mockScope);
|
||||
expect(mockScope.getRegExp()).toEqual(/\S/);
|
||||
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
69
platform/forms/test/controllers/FormControllerSpec.js
Normal file
69
platform/forms/test/controllers/FormControllerSpec.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*global define,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
|
||||
define(
|
||||
["../../src/controllers/FormController"],
|
||||
function (FormController) {
|
||||
"use strict";
|
||||
|
||||
describe("The form controller", function () {
|
||||
var mockScope,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", [ "$watch" ]);
|
||||
mockScope.$parent = {};
|
||||
controller = new FormController(mockScope);
|
||||
});
|
||||
|
||||
it("watches for changes in form by name", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"mctForm",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("conveys form status to parent scope", function () {
|
||||
var someState = { someKey: "some value" };
|
||||
mockScope.name = "someName";
|
||||
mockScope.$watch.mostRecentCall.args[1](someState);
|
||||
expect(mockScope.$parent.someName).toBe(someState);
|
||||
});
|
||||
|
||||
it("allows strings to be converted to RegExps", function () {
|
||||
// Should have added getRegExp to the scope,
|
||||
// to convert strings to regular expressions
|
||||
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
|
||||
});
|
||||
|
||||
it("returns the same regexp instance for the same string", function () {
|
||||
// Don't want new instances each digest cycle, for performance
|
||||
var strRegExp = "^[a-z]\\d+$",
|
||||
regExp;
|
||||
|
||||
// Add getRegExp to scope
|
||||
regExp = mockScope.getRegExp(strRegExp);
|
||||
|
||||
// Same object instance each time...
|
||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||
});
|
||||
|
||||
it("passes RegExp objects through untouched", function () {
|
||||
// Permit using forms to simply provide their own RegExp object
|
||||
var regExp = /^\d+[a-d]$/;
|
||||
|
||||
// Should have added getRegExp to the scope,
|
||||
// to convert strings to regular expressions
|
||||
expect(mockScope.getRegExp(regExp)).toBe(regExp);
|
||||
});
|
||||
|
||||
it("passes a non-whitespace regexp when no pattern is defined", function () {
|
||||
// If no pattern is supplied, ng-pattern should match anything
|
||||
expect(mockScope.getRegExp()).toEqual(/\S/);
|
||||
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -2,5 +2,6 @@
|
||||
"MCTControl",
|
||||
"MCTForm",
|
||||
"controllers/CompositeController",
|
||||
"controllers/DateTimeController"
|
||||
"controllers/DateTimeController",
|
||||
"controllers/FormController"
|
||||
]
|
Loading…
Reference in New Issue
Block a user