componentDidMount () {
   if (window.document.flyingDialogs && window.document.flyingDialogs.length > 0) {
     const flyingDialog = window.document.flyingDialogs[window.document.flyingDialogs.length - 1];
     const node = ReactDOM.findDOMNode (flyingDialog);
     this.flyingDialogRect = node.getBoundingClientRect ();
   }
 }
 getViewParentRect (container) {
   const dragParentId = container.props['view-parent-id'];
   const parent = this.findViewId (dragParentId);
   if (parent) {
     const parentNode = ReactDOM.findDOMNode (parent);
     return parentNode.getBoundingClientRect ();
   }
   return null;
 }
 // Return the description of origin, whith is the full rectangle of item origin.
 findOrigin () {
   const dragController = this.read ('drag-controller');
   const dragOwnerId    = this.read ('drag-owner-id');
   for (var container of window.document.dragControllers) {
     const dc = container.props['drag-controller'];
     if (dc === dragController) {
       const n = ReactDOM.findDOMNode (container);
       const rect = this.findNodeOrigin (container, n, dragOwnerId);
       if (rect) {
         return rect;
       }
     }
   }
   return null;
 }
  onMyMouseMove (e) {
    let x = e.clientX;
    let y = e.clientY;
    if (!x && e.touches.length > 0) {
      x = e.touches[0].clientX;
      y = e.touches[0].clientY;
    }
    if (!x || !y) {
      return;
    }
    if (this.moveCount === 0) {  // first move ?
      this.startX = x;
      this.startY = y;
      const dragOwnerId = this.read ('drag-owner-id');
      const dragCab = this.searchDragCab (dragOwnerId);
      const node = ReactDOM.findDOMNode (dragCab);
      const rect = node.getBoundingClientRect ();
      this.offsetX = x - rect.left;
      this.offsetY = y - rect.top;
      this.rectOrigin = this.findOrigin ();
    }
    this.moveCount++;

    const mode = this.read ('mode');
    if (mode === 'corner-top-left') {
      this.x = x;
      this.y = y;
    } else {  // keep mouse at click point
      this.x = x - this.offsetX;
      this.y = y - this.offsetY;
    }

    const dest = this.find (x, y);
    if (dest && dest.ownerId === this.rectOrigin.ownerId &&
      (dest.index === this.rectOrigin.index || dest.index === this.rectOrigin.index + 1)) {
      this.dest = this.rectOrigin;
    } else {
      this.dest = dest;
    }

    if (!this.lastDragStarted && this.isDragStarted ()) {
      this.lastDragStarted = true;
      this.selectMulti (true);
    }
  }
 find (x, y) {
   const direction      = this.read ('direction');
   const dragOwnerId    = this.read ('drag-owner-id');
   const dragCab        = this.searchDragCab (dragOwnerId);
   const dragController = dragCab.read ('drag-controller');
   for (var container of window.document.dragControllers) {
     const dc = container.props['drag-controller'];
     if (dc === dragController) {
       const n = ReactDOM.findDOMNode (container);
       const rect = n.getBoundingClientRect ();
       const vpr = this.getViewParentRect (container);
       const pr = this.getParentRect (container);
       const parentRect = clip (vpr, pr);
       if (isInside (parentRect, x, y) && isInside (rect, x, y)) {
         if (direction === 'horizontal') {
           return this.findH (container, n, x, parentRect);
         } else {
           return this.findV (container, n, y, parentRect);
         }
       }
     }
   }
   return null;
 }
 doShowCombo (x) {
   // Trace.log ('MessengerTicket.showCombo');
   const node = ReactDOM.findDOMNode (this);
   this.comboLocation = ComboHelpers.getComboLocation (node, this.props.theme, 'flying-balloon', x);
   this.showCombo = true;
 }