<commit_before>﻿using System.Runtime.WootzJs;
using WootzJs.Web;

namespace WootzJs.Mvc.Views
{
    internal class MouseTrackingEngine
    {
        Element lastElement;
        bool isMouseDown;

        internal void Initialize()
        {
            Browser.Window.AddEventListener("mousemove", OnMouseMove);         
            Browser.Window.AddEventListener("mouseout", OnMouseOut);         
            Browser.Window.AddEventListener("mousedown", OnMouseDown);
            Browser.Window.AddEventListener("mouseup", OnMouseUp);         
        }

        private void OnMouseMove(Event evt)
        {
            var currentElement = evt.Target;
            if (lastElement != currentElement)
            {
                var current = currentElement;
                while (current != null)
                {
                    var hasMouse = current.As<JsObject>().member("$hasMouse");
                    if (!hasMouse)
                        FireMouseEntered(current);
                    else
                        break;
                    current = current.ParentElement;
                }

                // If the new element is not contained in the last element...
                if (lastElement != null && !currentElement.IsDescendentOf(lastElement))
                {
                    var last = lastElement;
                    while (last != null)
                    {
                        if (!last.Contains(currentElement))
                            FireMouseExited(last);
                        else
                            break;
                        last = last.ParentElement;
                    }
                }

                lastElement = currentElement;
            }
        }

        private void FireMouseEntered(Element element)
        {
            element.As<JsObject>().memberset("$hasMouse", true);
            var mouseEnterEvent = Browser.Document.CreateCustomEvent("mouseentered", null);
            element.DispatchEvent(mouseEnterEvent);            
        }

        private void FireMouseExited(Element element)
        {
            element.As<JsObject>().memberset("$hasMouse", false);
            var mouseExitedEvent = Browser.Document.CreateCustomEvent("mouseexited", null);
            element.DispatchEvent(mouseExitedEvent);                                
        }

        private void FireMouseUp(Element element)
        {
            var mouseExitedEvent = Browser.Document.CreateCustomEvent("mouseup", null);
            element.DispatchEvent(mouseExitedEvent);                                
        }

        private void OnMouseOut(Event evt)
        {
            if (evt.RelatedTarget == null)
            {
                var current = lastElement;
                while (current != null)
                {
                    FireMouseExited(lastElement);                
                    current = current.ParentElement;
                }
            }
        }

        private void OnMouseDown(Event evt)
        {
            isMouseDown = true;
        }

        private void OnMouseUp(Event evt)
        {
            isMouseDown = false;
        }

        public bool IsMouseDown
        {
            get { return isMouseDown; }
        }
    }
}<commit_msg>Add code that ensures mouseup events get fired even if the cursor is no longer in the control<commit_after>﻿using System.Runtime.WootzJs;
using WootzJs.Web;

namespace WootzJs.Mvc.Views
{
    internal class MouseTrackingEngine
    {
        Element lastElement;
        bool isMouseDown;
        Element mouseDownTarget;

        internal void Initialize()
        {
            Browser.Window.AddEventListener("mousemove", OnMouseMove);         
            Browser.Window.AddEventListener("mouseout", OnMouseOut);         
            Browser.Window.AddEventListener("mousedown", OnMouseDown);
            Browser.Window.AddEventListener("mouseup", OnMouseUp);         
        }

        private void OnMouseMove(Event evt)
        {
            var currentElement = evt.Target;
            if (lastElement != currentElement)
            {
                var current = currentElement;
                while (current != null)
                {
                    var hasMouse = current.As<JsObject>().member("$hasMouse");
                    if (!hasMouse)
                        FireMouseEntered(current);
                    else
                        break;
                    current = current.ParentElement;
                }

                // If the new element is not contained in the last element...
                if (lastElement != null && !currentElement.IsDescendentOf(lastElement))
                {
                    var last = lastElement;
                    while (last != null)
                    {
                        if (!last.Contains(currentElement))
                            FireMouseExited(last);
                        else
                            break;
                        last = last.ParentElement;
                    }
                }

                lastElement = currentElement;
            }
        }

        private void FireMouseEntered(Element element)
        {
            element.As<JsObject>().memberset("$hasMouse", true);
            var mouseEnterEvent = Browser.Document.CreateCustomEvent("mouseentered", null);
            element.DispatchEvent(mouseEnterEvent);            
        }

        private void FireMouseExited(Element element)
        {
            element.As<JsObject>().memberset("$hasMouse", false);
            var mouseExitedEvent = Browser.Document.CreateCustomEvent("mouseexited", null);
            element.DispatchEvent(mouseExitedEvent);                                
        }

        private void FireMouseUp(Element element)
        {
            var mouseExitedEvent = Browser.Document.CreateCustomEvent("mouseup", null);
            element.DispatchEvent(mouseExitedEvent);                                
        }

        private void OnMouseOut(Event evt)
        {
            if (evt.RelatedTarget == null)
            {
                var current = lastElement;
                while (current != null)
                {
                    FireMouseExited(lastElement);                
                    current = current.ParentElement;
                }
            }
        }

        private void OnMouseDown(Event evt)
        {
            isMouseDown = true;
            mouseDownTarget = evt.Target;
        }

        private void OnMouseUp(Event evt)
        {
            isMouseDown = false;
            if (evt.Target != mouseDownTarget)
                FireMouseUp(mouseDownTarget);
        }

        public bool IsMouseDown
        {
            get { return isMouseDown; }
        }
    }
}
{'fraction_non_alphanumeric': 0.07696827262044653, 'fraction_numerical': 0.0, 'mean_word_length': 1.2636303191489362, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4215447', 'n_tokens_mistral': 1597, 'n_tokens_neox': 1512, 'n_words': 315}