Source: directive/form.js

/**
 * General config of ngForm used throughout the site.
 * @module
 */
'use strict';

app.directive('ngForm', [
  '$route', '$timeout', '$animate', 'constantService', 'messageService',
  function ($route, $timeout, $animate, constants, messages) {
    var pre = function ($scope, $element, $attrs) {
      var name = $attrs.name || $attrs.ngForm;
      var form = name && $scope.$eval(name);
      if (!form)
        return;

      form.$element = $element;

      var controls = [];

      /**
     * Check if the form is dirty.
     * @interface form/checkDirty
     */
      function checkDirty() {
        if (!(form.$dirty || form.$submitted) || controls.some(function (control) {
            return control.$dirty;
          }))
            return;
        /* effectively call form.$setPristine, without the child controls. */
        $animate.setClass($element, 'ng-pristine', 'ng-dirty ng-submitted');
        form.$dirty = false;
        form.$pristine = true;
        form.$submitted = false;
        if (form.$$parentForm.subformControl)
          form.$$parentForm.subformControl.$setPristine();
      }

      /**
     * Set the form state back to its unsubmitted state.
     * @interface form/$setUnsubmitted
     */
      form.$setUnsubmitted = function () {
        if (!form.$submitted || controls.some(function (control) {
          return control.$submitted;
        }))
          return;
        $animate.removeClass($element, 'ng-submitted');
        form.$submitted = false;
        if (form.$$parentForm.$setUnsubmitted)
          form.$$parentForm.$setUnsubmitted();
      };

      var $addControl = form.$addControl;
      var $removeControl = form.$removeControl;

      /* this is unfortunate, just because we can't access the existing controls list. */
      form.$addControl = function (control) {
        if ('$pristine' in control)
          controls.push(control);
        return $addControl(control);
      };

      form.$removeControl = function (control) {
        controls.remove(control);
        checkDirty();
        return $removeControl(control);
      };

      form.subformControl = {
        $setPristine: checkDirty
      };

      if ('isolate' in $attrs) {
        form.$$parentForm.$removeControl(form);
        form.$setDirty = function() {
          $animate.removeClass($element, 'ng-pristine');
          $animate.addClass($element, 'ng-dirty');
          form.$dirty = true;
          form.$pristine = false;
        };
      }
      /* it'd be nicer to handle this in $addControl, but it happens too early */
      else if (form.$$parentForm.subformControl)
        form.$addControl(form.$$parentForm.subformControl);

      var unclaimed = {};
      form.validators = {};
      form.validator = {
        server: function (res, replace) {
          messages.clear(form);
          if ($.isEmptyObject(res)) {
            res.data = {};
          } else if (!angular.isObject(res.data)) {
            messages.addError({
              body: constants.message('error.generic'),
              report: res,
              owner: form
            });
            return;
          }

          var errors = messages.foreachError(res.data);
          var name;
          for (name in form.validators) {
            form.validators[name].server(errors[name] || [], replace);
            delete errors[name];
          }

          for (name in errors)
            messages.add({
              type: 'red',
              body: errors[name].join('; '),
              owner: form
            });
        },

        clearServer: function () {
          _.each(form.validators, function (validator) {
            validator.server({}, true);
          });
        },

        client: function (data, replace) {
          for (var name in data) {
            if (!data.hasOwnProperty(name)) {
              continue;
            } else if (form.validators[name]) {
              form.validators[name].client(data[name], replace);
            } else {
              unclaimed[name] = data[name];
            }
          }
        },

        add: function (name, validator) {
          form.validators[name] = validator;

          if (unclaimed[name]) {
            validator.client(unclaimed[name], true);
            delete unclaimed[name];
          }
        },
      };

      /**
     * Pop up a JS confirm dialogue to ask if the user is sure to abandon changes without submitting the form.
     * @interface form/resetAll
     */
      form.resetAll = function (force, check) {
        if (!(force || form.$pristine)) {
          if (!(confirm(constants.message('navigation.confirmation')))) {
            window.dataLayer.push({
              'event': 'gtm.confirm',
              'gtm.confirmAction': 'cancel'
            });
            return false;
          } else {
            window.dataLayer.push({
              'event': 'gtm.confirm',
              'gtm.confirmAction': 'ok'
            });
          }
        } 
        if (check)
          return true;
        var x = window.pageXOffset,
            y = window.pageYOffset;
        $route.reload();
        $timeout(function () {
          window.scrollTo(x, y);
        });
        return true;
      };
    };

    return {
      restrict: 'EA',
      link: {
        pre: pre
      }
    };
  }
]);