XingFramework/xing-frontend-utils

View on GitHub
src/xing-frontend-utils/components/toast/interimElement.js

Summary

Maintainability
D
2 days
Test Coverage
import {} from './compiler.js';

angular.module(`xing.utils.interimElement`, [
  `xing.utils.compiler`
])

.factory('$$interimElement', [
  '$q',
  '$rootScope',
  '$timeout',
  '$rootElement',
  '$animate',
  '$xngCompiler',
  InterimElementFactory
]);

/**
 * @ngdoc service
 * @name $$interimElement
 *
 * @description
 *
 * Factory that contructs `$$interimElement.$service` services.
 * Used internally in xing for elements that appear on screen temporarily.
 * The service provides a promise-like API for interacting with the temporary
 * elements.
 *
 * ```js
 * app.service('$xngToast', function($$interimElement) {
 *   var $xngToast = $$interimElement(toastDefaultOptions);
 *   return $xngToast;
 * });
 * ```
 * @param {object=} defaultOptions Options used by default for the `show` method on the service.
 *
 * @returns {$$interimElement.$service}
 *
 */

function InterimElementFactory($q, $rootScope, $timeout, $rootElement, $animate, $xngCompiler) {

  return function createInterimElementService(defaults) {

    /**
     * @ngdoc service
     * @name $$interimElement.$service
     *
     * @description
     * A service used to control inserting and removing an element into the DOM.
     *
     */


    var stack = [];

    var parent = $rootElement.find('body');
    if (!parent.length) { parent = $rootElement; }

    defaults = angular.extend({
      parent: parent,
      onShow: function(scope, $el, options) {
        return $animate.enter($el, options.parent);
      },
      onRemove: function(scope, $el, options) {
        return $animate.leave($el);
      },
    }, defaults || {});

    var service;
    service = {
      show: show,
      hide: hide,
      cancel: cancel
    };
    return service;
    /**
     * @ngdoc method
     * @name $$interimElement.$service#show
     * @kind function
     *
     * @description
     * Compiles and inserts an element into the DOM.
     *
     * @param {Object} options Options object to compile with.
     *
     * @returns {Promise} Promise that will resolve when the service
     * has `#close()` or `#cancel()` called.
     *
     */
    function show(options) {
      if (stack.length) {
        service.hide();
      }

      var interimElement = new InterimElement(options);
      stack.push(interimElement);
      return interimElement.show().then(function() {
        return interimElement.deferred.promise;
      });
    }

    /**
     * @ngdoc method
     * @name $$interimElement.$service#hide
     * @kind function
     *
     * @description
     * Removes the `$interimElement` from the DOM and resolves the promise returned from `show`
     *
     * @param {*} resolveParam Data to resolve the promise with
     *
     * @returns undefined data that resolves after the element has been removed.
     *
     */
    function hide(success) {
      var interimElement = stack.shift();
      interimElement.remove().then(function() {
        interimElement.deferred.resolve(success);
      });
    }

    /**
     * @ngdoc method
     * @name $$interimElement.$service#cancel
     * @kind function
     *
     * @description
     * Removes the `$interimElement` from the DOM and rejects the promise returned from `show`
     *
     * @param {*} reason Data to reject the promise with
     *
     * @returns undefined
     *
     */
    function cancel(reason) {
      var interimElement = stack.shift();
      interimElement.remove().then(function() {
        interimElement.deferred.reject(reason);
      });
    }


    /*
     * Internal Interim Element Object
     * Used internally to manage the DOM element and related data
     */
    function InterimElement(options) {
      var self;
      var hideTimeout, element;

      options = options || {};

      options = angular.extend({
        scope: options.scope || $rootScope.$new(options.isolateScope)
      }, defaults, options);

      self = {
        options: options,
        deferred: $q.defer(),
        show: function() {
          return $xngCompiler.compile(options).then(function(compiledData) {
            element = compiledData.link(options.scope);
            var ret = options.onShow(options.scope, element, options);
            return $q.when(ret)
              .then(startHideTimeout);

            function startHideTimeout() {
              if (options.hideDelay) {
                hideTimeout = $timeout(service.hide, options.hideDelay) ;
              }
            }
          });
        },
        cancelTimeout: function() {
          if (hideTimeout) {
            $timeout.cancel(hideTimeout);
            hideTimeout = undefined;
          }
        },
        remove: function() {
          self.cancelTimeout();
          var ret = options.onRemove(options.scope, element, options);
          return $q.when(ret).then(function() {
            options.scope.$destroy();
          });
        }
      };
      return self;
    }
  };
}