import { Class } from '../../core/Core';
import Obj from '../../foundation/Object';
import '../../foundation/EventTarget';  // For Function#on

const ModalEventHandler = Class({

    Extends: Obj,

    init (/* ...mixins */) {
        ModalEventHandler.parent.constructor.apply( this, arguments );
        this._seenMouseDown = false;
    },

    inView ( event ) {
        let targetView = event.targetView;
        const view = this.get( 'view' );
        while ( targetView && targetView !== view ) {
            targetView = targetView.get( 'parentView' );
        }
        return !!targetView;
    },

    // If a user clicks outside the menu we want to close it. But we don't want
    // the mousedown/mouseup/click events to propagate to what's below. The
    // events fire in that order, and not all are guaranteed to fire (the user
    // could mousedown and drag their mouse out of the window before releasing
    // it or vica versa. If there is a drag in between mousedown and mouseup,
    // the click event won't fire).
    //
    // The safest to hide on is click, as we know there are no more events from
    // this user interaction which we need to capture, and it also means the
    // user has clicked and released outside the pop over; a decent indication
    // we should close it. However, if the pop over was triggered on mousedown
    // we may still see a mouseup and a click event from this initial user
    // interaction, but these must not hide the view. Therefore, we make sure
    // we've seen at least one mousedown event after the popOver view shows
    // before hiding on click. On Android/iOS, we will not see a mousedown
    // event, so we also count a touchstart event.
    handleMouse: function ( event ) {
        const type = event.type;
        let view;
        if ( !event.seenByModal && !this.inView( event ) ) {
            event.stopPropagation();
            if ( type === 'mousedown' ) {
                this._seenMouseDown = true;
            } else if ( type === 'click' ) {
                event.preventDefault();
                if ( this._seenMouseDown ) {
                    view = this.get( 'view' );
                    if ( view.clickedOutside ) {
                        view.clickedOutside( event );
                    }
                }
            } else if ( type === 'wheel' ) {
                event.preventDefault();
            }
        }
        event.seenByModal = true;
    }.on( 'click', 'mousedown', 'mouseup', 'tap', 'wheel' ),

    // If the user clicks on a scroll bar to scroll (I know, who does that
    // these days right?), we don't want to count that as a click. So cancel
    // the seen mousedown on scroll events.
    handleScroll: function () {
        this._seenMouseDown = false;
    }.on( 'scroll' ),

    handleKeys: function ( event ) {
        if ( !event.seenByModal && !this.inView( event ) ) {
            event.stopPropagation();
            // View may be interested in key events:
            const view = this.get( 'view' );
            if ( view.keyOutside ) {
                view.keyOutside( event );
            }
        }
        event.seenByModal = true;
    }.on( 'keypress', 'keydown', 'keyup' ),

    handleTouch: function ( event ) {
        if ( !event.seenByModal && !this.inView( event ) ) {
            event.preventDefault();
            event.stopPropagation();
            // Clicks outside should now close the modal.
            this._seenMouseDown = true;
        }
        event.seenByModal = true;
    }.on( 'touchstart' ),
});

export default ModalEventHandler;

@@ -140,220 +140,91 @@
 #on%0A
-%0Aconst ModalEventHandler = Class(%7B%0A%0A    Extends: Obj,%0A%0A    init (/* ...mixins */) %7B%0A        ModalEventHandler.parent.constructor.apply( this, arguments );%0A        this._seenMouseDown = false;%0A    %7D,%0A%0A    inView (
+import ScrollView from '../containers/ScrollView';%0A%0Aconst inView = function ( view,
  eve
@@ -226,28 +226,24 @@
 , event ) %7B%0A
-    
     let targ
@@ -273,53 +273,8 @@
 ew;%0A
-        const view = this.get( 'view' );%0A    
     
@@ -315,28 +315,24 @@
 == view ) %7B%0A
-    
         targ
@@ -372,34 +372,26 @@
 iew' );%0A    
-    %7D%0A    
+%7D%0A
     return !
@@ -397,24 +397,219 @@
 !!targetView
+;%0A%7D;%0A%0Aconst ModalEventHandler = Class(%7B%0A%0A    Extends: Obj,%0A%0A    init (/* ...mixins */) %7B%0A        ModalEventHandler.parent.constructor.apply( this, arguments );%0A        this._seenMouseDown = false
 ;%0A    %7D,%0A%0A  
@@ -1767,43 +1767,66 @@
 nst 
-type = event.type;%0A        let view
+view = this.get( 'view' );%0A        const type = event.type
 ;%0A  
@@ -1855,36 +1855,37 @@
 ByModal && !
-this.
 inView(
+ view,
  event ) ) %7B
@@ -2142,55 +2142,8 @@
 ) %7B%0A
-                    view = this.get( 'view' );%0A
     
@@ -2322,24 +2322,176 @@
 'wheel' ) %7B%0A
+                const scrollView = this.get( 'view' ).getParent( ScrollView );%0A                if ( !scrollView %7C%7C !inView( scrollView, event ) ) %7B%0A    
             
@@ -2510,32 +2510,50 @@
 eventDefault();%0A
+                %7D%0A
             %7D%0A  
@@ -2973,32 +2973,73 @@
 ion ( event ) %7B%0A
+        const view = this.get( 'view' );%0A
         if ( !ev
@@ -3054,36 +3054,37 @@
 ByModal && !
-this.
 inView(
+ view,
  event ) ) %7B
@@ -3178,53 +3178,8 @@
 ts:%0A
-            const view = this.get( 'view' );%0A
     
@@ -3386,32 +3386,73 @@
 ion ( event ) %7B%0A
+        const view = this.get( 'view' );%0A
         if ( !ev
@@ -3475,20 +3475,21 @@
 && !
-this.
 inView(
+ view,
  eve

Allow scrolling of ScrollView containing modal