text: /**
   * A drag proxy that creates a new element to follow the cursor.
   */
  Ext.define('Ext.drag.proxy.Placeholder', {
      extend: 'Ext.drag.proxy.None',
      alias: 'drag.proxy.placeholder',
  
      config: {
          /**
           * @cfg {String} cls
           * A class for this proxy.
           */
          cls: '',
  
          /**
           * @cfg {Number[]} cursorOffset
           * Determines the position of the proxy in relation
           * to the cursor.
           */
          cursorOffset: [12, 20],
  
          /**
           * @cfg {String} html
           * The html for this proxy.
           */
          html: null,
  
          /**
           * @cfg {String} invalidCls
           * A class to add to this proxy when over an
           * invalid {@link Ext.drag.Target target}.
           */
          invalidCls: '',
  
          /**
           * @cfg {String} validCls
           * A class to add to this proxy when over a
           * valid {@link Ext.drag.Target target}.
           */
          validCls: ''
      },
  
      placeholderCls: Ext.baseCSSPrefix + 'drag-proxy-placeholder',
  
      /**
       * @method cleanup
       * @inheritdoc
       */
      cleanup: function() {
          this.element = Ext.destroy(this.element);
      },
  
      /**
       * @method getElement
       * @inheritdoc
       */
      getElement: function() {
          var el = Ext.getBody().createChild({
              cls: this.getCls(),
              html: this.getHtml()
          });
  
          el.addCls(this.placeholderCls);
  
          el.setTouchAction({
              panX: false,
              panY: false
          });
  
          return el;
      },
  
      /**
       * @method update
       * @inheritdoc
       */
      update: function(info) {
          var el = this.element,
              invalidCls = this.getInvalidCls(),
              validCls = this.getValidCls(),
              valid = info.valid;
  
          if (info.target) {
              // If we are valid, replace the invalidCls with the validCls.
              // Otherwise do the reverse
              el.replaceCls(valid ? invalidCls : validCls, valid ? validCls : invalidCls);
          }
          else {
              el.removeCls([invalidCls, validCls]);
          }
      },
  
      updateCls: function(cls, oldCls) {
          var el = this.element;
  
          if (el) {
              if (oldCls) {
                  el.removeCls(oldCls);
              }
  
              if (cls) {
                  el.addCls(cls);
              }
          }
      },
  
      updateHtml: function(html) {
          var el = this.element;
  
          if (el) {
              el.setHtml(html || '');
          }
      },
  
      updateInvalidCls: function(invalidCls, oldInvalidCls) {
          this.doUpdateCls(invalidCls, oldInvalidCls);
      },
  
      updateValidCls: function(validCls, oldValidCls) {
          this.doUpdateCls(validCls, oldValidCls);
      },
  
      destroy: function() {
          this.element = Ext.destroy(this.element);
  
          this.callParent();
      },
  
      privates: {
          /**
           * @method adjustCursorOffset
           * @inheritdoc
           */
          adjustCursorOffset: function(info, xy) {
              var offset = this.getCursorOffset();
  
              if (offset) {
                  xy[0] += (offset[0] || 0);
                  xy[1] += (offset[1] || 0);
              }
  
              return xy;
          },
  
          /**
           * Removes a class and replaces it with a new one, if the old class
           * was already on the element.
           * 
           * @param {String} cls The new class to add.
           * @param {String} oldCls The old class to remove.
           *
           * @private
           */
          doUpdateCls: function(cls, oldCls) {
              var el = this.element,
                  hasCls;
  
              if (el) {
                  if (oldCls) {
                      hasCls = cls && el.hasCls(oldCls);
                      el.removeCls(oldCls);
                  }
  
                  if (cls && hasCls) {
                      el.addCls(cls);
                  }
              }
          }
      }
  });
  