diff options
Diffstat (limited to 'src/service')
| -rw-r--r-- | src/service/formFactory.js | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/src/service/formFactory.js b/src/service/formFactory.js deleted file mode 100644 index b051f7b9..00000000 --- a/src/service/formFactory.js +++ /dev/null @@ -1,414 +0,0 @@ -'use strict'; - -/** - * @ngdoc object - * @name angular.module.ng.$formFactory - * - * @description - * Use `$formFactory` to create a new instance of a {@link angular.module.ng.$formFactory.Form Form} - * controller or to find the nearest form instance for a given DOM element. - * - * The form instance is a collection of widgets, and is responsible for life cycle and validation - * of widget. - * - * Keep in mind that both form and widget instances are {@link api/angular.module.ng.$rootScope.Scope scopes}. - * - * @param {Form=} parentForm The form which should be the parent form of the new form controller. - * If none specified default to the `rootForm`. - * @returns {Form} A new {@link angular.module.ng.$formFactory.Form Form} instance. - * - * @example - * - * This example shows how one could write a widget which would enable data-binding on - * `contenteditable` feature of HTML. - * - <doc:example module="formModule"> - <doc:source> - <script> - function EditorCntl($scope) { - $scope.htmlContent = '<b>Hello</b> <i>World</i>!'; - } - - HTMLEditorWidget.$inject = ['$scope', '$element', '$sanitize']; - function HTMLEditorWidget(scope, element, $sanitize) { - scope.$parseModel = function() { - // need to protect for script injection - try { - scope.$viewValue = $sanitize( - scope.$modelValue || ''); - if (this.$error.HTML) { - // we were invalid, but now we are OK. - scope.$emit('$valid', 'HTML'); - } - } catch (e) { - // if HTML not parsable invalidate form. - scope.$emit('$invalid', 'HTML'); - } - } - - scope.$render = function() { - element.html(this.$viewValue); - } - - element.bind('keyup', function() { - scope.$apply(function() { - scope.$emit('$viewChange', element.html()); - }); - }); - } - - angular.module('formModule', [], function($compileProvider){ - $compileProvider.directive('ngHtmlEditorModel', function ($formFactory) { - return function(scope, element, attr) { - var form = $formFactory.forElement(element), - widget; - element.attr('contentEditable', true); - widget = form.$createWidget({ - scope: scope, - model: attr.ngHtmlEditorModel, - controller: HTMLEditorWidget, - controllerArgs: {$element: element}}); - // if the element is destroyed, then we need to - // notify the form. - element.bind('$destroy', function() { - widget.$destroy(); - }); - }; - }); - }); - </script> - <form name='editorForm' ng:controller="EditorCntl"> - <div ng:html-editor-model="htmlContent"></div> - <hr/> - HTML: <br/> - <textarea ng:model="htmlContent" cols="80"></textarea> - <hr/> - <pre>editorForm = {{editorForm|json}}</pre> - </form> - </doc:source> - <doc:scenario> - it('should enter invalid HTML', function() { - expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-valid/); - input('htmlContent').enter('<'); - expect(element('form[name=editorForm]').prop('className')).toMatch(/ng-invalid/); - }); - </doc:scenario> - </doc:example> - */ - -/** - * @ngdoc object - * @name angular.module.ng.$formFactory.Form - * @description - * The `Form` is a controller which keeps track of the validity of the widgets contained within it. - */ - -function $FormFactoryProvider() { - var $parse; - this.$get = ['$rootScope', '$parse', '$controller', - function($rootScope, $parse_, $controller) { - $parse = $parse_; - /** - * @ngdoc proprety - * @name rootForm - * @propertyOf angular.module.ng.$formFactory - * @description - * Static property on `$formFactory` - * - * Each application ({@link guide/dev_guide.scopes.internals root scope}) gets a root form which - * is the top-level parent of all forms. - */ - formFactory.rootForm = formFactory($rootScope); - - - /** - * @ngdoc method - * @name forElement - * @methodOf angular.module.ng.$formFactory - * @description - * Static method on `$formFactory` service. - * - * Retrieve the closest form for a given element or defaults to the `root` form. Used by the - * {@link angular.module.ng.$compileProvider.directive.form form} element. - * @param {Element} element The element where the search for form should initiate. - */ - formFactory.forElement = function(element) { - return element.inheritedData('$form') || formFactory.rootForm; - }; - return formFactory; - - function formFactory(parent) { - var scope = (parent || formFactory.rootForm).$new(); - $controller(FormController, {$scope: scope}); - return scope; - } - - }]; - - function propertiesUpdate(widget) { - widget.$valid = !(widget.$invalid = - !(widget.$readonly || widget.$disabled || equals(widget.$error, {}))); - } - - /** - * @ngdoc property - * @name $error - * @propertyOf angular.module.ng.$formFactory.Form - * @description - * Property of the form and widget instance. - * - * Summary of all of the errors on the page. If a widget emits `$invalid` with `REQUIRED` key, - * then the `$error` object will have a `REQUIRED` key with an array of widgets which have - * emitted this key. `form.$error.REQUIRED == [ widget ]`. - */ - - /** - * @ngdoc property - * @name $invalid - * @propertyOf angular.module.ng.$formFactory.Form - * @description - * Property of the form and widget instance. - * - * True if any of the widgets of the form are invalid. - */ - - /** - * @ngdoc property - * @name $valid - * @propertyOf angular.module.ng.$formFactory.Form - * @description - * Property of the form and widget instance. - * - * True if all of the widgets of the form are valid. - */ - - /** - * @ngdoc event - * @name angular.module.ng.$formFactory.Form#$valid - * @eventOf angular.module.ng.$formFactory.Form - * @eventType listen on form - * @description - * Upon receiving the `$valid` event from the widget update the `$error`, `$valid` and `$invalid` - * properties of both the widget as well as the from. - * - * @param {string} validationKey The validation key to be used when updating the `$error` object. - * The validation key is what will allow the template to bind to a specific validation error - * such as `<div ng:show="form.$error.KEY">error for key</div>`. - */ - - /** - * @ngdoc event - * @name angular.module.ng.$formFactory.Form#$invalid - * @eventOf angular.module.ng.$formFactory.Form - * @eventType listen on form - * @description - * Upon receiving the `$invalid` event from the widget update the `$error`, `$valid` and `$invalid` - * properties of both the widget as well as the from. - * - * @param {string} validationKey The validation key to be used when updating the `$error` object. - * The validation key is what will allow the template to bind to a specific validation error - * such as `<div ng:show="form.$error.KEY">error for key</div>`. - */ - - /** - * @ngdoc event - * @name angular.module.ng.$formFactory.Form#$validate - * @eventOf angular.module.ng.$formFactory.Form - * @eventType emit on widget - * @description - * Emit the `$validate` event on the widget, giving a widget a chance to emit a - * `$valid` / `$invalid` event base on its state. The `$validate` event is triggered when the - * model or the view changes. - */ - - /** - * @ngdoc event - * @name angular.module.ng.$formFactory.Form#$viewChange - * @eventOf angular.module.ng.$formFactory.Form - * @eventType listen on widget - * @description - * A widget is responsible for emitting this event whenever the view changes do to user interaction. - * The event takes a `$viewValue` parameter, which is the new value of the view. This - * event triggers a call to `$parseView()` as well as `$validate` event on widget. - * - * @param {*} viewValue The new value for the view which will be assigned to `widget.$viewValue`. - */ - - FormController.$inject = ['$scope', '$injector']; - function FormController($scope, $injector) { - this.$injector = $injector; - - var form = this.form = $scope, - $error = form.$error = {}; - - form.$on('$destroy', function(event){ - var widget = event.targetScope; - if (widget.$widgetId) { - delete form[widget.$widgetId]; - } - forEach($error, removeWidget, widget); - }); - - form.$on('$valid', function(event, error){ - var widget = event.targetScope; - delete widget.$error[error]; - propertiesUpdate(widget); - removeWidget($error[error], error, widget); - }); - - form.$on('$invalid', function(event, error){ - var widget = event.targetScope; - addWidget(error, widget); - widget.$error[error] = true; - propertiesUpdate(widget); - }); - - propertiesUpdate(form); - form.$createWidget = bind(this, this.$createWidget); - - function removeWidget(queue, errorKey, widget) { - if (queue) { - widget = widget || this; // so that we can be used in forEach; - for (var i = 0, length = queue.length; i < length; i++) { - if (queue[i] === widget) { - queue.splice(i, 1); - if (!queue.length) { - delete $error[errorKey]; - } - } - } - propertiesUpdate(form); - } - } - - function addWidget(errorKey, widget) { - var queue = $error[errorKey]; - if (queue) { - for (var i = 0, length = queue.length; i < length; i++) { - if (queue[i] === widget) { - return; - } - } - } else { - $error[errorKey] = queue = []; - } - queue.push(widget); - propertiesUpdate(form); - } - } - - - /** - * @ngdoc method - * @name $createWidget - * @methodOf angular.module.ng.$formFactory.Form - * @description - * - * Use form's `$createWidget` instance method to create new widgets. The widgets can be created - * using an alias which makes the accessible from the form and available for data-binding, - * useful for displaying validation error messages. - * - * The creation of a widget sets up: - * - * - `$watch` of `expression` on `model` scope. This code path syncs the model to the view. - * The `$watch` listener will: - * - * - assign the new model value of `expression` to `widget.$modelValue`. - * - call `widget.$parseModel` method if present. The `$parseModel` is responsible for copying - * the `widget.$modelValue` to `widget.$viewValue` and optionally converting the data. - * (For example to convert a number into string) - * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid` - * event. - * - call `widget.$render()` method on widget. The `$render` method is responsible for - * reading the `widget.$viewValue` and updating the DOM. - * - * - Listen on `$viewChange` event from the `widget`. This code path syncs the view to the model. - * The `$viewChange` listener will: - * - * - assign the value to `widget.$viewValue`. - * - call `widget.$parseView` method if present. The `$parseView` is responsible for copying - * the `widget.$viewValue` to `widget.$modelValue` and optionally converting the data. - * (For example to convert a string into number) - * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid` - * event. - * - Assign the `widget.$modelValue` to the `expression` on the `model` scope. - * - * - Creates these set of properties on the `widget` which are updated as a response to the - * `$valid` / `$invalid` events: - * - * - `$error` - object - validation errors will be published as keys on this object. - * Data-binding to this property is useful for displaying the validation errors. - * - `$valid` - boolean - true if there are no validation errors - * - `$invalid` - boolean - opposite of `$valid`. - * @param {Object} params Named parameters: - * - * - `scope` - `{Scope}` - The scope to which the model for this widget is attached. - * - `model` - `{string}` - The name of the model property on model scope. - * - `controller` - {WidgetController} - The controller constructor function. - * The controller constructor should create these instance methods. - * - `$parseView()`: optional method responsible for copying `$viewVale` to `$modelValue`. - * The method may fire `$valid`/`$invalid` events. - * - `$parseModel()`: optional method responsible for copying `$modelVale` to `$viewValue`. - * The method may fire `$valid`/`$invalid` events. - * - `$render()`: required method which needs to update the DOM of the widget to match the - * `$viewValue`. - * - * - `controllerArgs` - `{Array}` (Optional) - Any extra arguments will be curried to the - * WidgetController constructor. - * - `onChange` - `{(string|function())}` (Optional) - Expression to execute when user changes the - * value. - * - `alias` - `{string}` (Optional) - The name of the form property under which the widget - * instance should be published. The name should be unique for each form. - * @returns {Widget} Instance of a widget scope. - */ - FormController.prototype.$createWidget = function(params) { - var form = this.form, - modelScope = params.scope, - onChange = params.onChange, - alias = params.alias, - scopeGet = $parse(params.model), - scopeSet = scopeGet.assign, - widget = form.$new(); - - this.$injector.instantiate(params.controller, extend({$scope: widget}, params.controllerArgs)); - - if (!scopeSet) { - throw Error("Expression '" + params.model + "' is not assignable!"); - } - - widget.$error = {}; - // Set the state to something we know will change to get the process going. - widget.$modelValue = Number.NaN; - // watch for scope changes and update the view appropriately - modelScope.$watch(scopeGet, function(value) { - if (!equals(widget.$modelValue, value)) { - widget.$modelValue = value; - widget.$parseModel ? widget.$parseModel() : (widget.$viewValue = value); - widget.$emit('$validate'); - widget.$render && widget.$render(); - } - }); - - widget.$on('$viewChange', function(event, viewValue){ - if (!equals(widget.$viewValue, viewValue)) { - widget.$viewValue = viewValue; - widget.$parseView ? widget.$parseView() : (widget.$modelValue = widget.$viewValue); - scopeSet(modelScope, widget.$modelValue); - if (onChange) modelScope.$eval(onChange); - widget.$emit('$validate'); - } - }); - - propertiesUpdate(widget); - - // assign the widgetModel to the form - if (alias && !form.hasOwnProperty(alias)) { - form[alias] = widget; - widget.$widgetId = alias; - } else { - alias = null; - } - - return widget; - }; -} |
