text: /*
  editableFactory is used to generate editable directives (see `/directives` folder)
  Inside it does several things:
  - detect form for editable element. Form may be one of three types:
    1. autogenerated form (for single editable elements)
    2. wrapper form (element wrapped by <form> tag)
    3. linked form (element has `e-form` attribute pointing to existing form)
  
  - attach editableController to element
  
  Depends on: editableController, editableFormFactory
  */
  angular.module('xeditable').factory('editableDirectiveFactory',
  ['$parse', '$compile', 'editableThemes', '$rootScope', '$document', 'editableController', 'editableFormController', 'editableOptions',
  function($parse, $compile, editableThemes, $rootScope, $document, editableController, editableFormController, editableOptions) {
  
    //directive object
    return function(overwrites) {
      return {
        restrict: 'A',
        scope: true,
        require: [overwrites.directiveName, '?^form'],
        controller: editableController,
        link: function(scope, elem, attrs, ctrl) {
          // editable controller
          var eCtrl = ctrl[0];
  
          // form controller
          var eFormCtrl;
  
          // this variable indicates is element is bound to some existing form, 
          // or it's single element who's form will be generated automatically
          // By default consider single element without any linked form.ß
          var hasForm = false;
       
          // element wrapped by form
          if(ctrl[1]) {
            eFormCtrl = ctrl[1];
            hasForm = attrs.eSingle === undefined;
          } else if(attrs.eForm) { // element not wrapped by <form>, but we hane `e-form` attr
            var getter = $parse(attrs.eForm)(scope);
            if(getter) { // form exists in scope (above), e.g. editable column
              eFormCtrl = getter;
              hasForm = true;
            } else { // form exists below or not exist at all: check document.forms
              for(var i=0; i<$document[0].forms.length;i++){
                if($document[0].forms[i].name === attrs.eForm) {
                  // form is below and not processed yet
                  eFormCtrl = null;
                  hasForm = true;
                  break;
                }
              }
            }
          }
  
          /*
          if(hasForm && !attrs.eName) {
            throw 'You should provide `e-name` for editable element inside form!';
          }
          */
  
          //check for `editable-form` attr in form
          /*
          if(eFormCtrl && ) {
            throw 'You should provide `e-name` for editable element inside form!';
          }
          */
  
          // store original props to `parent` before merge
          angular.forEach(overwrites, function(v, k) {
            if(eCtrl[k] !== undefined) {
              eCtrl.parent[k] = eCtrl[k];
            }
          });
  
          // merge overwrites to base editable controller
          angular.extend(eCtrl, overwrites);
  
          // x-editable can be disabled using editableOption or edit-disabled attribute
          var disabled = angular.isDefined(attrs.editDisabled) ?
            scope.$eval(attrs.editDisabled) :
            editableOptions.isDisabled;
  
          if (disabled) {
            return;
          }
          
          // init editable ctrl
          eCtrl.init(!hasForm);
  
          // publich editable controller as `$editable` to be referenced in html
          scope.$editable = eCtrl;
  
          // add `editable` class to element
          elem.addClass('editable');
  
          // hasForm
          if(hasForm) {
            if(eFormCtrl) {
              scope.$form = eFormCtrl;
              if(!scope.$form.$addEditable) {
                throw 'Form with editable elements should have `editable-form` attribute.';
              }
              scope.$form.$addEditable(eCtrl);
            } else {
              // future form (below): add editable controller to buffer and add to form later
              $rootScope.$$editableBuffer = $rootScope.$$editableBuffer || {};
              $rootScope.$$editableBuffer[attrs.eForm] = $rootScope.$$editableBuffer[attrs.eForm] || [];
              $rootScope.$$editableBuffer[attrs.eForm].push(eCtrl);
              scope.$form = null; //will be re-assigned later
            }
          // !hasForm
          } else {
            // create editableform controller
            scope.$form = editableFormController();
            // add self to editable controller
            scope.$form.$addEditable(eCtrl);
  
            // if `e-form` provided, publish local $form in scope
            if(attrs.eForm) {
              scope.$parent[attrs.eForm] = scope.$form;
            }
  
            // bind click - if no external form defined
            if(!attrs.eForm || attrs.eClickable) {
              elem.addClass('editable-click');
              elem.bind(editableOptions.activationEvent, function(e) {
                e.preventDefault();
                e.editable = eCtrl;
                scope.$apply(function(){
                  scope.$form.$show();
                });
              });
            }
          }
  
        }
      };
    };
  }]);
  