[Forms] Copy mct-form to mct-toolbar

Copy mct-form template and scripts to use as a basis
for mct-toolbar. WTD-684.
This commit is contained in:
Victor Woeltjen 2015-01-15 14:23:01 -08:00
parent 244583b2f7
commit aed6787f2c
4 changed files with 200 additions and 0 deletions

View File

@ -7,6 +7,10 @@
"key": "mctForm",
"implementation": "MCTForm.js"
},
{
"key": "mctToolbar",
"implementation": "MCTToolbar.js"
},
{
"key": "mctControl",
"implementation": "MCTControl.js",

View File

@ -0,0 +1,42 @@
<form name="mctForm" novalidate>
<div class="form">
<span ng-repeat="section in structure.sections">
<div class="section-header" ng-if="section.name">
{{section.name}}
</div>
<div class="form-section">
<ng-form name="mctFormInner" ng-repeat="row in section.rows">
<div class="form-row validates"
ng-class="{
req: row.required,
valid: mctFormInner.$dirty && mctFormInner.$valid,
invalid: mctFormInner.$dirty && !mctFormInner.$valid
}">
<div class='label' title="{{row.description}}">
{{row.name}}
<span ng-if="row.description"
class="ui-symbol">
i
</span>
</div>
<div class='controls'>
<div class="wrapper" ng-if="row.control">
<mct-control key="row.control"
ng-model="ngModel"
ng-required="row.required"
ng-pattern="getRegExp(row.pattern)"
options="row.options"
structure="row"
field="row.key">
</mct-control>
</div>
</div>
</div>
</ng-form>
</div>
</span>
</div>
</form>

View 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;
}
);

View 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/);
});
});
}
);