Example #1
0
        private static void OnNameChanged_MethodToUpdateDom(DependencyObject d, object value)
        {
            var @this = (FrameworkElement)d;

            INTERNAL_HtmlDomManager.SetDomElementAttribute(@this.INTERNAL_OuterDomElement, "dataId", (value ?? string.Empty).ToString());
        }
Example #2
0
        internal virtual string ToString(bool indentXml)
        {
            string nonIndentedXML = null;

            if (INTERNAL_HtmlDomManager.IsInternetExplorer() || Interop.IsRunningInTheSimulator)
            {
                nonIndentedXML = Convert.ToString(CSHTML5.Interop.ExecuteJavaScript("(new XMLSerializer()).serializeToString($0).replace(/Prefix\\d+:AttributeToRemoveFromXMLSerialization=\\$1/g, \"\")", INTERNAL_jsnode, DataContractSerializer_Helpers.ATTRIBUTE_TO_REMOVE_FROM_XMLSERIALIZATION_VALUE)); //todo: find a way to use DataContractSerializer_Helpers.ATTRIBUTE_TO_REMOVE_FROM_XMLSERIALIZATION_NAME while not having the quotation marks.
            }
            else
            {
                if (Convert.ToBoolean(CSHTML5.Interop.ExecuteJavaScript("$0.outerHTML != undefined", INTERNAL_jsnode)))
                {
                    nonIndentedXML = Convert.ToString(CSHTML5.Interop.ExecuteJavaScript("$0.outerHTML", INTERNAL_jsnode));
                }
                else //we are at the root and we need to start from its first child:
                {
                    nonIndentedXML = Convert.ToString(CSHTML5.Interop.ExecuteJavaScript("$0.firstchild.outerHTML", INTERNAL_jsnode));
                }
            }

            if (indentXml)
            {
#if OLD_ALGORITHM_TO_FORMAT_XML
                //now we need to put new lines and indentations to the xml:
                //locate beginning of tags (the '<' character)
                //  add a new line after them
                //  increase/decrease indentation depending on the next tag (decrease if </XXX>, increase otherwise)
                //should be good.

                string   indentedXML                = string.Empty;
                string[] splittedXML                = nonIndentedXML.Split('<');
                string   currentIndentation         = "";
                int      length                     = splittedXML.Length;
                bool     isFirst                    = true;
                bool     thisLoopImpactsIndentation = true;       //required to avoid changing the indentation on lines that contain the start and end of a tag (those that contain text)
                for (int i = 1; i < length; ++i)                  //starts at one because the first element in splittedXml is empty.
                {
                    string part          = splittedXML[i].Trim(); //we Trim just in case but I don't think it is useful
                    string formattedPart = "<" + part;            //"<" removed by the split
                    if (!part.StartsWith("/"))
                    {
                        //now we check if there is a content as text to this tag:
                        int index = formattedPart.IndexOf('>');
                        if (index < formattedPart.Length - 1)
                        {
                            //the element contains a text so we add the closing tag:
                            ++i; //advance the loop to the index of the closing tag

                            string closingTag = splittedXML[i].Trim();
                            formattedPart += "<" + closingTag;

                            thisLoopImpactsIndentation = false;
                        }
                    }

                    if (!isFirst)
                    {
                        indentedXML += Environment.NewLine;
                    }
                    if (part.StartsWith("/"))
                    {
                        currentIndentation         = currentIndentation.Substring(2); //we remove two spaces
                        thisLoopImpactsIndentation = false;
                    }

                    indentedXML += currentIndentation;
                    indentedXML += formattedPart;
                    if (thisLoopImpactsIndentation)
                    {
                        currentIndentation += "  ";
                    }

                    thisLoopImpactsIndentation = true;
                    isFirst = false;
                }
#else
                string indentedXML = Interop.ExecuteJavaScript("window.vkbeautify.xml($0, 2)", nonIndentedXML).ToString();
#endif
                return(indentedXML);
            }
            else
            {
                return(nonIndentedXML);
            }
        }
Example #3
0
        //INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

        /// <summary>
        /// Prepares the Shape so that its canvas has the size it should have, depending on its container, content and Stretch mode.
        /// </summary>
        /// <param name="frameworkElement">The Shape containing the canvas.</param>
        /// <param name="canvasDomElement">The canvas in the Shape.</param>
        /// <param name="minX">The minimum X-coordinate of the points in the Shape.</param>
        /// <param name="maxX">The maximum X-coordinate of the points in the Shape.</param>
        /// <param name="minY">The minimum Y-coordinate of the points in the Shape.</param>
        /// <param name="maxY">The maximum Y-coordinate of the points in the Shape.</param>
        /// <param name="stretch">The Stretch mode to apply on the Shape</param>
        /// <param name="shapeActualSize"></param>
        internal static void PrepareStretch(FrameworkElement frameworkElement, object canvasDomElement, double minX, double maxX, double minY, double maxY, Stretch stretch, out Size shapeActualSize)
        {
            var canvasStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(canvasDomElement);

            //Two steps:
            // 1) We get the size the Shape would take if Stretch = None so that we know its prefered size
            // 2) We make the element take the allowed size closest to that prefered size.

            //We get the size the Shape would take if its Stretch mode was Stretch.None:
            //in Stretch.None mode, the size is from 0 to the rightmost poit and bottommost point:
            double sizeX = maxX;
            double sizeY = maxY;

            //in other Stretched modes, the size is from the leftmost point to the rightmost point and from the topmost to the bottommost point:
            if (stretch != Stretch.None)
            {
                sizeX = maxX - minX;
                sizeY = maxY - minY;
            }
            else //we want to add the size of the shape that goes into negative values:
            {
                if (minX < 0)
                {
                    sizeX = maxX - minX;
                }
                if (minY < 0)
                {
                    sizeY = maxY - minY;
                }
            }
            //todo: (?) for the line below, replace the "+ 1" with the StrokeThickness/LineWidth
            Size sizeToApply = new Size(sizeX + 1, sizeY + 1); //example: a vertical line still needs 1 pixel width

            //we apply the possible defined size of the outerDomElement of the shape:
            dynamic style = INTERNAL_HtmlDomManager.GetFrameworkElementOuterStyleForModification(frameworkElement);
            bool    frameworkElementWidthWasSpecified = false;
            double  frameworkElementWidth             = frameworkElement.Width;
            double  frameworkElementHeight            = frameworkElement.Height;

            if (!double.IsNaN(frameworkElementWidth))
            {
                frameworkElementWidthWasSpecified = true;
                sizeToApply.Width = frameworkElementWidth + 1;
                style.width       = sizeToApply.Width + "px";
            }
            bool frameworkElementHeightWasSpecified = false;

            if (!double.IsNaN(frameworkElementHeight))
            {
                frameworkElementHeightWasSpecified = true;
                sizeToApply.Height = frameworkElementHeight + 1;
                style.height       = sizeToApply.Height + "px";
            }

            //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
            INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

            canvasStyle.width  = sizeToApply.Width + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
            canvasStyle.height = sizeToApply.Height + "px";

            // Get the framework element size after the initial rendering:
            if (frameworkElementWidthWasSpecified && frameworkElementHeightWasSpecified)
            {
                shapeActualSize = new Size(frameworkElementWidth, frameworkElementHeight);
            }
            else
            {
                shapeActualSize = frameworkElement.INTERNAL_GetActualWidthAndHeight(); //Note: in case that the framework element is constrained, it won't take the size of its canvas2d content, so we then resize the canvas2d content so that the shape stretches.
                if (frameworkElementWidthWasSpecified)
                {
                    shapeActualSize.Width = frameworkElementWidth;
                }
                if (frameworkElementHeightWasSpecified)
                {
                    shapeActualSize.Height = frameworkElementHeight;
                }
            }

            if (!frameworkElementWidthWasSpecified || !frameworkElementHeightWasSpecified)
            {
                // Here is the trick:
                //  the element should try to get the size ("separately" in width and height) that is closest to its prefered size (which has been defined in sizeToApply).
                //  to do that, we put the canvas at the prefered size, then we make it take the size of the container (the container is the div that contains the canvas, it is also the Shape's OuterDomElement):
                //      - the first step will make the container take the size it is allowed to that is closest to the prefered size of the element
                //      - the second step will change the canvas' size to the container's size so that the canvas also takes the allowed size closest to its prefered size.

                if (!frameworkElementWidthWasSpecified)
                {
                    canvasStyle.width = shapeActualSize.Width + "px";
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + 1); //todo: add StrokeThickness instead of +1?
                }
                if (!frameworkElementHeightWasSpecified)
                {
                    canvasStyle.height = shapeActualSize.Height + "px";
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + 1); //todo: add StrokeThickness instead of +1?
                }
            }

            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.translate(0.5, 0.5); //makes is less blurry for some reason.
        }
        object InvokeMethod(string methodName, object[] args)
        {
            string methodArgumentsFormattedForJavaScript = string.Join(", ", args.Select(x => INTERNAL_HtmlDomManager.ConvertToStringToUseInJavaScriptCode(x)));
            string javaScriptCodeToExecute =
                string.Format(@"
var element = document.getElementByIdSafe(""{0}"");
var returnValue;
if (element) {{
    returnValue = element.getContext('2d')[""{1}""]({2});
}} 
returnValue;", _domElementUniqueIdentifier, methodName, methodArgumentsFormattedForJavaScript);
            var result = CSHTML5.Interop.ExecuteJavaScriptAsync(javaScriptCodeToExecute);

            return(result);
            //INTERNAL_SimulatorPerformanceOptimizer.QueueJavaScriptCode(javaScriptCodeToExecute);
            //result = null;
        }
Example #5
0
        public override object CreateDomElement(object parentRef, out object domElementWhereToPlaceChildren)
        {
            //INTERNAL_HtmlDomManager.GetDomElementStyleForModification(div).position = "absolute";
            //div.style.position = "absolute";
            //note: size must be set in the div part only (the rest will follow).

            _renderedOrientation = this.Orientation;

            if (_renderedOrientation == Orientation.Horizontal)
            {
                //------v1------//

                //wrapper for the whole stackpanel:
                //<div>
                //  <table style="height:inherit; border-collapse:collapse">
                //    <tr>
                //          ...
                //    </tr>
                //  </table>
                //</div>

                //var table = INTERNAL_HtmlDomManager.CreateDomElement("table");
                //table.style.height = "inherit";
                //table.style.borderCollapse = "collapse";

                //var tr = INTERNAL_HtmlDomManager.CreateDomElement("tr");
                //tr.style.padding = "0px";

                //INTERNAL_HtmlDomManager.AppendChild(table, tr);
                //INTERNAL_HtmlDomManager.AppendChild(div, table);


                //domElementWhereToPlaceChildren = tr;

                //------v2------//
                //wrapper for the whole StackPanel - v2:
                //  <div style="display:table-row">
                //      <div style="margin-left: 0px; margin-right: auto; height: 100%">
                //          ...
                //      </div>
                //  </div>


                object outerDiv;
                var    outerDivStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", parentRef, this, out outerDiv);

                if (INTERNAL_HtmlDomManager.IsInternetExplorer() && !INTERNAL_HtmlDomManager.IsEdge()) //When in Internet Explorer, we need to use display:grid instead of table so that VerticalAlignment.Stretch works (cf StratX.Star in the products page) but we definitely do not want this to be used in Edge as it crashes and causes the whole app to restart (cf ShowcaseApp with CSHTML5 from v1.0 beta 13.2 to RC1 included)
                {
                    outerDivStyle.display = !Grid_InternalHelpers.isMSGrid() ? outerDivStyle.display = "grid" : Grid_InternalHelpers.INTERNAL_CSSGRID_MS_PREFIX + "grid";
                }
                else
                {
                    outerDivStyle.display = "table";
                }
                object innerDiv;
                var    innerDivStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", outerDiv, this, out innerDiv);

                innerDivStyle.marginLeft  = "0px";
                innerDivStyle.marginRight = "auto";
                innerDivStyle.height      = "100%";
                innerDivStyle.display     = "table";

                domElementWhereToPlaceChildren = innerDiv;

                return(outerDiv);
            }
            else
            {
#if !BRIDGE
                return(base.CreateDomElement(parentRef, out domElementWhereToPlaceChildren));
#else
                return(CreateDomElement_WorkaroundBridgeInheritanceBug(parentRef, out domElementWhereToPlaceChildren));
#endif
            }
        }
Example #6
0
        private object AddPasswordInputDomElement(object parentRef, out object domElementWhereToPlaceChildren, bool isTemplated)
        {
            dynamic passwordField;
            var     passwordFieldStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("input", parentRef, this, out passwordField);

            //dynamic passwordField = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("input", parentRef, this);

            _passwordInputField = passwordField;

            domElementWhereToPlaceChildren = passwordField;               // Note: this value is used by the Padding_Changed method to set the padding of the PasswordBox.

            if (isTemplated)                                              //When templated, we remove the outlining that apears when the element has the focus:
            {
                passwordFieldStyle.border          = "transparent";       // This removes the border. We do not need it since we are templated
                passwordFieldStyle.outline         = "solid transparent"; // Note: this is to avoind having the weird border when it has the focus. I could have used outlineWidth = "0px" but or some reason, this causes the caret to not work when there is no text.
                passwordFieldStyle.backgroundColor = "transparent";
                passwordFieldStyle.fontSize        = "inherit";           // Not inherited by default for "input" DOM elements
            }

            passwordFieldStyle.width  = "100%";
            passwordFieldStyle.height = "100%";

            INTERNAL_HtmlDomManager.SetDomElementAttribute(passwordField, "type", "password", forceSimulatorExecuteImmediately: true);
            //passwordField.type = "password";

            //-----------------------
            // Prepare to raise the "TextChanged" event and to update the value of the "Text" property when the DOM text changes:
            //-----------------------
            //todo: why did we put this here instead of in INTERNAL_AttachToDomEvents?
            if (IsRunningOnInternetExplorer())
            {
                //-----------------------
                // Fix "input" event not working under IE:
                //-----------------------
                this.GotFocus  += InternetExplorer_GotFocus;
                this.LostFocus += InternetExplorer_LostFocus;
                INTERNAL_EventsHelper.AttachToDomEvents("textinput", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("paste", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("cut", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("keyup", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("delete", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("mouseup", passwordField, (Action <object>)(e =>
                {
                    InternetExplorer_RaisePasswordChangedIfNecessary();
                }));
            }
            else
            {
                //-----------------------
                // Modern browsers
                //-----------------------
                INTERNAL_EventsHelper.AttachToDomEvents("input", passwordField, (Action <object>)(e =>
                {
                    PasswordAreaValueChanged();
                }));
            }

            //textArea.style.resize = "none"; //to avoid letting the posibility to the user to resize the TextBox

            if (isTemplated)
            {
                //the following methods were ignored before because _contentEditableDiv was not defined due to the fact that we waited for the template to be made so we would know where to put it.
                //as a consequence, we call them here:
                OnAfterApplyHorizontalAlignmentAndWidth();
                OnAfterApplyVerticalAlignmentAndWidth();

                //register to focusin events on the OuterDomElement so that we can "reroute" the focus on the contentEditable element.
                CSHTML5.Interop.ExecuteJavaScript(@"$0.tabIndex = 32767; $0.addEventListener('focusin', $1)", this.INTERNAL_OuterDomElement, (Action <object>)PasswordBox_GotFocus);
                //Note on the line above: 32767 is the maximum value commonly allowed in browsers (and can be considered the default value)
                if (INTERNAL_HtmlDomManager.IsInternetExplorer())
                {
                    //workaround due to IE setting the focus at the end of the click, (or at least after the focusin event), which cancels the work done during focusin.
                    //if I'm not mistaken, the click event happens even when we click on a child of the element so we're all good. (We had to fix the case where a Button had a TextBox inside of it, which is why I assumed that).
                    CSHTML5.Interop.ExecuteJavaScript(@"$0.addEventListener('click', $1)", this.INTERNAL_OuterDomElement, (Action <object>)PasswordBox_GotFocus);
                }
            }

            return(passwordField);
        }
Example #7
0
 public override object CreateDomElement(object parentRef, out object domElementWhereToPlaceChildren)
 {
     _jsDiv = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", parentRef, this);
     domElementWhereToPlaceChildren = _jsDiv;
     return(_jsDiv);
 }
Example #8
0
        private object AddContentEditableDomElement(object parentRef, out object domElementWhereToPlaceChildren)
        {
            bool   isReadOnly = this.Host.IsReadOnly;
            object outerDiv;
            var    outerDivStyle   = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", parentRef, this, out outerDiv);
            string backgroundColor = "transparent"; //value when it is templated

            outerDivStyle.backgroundColor = backgroundColor;
            outerDivStyle.height          = "100%";

            object middleDiv;
            var    middleDivStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", outerDiv, this, out middleDiv);

            middleDivStyle.width  = "100%";
            middleDivStyle.height = "100%";

            object contentEditableDiv;
            var    contentEditableDivStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", middleDiv, this, out contentEditableDiv);

            _contentEditableDiv = contentEditableDiv;
            Host.UpdateFocusContentEditable(_contentEditableDiv);
            if (INTERNAL_HtmlDomManager.IsInternetExplorer())
            {
                //set the class to remove margins on <p> inside the contentEditableDiv
                OpenSilver.Interop.ExecuteJavaScript(@"$0.classList.add(""ie_set_p_margins_to_zero"")", contentEditableDiv);
            }

            contentEditableDivStyle.width  = "100%";
            contentEditableDivStyle.height = "100%";

            // Apply Host.TextWrapping
            contentEditableDivStyle.whiteSpace = Host.TextWrapping == TextWrapping.NoWrap ? "nowrap" : "pre-wrap";

            // Apply Host.HorizontalScrollBarVisibility
            contentEditableDivStyle.overflowX = ScrollBarVisibilityToHtmlString(Host.HorizontalScrollBarVisibility) ?? "hidden";

            // Apply Host.VerticalScrollBarVisibility
            contentEditableDivStyle.overflowY = ScrollBarVisibilityToHtmlString(Host.VerticalScrollBarVisibility) ?? "hidden";

            contentEditableDivStyle.outline    = "solid transparent"; // Note: this is to avoind having the weird border when it has the focus. I could have used outlineWidth = "0px" but or some reason, this causes the caret to not work when there is no text.
            contentEditableDivStyle.background = "solid transparent";
            contentEditableDivStyle.cursor     = "text";

            // Apply TextAlignment
            UpdateTextAlignment(contentEditableDivStyle, Host.TextAlignment);

            string isContentEditable = (!isReadOnly).ToString().ToLower();

            INTERNAL_HtmlDomManager.SetDomElementAttribute(contentEditableDiv, "contentEditable", isContentEditable);
            this.INTERNAL_OptionalSpecifyDomElementConcernedByFocus = contentEditableDiv;
            this.INTERNAL_OptionalSpecifyDomElementConcernedByMinMaxHeightAndWidth = contentEditableDiv;

            contentEditableDivStyle.minWidth  = "14px";
            contentEditableDivStyle.minHeight = (Math.Floor(this.Host.FontSize * 1.5 * 1000) / 1000).ToInvariantString() + "px"; // Note: We multiply by 1000 and then divide by 1000 so as to only keep 3 decimals at the most. //Note: setting "minHeight" is for FireFox only, because other browsers don't seem to need it. The "1.5" factor is here to ensure that the resulting Height is the same as that of the PasswordBox.

            // Fix for Internet Explorer: when pressing Enter in the ContentEditable div, IE will create a new paragraph, which results in graphical issues to the distance between paragraphs. To fix this issue, we put an empty DIV inside by default. When IE detects that there are DIVs inside, it adds a new DIV instead of creating a new paragraph when the user presses Enter.
            if (INTERNAL_HtmlDomManager.IsInternetExplorer())
            {
                object divToImproveIELineBreaks;
                var    divToImproveIELineBreaksStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle("div", contentEditableDiv, this, out divToImproveIELineBreaks);
            }

            domElementWhereToPlaceChildren = contentEditableDiv;

            // Set the mark saying that the pointer events must be "absorbed" by the TextBox:
            INTERNAL_HtmlDomManager.SetDomElementProperty(outerDiv, "data-absorb-events", true);

            //-----------------------
            // Prepare to raise the "TextChanged" event and to update the value of the "Text" property when the DOM text changes:
            //-----------------------
            //todo: why did we put this here instead of in INTERNAL_AttachToDomEvents?
            if (IsRunningOnInternetExplorer())
            {
                //-----------------------
                // Fix "input" event not working under IE:
                //-----------------------
                this.GotFocus  += InternetExplorer_GotFocus;
                this.LostFocus += InternetExplorer_LostFocus;
                INTERNAL_EventsHelper.AttachToDomEvents("textinput", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("paste", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("cut", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("keyup", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("delete", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
                INTERNAL_EventsHelper.AttachToDomEvents("mouseup", contentEditableDiv, (Action <object>)(e =>
                {
                    InternetExplorer_RaiseTextChangedIfNecessary();
                }));
            }
            else
            {
                //-----------------------
                // Modern browsers
                //-----------------------
                INTERNAL_EventsHelper.AttachToDomEvents("input", contentEditableDiv, (Action <object>)(e =>
                {
                    TextAreaValueChanged();
                }));
            }

            //-----------------------
            // Prevent pressing Enter for line break when "AcceptsReturn" is false and prevent pressing any other key than backspace when "MaxLength" is reached:
            // Also prevent the default event when pressing tab and add "\t" when "AcceptsTab" is set to true:
            //-----------------------
            if (IsRunningInJavaScript())
            {
#if OPENSILVER
                throw new InvalidOperationException();
#elif BRIDGE
                //BRIDGETODO : here the code below works weird
                // instance = this
                // makes instance working properly, where it shouldn't
                //Note: I think the reason why instance = this works is because it is set with the correct context of "this",
                //      so instance = this TextBox. If it was inside the function defined as callback of addEventListener,
                //      "this" would be in the context of the event triggered, so it would be the contentEditable div.
                Bridge.Script.Write(@"
var instance = $1;
$0.addEventListener('keydown', function(e) {
    if (e.keyCode == 13 && instance.AcceptsReturn !== true)
    {
        e.preventDefault();
        return false;
    }

    var isAddingTabulation = e.keyCode == 9 && instance.AcceptsTab == true;
    var isRemovingTabulation = isAddingTabulation && e.shiftKey;
    if(isRemovingTabulation)
    {
        isAddingTabulation = false
    }

    if((isAddingTabulation || e.keyCode == 13 || e.keyCode == 32 || e.keyCode > 47) && instance.MaxLength != 0)
    {
        var textLength = instance.GetTextLengthIncludingNewLineCompensation();

        if (e.keyCode == 13)
        {
            textLength += 1; //because adding a new line takes 2 characters instead of 1.
        }
        if(textLength >= instance.MaxLength)
        {
            e.preventDefault();
            return false;
        }
    }

    if(isAddingTabulation)
    {
        //we need to add '\t' where the cursor is, prevent the event (which would change the focus) and dispatch the event for the text changed:
        var sel, range;
        if (window.getSelection) {
            sel = window.getSelection();
            if (sel.rangeCount) {
                range = sel.getRangeAt(0);
                range.deleteContents();
                range.insertNode(document.createTextNode('\t'));
                sel.collapseToEnd();
                range.collapse(false); //for IE
            }
        } else if (document.selection && document.selection.createRange) {
            range = document.selection.createRange();
            range.text = '\t';
            document.selection.collapseToEnd();
        }
        if (window.IS_EDGE)
        {
            sel.removeAllRanges();
            sel.addRange(range);
        }

        instance.TextAreaValueChanged(); //todo: test this.
        e.preventDefault();
            return false;
    }
    if (isRemovingTabulation)
    {
        var sel, range;
        if (window.getSelection) {
            sel = window.getSelection();
            if (sel.rangeCount) {
                range = sel.getRangeAt(0);
                if(range.collapsed)
                {
                    //if the previous character is a '\t', we want to remove it:
                    var rangeStartContainer = range.startContainer;
                    var rangeStartOffset = range.startOffset;

                    //we get the node that contains the text that needs changing and the index of the character to remove:
                    var textNodeToModify = undefined;
                    var indexToRemove = -1;
                    if(rangeStartContainer.nodeType == Node.TEXT_NODE && rangeStartOffset > 0)
                    {
        
                        textNodeToModify = rangeStartContainer;
                        indexToRemove = rangeStartOffset - 1;
                    }
                    else //The potential tab to remove is in the node that is right before the selection(caret) so we look at the last character of the 'previous sibling':
                    {
                        var previousSibling = undefined;

                        // we get the previous node:
                        if(rangeStartContainer.nodeType == Node.TEXT_NODE) //the caret was right before the first element of a textNode. I am not sure if we can arrive here since this case seems to be considered as 'the caret is between the nodes' instead of 'the caret is in the node but before the first character'
                        {
                            previousSibling = rangeStartContainer.previousSibling;
                        }
                        else //the caret is considered between nodes so the range container is the element that contains the text nodes.
                        {
                            if(rangeStartOffset > 0) //otherwise, we are at the first character inside a new div (or p), which means at the start of a new line so nothing to remove.
                            {
                                previousSibling = rangeStartContainer.childNodes[rangeStartOffset -1];
                            }
                        }

                        //We update the node and index to modify:
                        if(previousSibling != undefined && previousSibling.nodeType == Node.TEXT_NODE)
                        {
                            textNodeToModify = previousSibling;
                            indexToRemove = previousSibling.textContent.length - 1;
                        } //else, the previous node was not a text node so there has to be a new line between the caret and the previous text so nothing to remove here.
                    }
        
                    if(textNodeToModify != undefined && indexToRemove != -1)
                    {
                        //range.startContainer.textContent = range.startContainer.textContent.substring(rangeStartOffset)
                        var textContent = textNodeToModify.textContent;
                        if(textContent[indexToRemove] == '\t')
                        {
                            var resultingString = textContent.substring(0, indexToRemove); //note: text.substring(0,-1) returns ""
                            resultingString += textContent.substring(indexToRemove + 1); //note: 'aaa'.substring(25) returns ""
                            textNodeToModify.textContent = resultingString;
                        }
                    }
    
                }
            }
        }
        //todo: else.
        instance.TextAreaValueChanged(); //todo: test this.
        e.preventDefault();
            return false;
    }

}, false);", contentEditableDiv, this);//AcceptsReturn, MaxLength
#endif
            }
#if OPENSILVER
            else
            {
                // ---- SIMULATOR ----
                string uid = ((INTERNAL_HtmlDomElementReference)contentEditableDiv).UniqueIdentifier;

                // Set the "data-accepts-return" property (that we have invented) so that the "KeyDown" and "Paste" JavaScript events can retrieve this value:
                // also set the "data-maxlength" and the "data-isreadonly"
                INTERNAL_HtmlDomManager.ExecuteJavaScript($@"
var element = document.getElementByIdSafe(""{uid}"");
element.setAttribute(""data-acceptsreturn"", ""{this.Host.AcceptsReturn.ToString().ToLower()}"");
element.setAttribute(""data-maxlength"", ""{this.Host.MaxLength}"");
element.setAttribute(""data-isreadonly"",""{isReadOnly.ToString().ToLower()}"");
element.setAttribute(""data-acceptstab"", ""{this.Host.AcceptsTab.ToString().ToLower()}"");");

                // Register the "keydown" javascript event:
                INTERNAL_HtmlDomManager.ExecuteJavaScript($@"
var element_OutsideEventHandler = document.getElementByIdSafe(""{uid}"");
element_OutsideEventHandler.addEventListener('keydown', function(e) {{

    var element_InsideEventHandler = document.getElementByIdSafe(""{uid}""); // For some reason we need to get again the reference to the element.
    var acceptsReturn = element_InsideEventHandler.getAttribute(""data-acceptsreturn"");
    var maxLength = element_InsideEventHandler.getAttribute(""data-maxlength"");
    var acceptsTab = element_InsideEventHandler.getAttribute(""data-acceptstab"");

    if (e.keyCode == 13)
    {{
        if(acceptsReturn != ""true"")
        {{
            e.preventDefault();
            return false;
        }}
    }}

    var isAddingTabulation = e.keyCode == 9 && acceptsTab == ""true"";

    if((isAddingTabulation || e.keyCode == 13 || e.keyCode == 32 || e.keyCode > 47) && maxLength != 0)
    {{
        var text = getTextAreaInnerText(element_InsideEventHandler);
        if (!acceptsReturn) {{
            text = text.replace(""\n"", """").replace(""\r"", """");
        }}

        var correctionDueToNewLines = 0;
        if (e.keyCode == 13)
        {{
            ++correctionDueToNewLines; //because adding a new line takes 2 characters instead of 1.
        }}
        if(text.length + correctionDueToNewLines >= maxLength)
        {{
            if (!window.getSelection().toString()) {{
                e.preventDefault();
                return false;
            }}
        }}
    }}

    if(isAddingTabulation)
    {{
        //we need to add '\t' where the cursor is, prevent the event (which would change the focus) and dispatch the event for the text changed:
        var sel, range;
        if (window.getSelection) {{
            sel = window.getSelection();
            if (sel.rangeCount) {{
                range = sel.getRangeAt(0);
                range.deleteContents();
                range.insertNode(document.createTextNode('\t'));
                sel.collapseToEnd();
                range.collapse(false); //for IE
            }}
        }} else if (document.selection && document.selection.createRange) {{
            range = document.selection.createRange();
            range.text = '\t';
            document.selection.collapseToEnd();
        }}
        if (window.IS_EDGE)
        {{
            sel.removeAllRanges();
            sel.addRange(range);
        }}

        instance.TextAreaValueChanged(); //todo: test this.
        e.preventDefault();
            return false;
    }}
}}, false);");//comma added on purpose because we need to get maxLength somehow (see how we did for acceptsReturn).
            }
#endif

            //-----------------------
            // Enforce only Plain Text + prevent line breaks if "AcceptsReturn" is false. This is required because in a ContentEditable div, the user can paste rich text. Furthermore, on IE, pressing Enter will insert a new paragraph.
            //-----------------------
            if (IsRunningInJavaScript())
            {
#if OPENSILVER
                throw new InvalidOperationException();
#elif BRIDGE
                var acceptsReturn = this.Host.AcceptsReturn;
                //todo: shouldn't we add a check for maxlength in the script below like in the other versions of this addEventListenter (in the simulator version below and in the #if !BRIDGE part above)?
                Bridge.Script.Write(@"
{0}.addEventListener('paste', function(e) {
    var isReadOnly= {1};
    if(!isReadOnly)
    {
        var isSingleLine = ({2} !== true); // This is the current value at the time when the event is raised.
        // Chrome supports setting ContentEditable to PlainText-Only, so we try this first:
        {0}.setAttribute('contenteditable', 'PLAINTEXT-ONLY');
        if ({0}.contentEditable === 'plaintext-only') // If setting the attribute worked, we can read it back (in lowercase)
        {
          // --- CHROME: ---
          // Nothing else to do about rich text conversion to plain text.
          // However we still need to remove line breaks if AcceptsReturn is false:
          if (isSingleLine){
            e.preventDefault();
            var content = (e.originalEvent || e).clipboardData.getData('text/plain');
            content = content.replace(/\n/g, '').replace(/\r/g, '');
            document.execCommand('insertText', false, content);
          }
    }
    else
        {
          {0}.setAttribute('contenteditable', 'true');
          if (e.clipboardData){

            // --- FIREFOX: ---
            e.preventDefault();
            var content = (e.originalEvent || e).clipboardData.getData('text/plain');
            if (isSingleLine){
              content = content.replace(/\n/g, '').replace(/\r/g, '');
            }
            document.execCommand('insertText', false, content);
          }
          else if (window.clipboardData){

            // --- INTERNET EXPLORER: ---
            e.preventDefault();
            var content = window.clipboardData.getData('Text');
            if (window.getSelection)
            {
              var newDiv = document.createElement('div');
              if (isSingleLine){
                content = content.replace(/\n/g, '').replace(/\r/g, '');
              }
              content = content.replace(/\r\n/g, '<br />');
              newDiv.innerHTML = content.replace(/\n/g, '<br />');
              var range = window.getSelection().getRangeAt(0);
              range.deleteContents()
              range.insertNode( newDiv );
              //window.getSelection().getRangeAt(0).insertNode( document.createTextNode(content) );
            }
          }
      }
            }
  
}, false);", contentEditableDiv, isReadOnly, acceptsReturn);
                //BRIDGETODO : check the code up
#endif
            }
#if OPENSILVER
            else
            {
                // ---- SIMULATOR ----
                string uid = ((INTERNAL_HtmlDomElementReference)contentEditableDiv).UniqueIdentifier;

                // The simulator uses Chrome, so we can set "ContentEditable" to plain-text only:
                // We still need to prevent prevent line breaks in the pasted text if "AcceptsReturn" is false:
                INTERNAL_HtmlDomManager.ExecuteJavaScript($@"
var element_OutsideEventHandler = document.getElementByIdSafe(""{uid}"");
element_OutsideEventHandler.addEventListener('paste', function(e) {{
    var element_InsideEventHandler = document.getElementByIdSafe(""{uid}""); // For some reason we need to get again the reference to the element.
    var isReadOnly= element_InsideEventHandler.getAttribute(""data-isreadonly"");
    if(isReadOnly !=""true"")
    {{
        var acceptsReturn = element_InsideEventHandler.getAttribute(""data-acceptsreturn"");
        var maxLength = element_InsideEventHandler.getAttribute(""data-maxlength"");
        element_InsideEventHandler.setAttribute(""contentEditable"", ""PLAINTEXT-ONLY"");
        if (acceptsReturn != ""true""){{
            e.preventDefault();
            var content = (e.originalEvent || e).clipboardData.getData('text/plain');
           if(content !== undefined){{
                content = content.replace(/\n/g, '').replace(/\r/g, '');
            }}
            if(maxLength != 0) {{
                var text = getTextAreaInnerText(element_InsideEventHandler);
                //var text = element_InsideEventHandler.innerText;
                if (!acceptsReturn) {{
                    text = text.replace(""\n"", """").replace(""\r"", """");
                }}

                var correctionDueToNewLines = 0;
                var textBoxTextLength = text.length + correctionDueToNewLines;
                var lengthComparison = maxLength - (content.length + textBoxTextLength);
                if(lengthComparison < 0) {{
                    content = content.substr(0, content.length+lengthComparison);
                }}
            }}
            document.execCommand('insertText', false, content);
        
        }}
    }}
    

}}, false);");
            }
#endif

            return(outerDiv);
        }
        static void AttachVisualChild_Private_MainSteps(UIElement child,
                                                        UIElement parent,
                                                        int index,
                                                        bool doesParentRequireToCreateAWrapperForEachChild,
                                                        object innerDivOfWrapperForChild,
                                                        object domElementWhereToPlaceChildStuff,
                                                        object wrapperForChild)
        {
            //--------------------------------------------------------
            // CREATE THE DIV FOR THE MARGINS (OPTIONAL):
            //--------------------------------------------------------

#if PERFSTAT
            var t1 = Performance.now();
#endif

            // Determine if an additional DIV for handling margins is needed:
            object additionalOutsideDivForMargins = null;
            var    margin = ((FrameworkElement)child).Margin;
            bool   containsNegativeMargins = (margin.Left < 0d || margin.Top < 0d || margin.Right < 0d || margin.Bottom < 0d);
            bool   isADivForMarginsNeeded  = !(parent is Canvas) && // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
                                             !(child is Inline);   // Note: inside a TextBlock we do not want the HTML DIV because we want to create HTML SPAN elements only (otherwise there would be unwanted line returns).

            if (isADivForMarginsNeeded && (parent.IsCustomLayoutRoot || parent.IsUnderCustomLayout))
            {
                isADivForMarginsNeeded = false;
            }

            if (isADivForMarginsNeeded)
            {
                // Determine where to place it:
                object whereToPlaceDivForMargins =
                    (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff);

                // Create and append the DIV for handling margins and append:
                additionalOutsideDivForMargins = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", whereToPlaceDivForMargins, parent, index); //todo: check if the third parameter should be the child or the parent (make something with margins and put a mouseenter in the parent then see if the event is triggered).

                // Style the DIV for handling margins:
                var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(additionalOutsideDivForMargins);
                style.boxSizing = "border-box";
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).HorizontalAlignment == HorizontalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Width)))
                {
                    if (!containsNegativeMargins)
                    {
                        style.width = "100%";
                    }
                }
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).VerticalAlignment == VerticalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Height)))
                {
                    style.height = "100%";
                }
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Create the DIV for the margin", t1);
#endif

            //--------------------------------------------------------
            // PREPARE THE CHILD:
            //--------------------------------------------------------

#if PERFSTAT
            var t2 = Performance.now();
#endif

            // Determine where to place the child:
            object whereToPlaceTheChild = (isADivForMarginsNeeded
                ? additionalOutsideDivForMargins : (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff));

            child.IsConnectedToLiveTree = true;

            // Set the "ParentWindow" property so that the element knows where to display popups:
            child.INTERNAL_ParentWindow = parent.INTERNAL_ParentWindow;

            // Create and append the DOM structure of the Child:
            object domElementWhereToPlaceGrandChildren = null;
            object outerDomElement;
            bool   isChildAControl = child is Control;
            if (child.INTERNAL_HtmlRepresentation == null)
            {
                bool hasTemplate = isChildAControl && ((Control)child).HasTemplate;
                if (hasTemplate)
                {
                    outerDomElement = ((Control)child).CreateDomElementForControlTemplate(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
                else
                {
                    outerDomElement = child.CreateDomElement(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
            }
            else
            {
                outerDomElement = INTERNAL_HtmlDomManager.CreateDomFromStringAndAppendIt(child.INTERNAL_HtmlRepresentation, whereToPlaceTheChild, child);
            }

            // Initialize the "Width" and "Height" of the child DOM structure:
            if (child is FrameworkElement)
            {
                FrameworkElement.INTERNAL_InitializeOuterDomElementWidthAndHeight(((FrameworkElement)child), outerDomElement);
            }

            // Update the DOM structure of the Child (for example, if the child is a Grid, this will render its rows and columns):
            child.INTERNAL_UpdateDomStructureIfNecessary();

            // For debugging purposes (to better read the output html), add a class to the outer DIV that tells us the corresponding type of the element (Border, StackPanel, etc.):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(outerDomElement, "class", child.GetType().ToString());

            // Set Visibility hidden when rendering with CustomLayout
            if (child.IsCustomLayoutRoot && child.Visibility == Visibility.Visible)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).visibility = "hidden";
                child.isFirstRendering = true;
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Prepare the child", t2);
#endif

            //--------------------------------------------------------
            // REMEMBER ALL INFORMATION FOR FUTURE USE:
            //--------------------------------------------------------

#if PERFSTAT
            var t3 = Performance.now();
#endif

            // Remember the DIVs:
            child.INTERNAL_OuterDomElement = outerDomElement;
            child.INTERNAL_InnerDomElement = domElementWhereToPlaceGrandChildren;
            child.INTERNAL_AdditionalOutsideDivForMargins            = additionalOutsideDivForMargins ?? outerDomElement;
            child.INTERNAL_InnerDivOfTheChildWrapperOfTheParentIfAny = doesParentRequireToCreateAWrapperForEachChild ? innerDivOfWrapperForChild : null;

            // Remember the information about the "VisualChildren":
            if (parent.INTERNAL_VisualChildrenInformation == null)
            {
                parent.INTERNAL_VisualChildrenInformation = new Dictionary <UIElement, INTERNAL_VisualChildInformation>();
            }
            parent.INTERNAL_VisualChildrenInformation.Add(child,
                                                          new INTERNAL_VisualChildInformation()
            {
                INTERNAL_UIElement = child,
                INTERNAL_OptionalChildWrapper_OuterDomElement             = wrapperForChild,
                INTERNAL_OptionalChildWrapper_ChildWrapperInnerDomElement = innerDivOfWrapperForChild
            });

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Remember all info for future use", t3);
#endif

            //--------------------------------------------------------
            // HANDLE SPECIAL CASES:
            //--------------------------------------------------------

#if PERFSTAT
            var t4 = Performance.now();
#endif

            // If we are inside a canvas, we set the position to "absolute":
            if (parent is Canvas)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).position = "absolute"; //todo: test if this works properly
            }

            UIElement.SetPointerEvents(child);

            // Reset the flag that tells if we have already applied the RenderTransformOrigin (this is useful to ensure that the default RenderTransformOrigin is (0,0) like in normal XAML, instead of (0.5,0.5) like in CSS):
            child.INTERNAL_RenderTransformOriginHasBeenApplied = false;

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle special cases", t4);
#endif

            //--------------------------------------------------------
            // HANDLE EVENTS:
            //--------------------------------------------------------

#if PERFSTAT
            var t5 = Performance.now();
#endif

            // Register DOM events if any:
            child.INTERNAL_AttachToDomEvents();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle events", t5);
#endif

            //--------------------------------------------------------
            // SET "ISLOADED" PROPERTY AND CALL "ONATTACHED" EVENT:
            //--------------------------------------------------------

            // Tell the control that it is now present into the visual tree:
            child._isLoaded = true;

            // Raise the "OnAttached" event:
            child.INTERNAL_OnAttachedToVisualTree(); // IMPORTANT: Must be done BEFORE "RaiseChangedEventOnAllDependencyProperties" (for example, the ItemsControl uses this to initialize its visual)

            //--------------------------------------------------------
            // RENDER THE ELEMENTS BY APPLYING THE CSS PROPERTIES:
            //--------------------------------------------------------

            // Defer rendering when the control is not visible to when becomes visible (note: when this option is enabled, we do not apply the CSS properties of the UI elements that are not visible. Those property are applied later, when the control becomes visible. This option results in improved performance.)
            bool enableDeferredRenderingOfCollapsedControls =
                EnableOptimizationWhereCollapsedControlsAreNotRendered ||
                EnableOptimizationWhereCollapsedControlsAreLoadedLast ||
                EnableOptimizationWhereCollapsedControlsAreNotLoaded;

            if (enableDeferredRenderingOfCollapsedControls && !child.IsVisible)
            {
                child.INTERNAL_DeferredRenderingWhenControlBecomesVisible = () =>
                {
                    RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
                    child.ClearMeasureAndArrangeValidation();
                };
            }
            else
            {
                RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
            }

            //--------------------------------------------------------
            // HANDLE BINDING:
            //--------------------------------------------------------

#if PERFSTAT
            var t9 = Performance.now();
#endif

            child.INTERNAL_UpdateBindingsSource();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle binding", t9);
#endif

            //--------------------------------------------------------
            // HANDLE TABINDEX:
            //--------------------------------------------------------

            // For GotFocus and LostFocus to work, the DIV specified by "INTERNAL_OptionalSpecifyDomElementConcernedByFocus"
            // (or the OuterDomElement otherwise) needs to have the "tabIndex" attribute set. Therefore we need to always set
            // it (unless IsTabStop is False) to its current value (default is Int32.MaxValue). At the time when this code was
            // written, there was no way to automatically call the "OnChanged" on a dependency property if no value was set.

            // IMPORTANT: This needs to be done AFTER the "OnApplyTemplate" (for example, the TextBox sets the "INTERNAL_OptionalSpecifyDomElementConcernedByFocus" in the "OnApplyTemplate").
            if (isChildAControl)
            {
                if (!(child is TextBlock)) // TextBlock should not count in tabbing (TextBlock is not supposed to be a Control).
                {
                    Control.TabIndexProperty_MethodToUpdateDom(child, ((Control)child).TabIndex);
                }
            }

            //--------------------------------------------------------
            // APPLY THE VISIBILITY:
            //--------------------------------------------------------

            Visibility childVisibility = child.Visibility;
            if (childVisibility == Visibility.Collapsed)
            {
                UIElement.INTERNAL_ApplyVisibility(child, childVisibility);
            }

            //--------------------------------------------------------
            // RAISE THE "SIZECHANGED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t10 = Performance.now();
#endif

            // Raise the "SizeChanged" event: (note: in XAML, the "SizeChanged" event is called before the "Loaded" event)
            // IMPORTANT: This event needs to be raised AFTER the "OnApplyTemplate" and AFTER the "IsLoaded=true" (for example, it is used in the ScrollBar implementation).
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_SizeChangedWhenAttachedToVisualTree();
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise size changed event", t10);
#endif

            //--------------------------------------------------------
            // RAISE THE "LOADED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t11 = Performance.now();
#endif

            // Raise the "Loaded" event: (note: in XAML, the "loaded" event of the children is called before the "loaded" event of the parent)
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_RaiseLoadedEvent();
            }

            child.StartManagingPointerPositionForPointerExitedEventIfNeeded();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise Loaded event", t11);
#endif
        }
Example #10
0
        internal void OnTextDecorationsChanged(TextDecorationCollection tdc)
        {
            string cssValue = tdc?.ToHtmlString() ?? string.Empty;

            INTERNAL_HtmlDomManager.GetDomElementStyleForModification(INTERNAL_OptionalSpecifyDomElementConcernedByFocus).textDecoration = cssValue;
        }
Example #11
0
        internal void OnTextDecorationsChanged(TextDecorations?tdc)
        {
            string cssValue = TextDecorationsToHtmlString(tdc);

            INTERNAL_HtmlDomManager.GetDomElementStyleForModification(INTERNAL_OptionalSpecifyDomElementConcernedByFocus).textDecoration = cssValue;
        }
Example #12
0
 internal void OnTextAlignmentChanged(TextAlignment alignment)
 {
     UpdateTextAlignment(INTERNAL_HtmlDomManager.GetFrameworkElementOuterStyleForModification(this), alignment);
 }
Example #13
0
        private void UnselectOtherRadioButtonsFromSameGroup()
        {
            string groupName = GroupName;

            if (string.IsNullOrWhiteSpace(groupName))
            {
                groupName = ((UIElement)INTERNAL_VisualParent).INTERNAL_ChildrenRadioButtonDefaultName;
            }

            //if the RadioButton has just been checked, we trigger the change event on the RadioButton of the same group that was checked before:
            if (INTERNAL_CheckBoxAndRadioButtonHelpers.IsRunningInJavaScript())
            {
#if !BRIDGE
                JSIL.Verbatim.Expression(@"
                        var radios = document.getElementsByName( $0 );
                        for(var i = 0; i < radios.length; i++ ) {
                            if( radios[i].isLastChecked === true && radios[i] !== $1) {
                                radios[i].checked = false;
                                radios[i].isLastChecked = undefined;
                                var evt = document.createEvent('Event');
                                evt.initEvent('change', false, false);
                                radios[i].dispatchEvent(evt);
                            }
                        }
                        $1.isLastChecked = true;
                    ", groupName, INTERNAL_OptionalSpecifyDomElementConcernedByFocus);
#else
                Script.Write(@"
var radios = document.getElementsByName( $0 );
                        for(var i = 0; i < radios.length; i++ ) {
                            if( radios[i].isLastChecked === true && radios[i] !== $1) {
                                radios[i].checked = false;
                                radios[i].isLastChecked = undefined;
                                var evt = document.createEvent('Event');
                                evt.initEvent('change', false, false);
                                radios[i].dispatchEvent(evt);
                            }
                        }
                        $1.isLastChecked = true;
                    ", groupName, INTERNAL_OptionalSpecifyDomElementConcernedByFocus);
#endif
            }
#if !BRIDGE
            else
            {
                string javaScriptCodeToExecute = string.Format(@"
                        var radios = document.getElementsByName( ""{0}"" );
                        var newlySelectedRadio = document.getElementById(""{1}"");
                            for(var i = 0; i < radios.length; i++ ) {{
                                if( radios[i].isLastChecked === true  && radios[i] !== newlySelectedRadio) {{
                                    radios[i].checked = false;
                                    radios[i].isLastChecked = undefined;
                                    var evt = document.createEvent('Event');
                                    evt.initEvent('change', false, false);
                                    radios[i].dispatchEvent(evt);
                                }}
                            }}
                            newlySelectedRadio.isLastChecked = true;
                        ", groupName, ((INTERNAL_HtmlDomElementReference)INTERNAL_OptionalSpecifyDomElementConcernedByFocus).UniqueIdentifier);
                INTERNAL_HtmlDomManager.ExecuteJavaScriptWithResult(javaScriptCodeToExecute);
            }
#endif
        }
Example #14
0
        protected internal override void Redraw()
        {
            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(this))
            {
                if (Data != null)
                {
                    double minX = double.MaxValue;
                    double minY = double.MaxValue;
                    double maxX = double.MinValue;
                    double maxY = double.MinValue;
                    if (Data is PathGeometry pathGeometry)
                    {
                        if (pathGeometry.Figures == null || pathGeometry.Figures.Count == 0)
                        {
                            return;
                        }
                    }
                    Data.GetMinMaxXY(ref minX, ref maxX, ref minY, ref maxY);


                    // If the rare case that the shape is so big (in terms of coordinates of the points, prior to any transform) that it exceeds the size of Int32 (for an example, refer to the charts in "Client_LD"), we need to make it smaller so that the HTML <canvas> control is able to draw it. We compensate by applying a ScaleTransform to the Data.Tranform:
                    Transform originalTransform = Data.Transform;
                    Transform actualTransform   = originalTransform;
                    double    int32FactorX      = 1d;
                    double    int32FactorY      = 1d;
                    INTERNAL_ShapesDrawHelpers.FixCoordinatesGreaterThanInt32MaxValue(minX,
                                                                                      minY,
                                                                                      maxX,
                                                                                      maxY,
                                                                                      ref actualTransform,
                                                                                      ref int32FactorX,
                                                                                      ref int32FactorY);

                    // Apply the transform to the min/max:
                    if (originalTransform != null)
                    {
                        // todo: appying the transform to the min/max is accurate only for Scale and
                        // translate transforms. For other transforms such as rotate, the min/max is incorrect.
                        // For a correct result, we should apply the transform to each point of the figure.

                        Point tmp1 = originalTransform.Transform(new Point(minX, minY));
                        Point tmp2 = originalTransform.Transform(new Point(maxX, maxY));
                        minX = tmp1._x;
                        minY = tmp1._y;
                        maxX = tmp2._x;
                        maxY = tmp2._y;
                    }

                    Size shapeActualSize;
                    INTERNAL_ShapesDrawHelpers.PrepareStretch(this, _canvasDomElement, minX, maxX, minY, maxY, Stretch, out shapeActualSize);

                    double horizontalMultiplicator;
                    double verticalMultiplicator;
                    double xOffsetToApplyBeforeMultiplication;
                    double yOffsetToApplyBeforeMultiplication;
                    double xOffsetToApplyAfterMultiplication;
                    double yOffsetToApplyAfterMultiplication;
                    double strokeThickness = Stroke == null ? 0d : StrokeThickness;
                    INTERNAL_ShapesDrawHelpers.GetMultiplicatorsAndOffsetForStretch(this,
                                                                                    strokeThickness,
                                                                                    minX,
                                                                                    maxX,
                                                                                    minY,
                                                                                    maxY,
                                                                                    Stretch,
                                                                                    shapeActualSize,
                                                                                    out horizontalMultiplicator,
                                                                                    out verticalMultiplicator,
                                                                                    out xOffsetToApplyBeforeMultiplication,
                                                                                    out yOffsetToApplyBeforeMultiplication,
                                                                                    out xOffsetToApplyAfterMultiplication,
                                                                                    out yOffsetToApplyAfterMultiplication,
                                                                                    out _marginOffsets);

                    ApplyMarginToFixNegativeCoordinates(new Point());
                    if (Stretch == Stretch.None)
                    {
                        ApplyMarginToFixNegativeCoordinates(_marginOffsets);
                    }

                    // A call to "context.beginPath" is required on IE and Edge for the figures to be drawn properly (cf. ZenDesk #971):
                    CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0.getContext('2d').beginPath()", _canvasDomElement);

                    var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(_canvasDomElement);

                    // We want the Transform to be applied only while drawing with the "DefineInCanvas" method, not when applying the stroke and fill, so that the Stroke Thickness does not get affected by the transform (like in Silverlight). To do so, we save the current canvas context, then apply the transform, then draw, and then restore to the original state before applying the stroke:
                    context.save();

                    // Apply the transform if any:
                    INTERNAL_ShapesDrawHelpers.ApplyTransformToCanvas(actualTransform, _canvasDomElement);

                    //problem here: the shape seems to be overall smaller than intended due to the edges of the path not being sharp?
                    Data.DefineInCanvas(this,
                                        _canvasDomElement,
                                        horizontalMultiplicator * int32FactorX,
                                        verticalMultiplicator * int32FactorY,
                                        xOffsetToApplyBeforeMultiplication,
                                        yOffsetToApplyBeforeMultiplication,
                                        xOffsetToApplyAfterMultiplication,
                                        yOffsetToApplyAfterMultiplication,
                                        shapeActualSize);

                    // Read the comment near the "save()" above to know what this "restore" is here for.
                    context.restore();

                    Shape.DrawFillAndStroke(this,
                                            Data.GetFillRuleAsString(),
                                            minX,
                                            minY,
                                            maxX,
                                            maxY,
                                            horizontalMultiplicator, // Note: here we do not multiply by "int32Factor" because we do not want to affect the tickness
                                            verticalMultiplicator,   // Note: here we do not multiply by "int32Factor" because we do not want to affect the tickness
                                            xOffsetToApplyBeforeMultiplication,
                                            yOffsetToApplyBeforeMultiplication,
                                            shapeActualSize);
                }
            }
        }
Example #15
0
        private void ApplyCSSChanges(double scaleX, double scaleY, double skewX, double skewY, double rotation, double translateX, double translateY)
        {
            //-------------
            // In XAML, order is always:
            // 1. Scale
            // 2. Skew
            // 3. Rotate
            // 4. Translate
            //
            // Below we do in reverse order because in CSS the right-most operation is done first.
            //-------------

            //TranslateX:
            CSSEquivalent translateXcssEquivalent = TranslateXProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (translateXcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    translateXcssEquivalent.DomElement,
                    translateXcssEquivalent.Name,
                    translateXcssEquivalent.Value(this, translateX));
            }

            //TranslateY:
            CSSEquivalent translateYcssEquivalent = TranslateYProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (translateYcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    translateYcssEquivalent.DomElement,
                    translateYcssEquivalent.Name,
                    translateYcssEquivalent.Value(this, translateY));
            }

            //Rotation:
            CSSEquivalent rotationcssEquivalent = RotationProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (rotationcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    rotationcssEquivalent.DomElement,
                    rotationcssEquivalent.Name,
                    rotationcssEquivalent.Value(this, rotation));
            }

            //SkewX:
            CSSEquivalent skewXcssEquivalent = SkewXProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (skewXcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    skewXcssEquivalent.DomElement,
                    skewXcssEquivalent.Name,
                    skewXcssEquivalent.Value(this, skewX));
            }

            //SkewY:
            CSSEquivalent skewYcssEquivalent = SkewYProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (skewYcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    skewYcssEquivalent.DomElement,
                    skewYcssEquivalent.Name,
                    skewYcssEquivalent.Value(this, skewY));
            }

            //ScaleX:
            CSSEquivalent scaleXcssEquivalent = ScaleXProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (scaleXcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    scaleXcssEquivalent.DomElement,
                    scaleXcssEquivalent.Name,
                    scaleXcssEquivalent.Value(this, scaleX));
            }

            //ScaleY:
            CSSEquivalent scaleYcssEquivalent = ScaleYProperty.GetTypeMetaData(typeof(CompositeTransform)).GetCSSEquivalent(this);

            if (scaleYcssEquivalent != null)
            {
                INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(
                    scaleYcssEquivalent.DomElement,
                    scaleYcssEquivalent.Name,
                    scaleYcssEquivalent.Value(this, scaleY));
            }
        }
Example #16
0
        protected internal void SetPointerAbsolutePosition(object jsEventArg, Window window)
        {
            if (Interop.IsRunningInTheSimulator)
            {
                // Hack to improve the Simulator performance by making only one interop call rather than two:
                string concatenated             = Convert.ToString(Interop.ExecuteJavaScript("$0.pageX + '|' + $0.pageY", jsEventArg));
                int    sepIndex                 = concatenated.IndexOf('|');
                string pointerAbsoluteXAsString = concatenated.Substring(0, sepIndex);
                string pointerAbsoluteYAsString = concatenated.Substring(sepIndex + 1);
                _pointerAbsoluteX = double.Parse(pointerAbsoluteXAsString, CultureInfo.InvariantCulture); //todo: verify that the locale is OK. I think that JS by default always produces numbers in invariant culture (with "." separator).
                _pointerAbsoluteY = double.Parse(pointerAbsoluteYAsString, CultureInfo.InvariantCulture); //todo: read note above
            }
            else
            {
                dynamic jsEventArgDynamic = (dynamic)jsEventArg;
                //todo - removeJSIL: once we stop supporting the JSIL version, remove the bools like the following and put the thing directly in the if (3x in this method for now).
                bool isArgsPageXDefined = INTERNAL_HtmlDomManager.IsNotUndefinedOrNull(jsEventArgDynamic.pageX); // Using a temporary variable to conatin the tests's result (this line and the following) because in JSIL, trying to do both tests in the if results in an UntranslatableMethod for some reason.
                bool isArgsPageXNotNull = isArgsPageXDefined;
                if (isArgsPageXDefined)                                                                          //Note: apparently, JSIL is really bad at translating things like "bool isArgsPageXNotNull = isArgsPageXDefined && (jsEventArgDynamic.pageX != 0) and ends up commiting seppuku by trying to cast 0 to a boolean.
                {
                    isArgsPageXNotNull = jsEventArgDynamic.pageX != 0;
                }
                if (isArgsPageXNotNull)
                {
                    _pointerAbsoluteX = (double)jsEventArgDynamic.pageX;
                    _pointerAbsoluteY = (double)jsEventArgDynamic.pageY;
                }
                else
                {
                    bool isArgsTouchesDefined  = INTERNAL_HtmlDomManager.IsNotUndefinedOrNull(jsEventArgDynamic.touches); // Using a temporary variable to conatin the tests's result (this line and the following) because in JSIL, trying to do both tests in the if results in an UntranslatableMethod for some reason.
                    bool isArgsTouchesNotEmpty = isArgsTouchesDefined;
                    if (isArgsTouchesDefined)
                    {
                        isArgsTouchesNotEmpty = jsEventArgDynamic.touches.length != 0;
                    }
                    if (isArgsTouchesNotEmpty) //Chrome for Android uses different ways to access the pointer's position.
                    {
                        _pointerAbsoluteX = (double)jsEventArgDynamic.touches[0].pageX;
                        _pointerAbsoluteY = (double)jsEventArgDynamic.touches[0].pageY;
                    }
                    else
                    {
                        bool isArgsChangedTouchesDefined  = INTERNAL_HtmlDomManager.IsNotUndefinedOrNull(jsEventArgDynamic.changedTouches); // Using a temporary variable to conatin the tests's result (this line and the following) because in JSIL, trying to do both tests in the if results in an UntranslatableMethod for some reason.
                        bool isArgsChangedTouchesNotEmpty = isArgsChangedTouchesDefined;
                        if (isArgsChangedTouchesDefined)
                        {
                            isArgsChangedTouchesNotEmpty = jsEventArgDynamic.changedTouches.length != 0;
                        }
                        if (isArgsChangedTouchesNotEmpty) //this is for the PointerRelease event on Chrome for Android
                        {
                            _pointerAbsoluteX = (double)jsEventArgDynamic.changedTouches[0].pageX;
                            _pointerAbsoluteY = (double)jsEventArgDynamic.changedTouches[0].pageY;
                        }
                        else
                        {
                            _pointerAbsoluteX = 0d;
                            _pointerAbsoluteY = 0d;
                        }
                    }
                }
            }

            //---------------------------------------
            // Adjust the absolute coordinates to take into account the fact that the XAML Window is not necessary un the top-left corner of the HTML page:
            //---------------------------------------
            if (window != null)
            {
                // Get the XAML Window root position relative to the page:
                object windowRootDomElement       = window.INTERNAL_OuterDomElement;
                object windowBoundingClientRect   = Interop.ExecuteJavaScript("$0.getBoundingClientRect()", windowRootDomElement);
                object pageBodyBoundingClientRect = Interop.ExecuteJavaScript("document.body.getBoundingClientRect()"); // This is to take into account the scrolling.

                double windowRootLeft;
                double windowRootTop;

                // Hack to improve the Simulator performance by making only one interop call rather than two:
                string concatenated = CSHTML5.Interop.ExecuteJavaScript("($0.left - $1.left) + '|' + ($0.top - $1.top)", windowBoundingClientRect, pageBodyBoundingClientRect).ToString();
                int    sepIndex     = concatenated.IndexOf('|');
                if (sepIndex > -1)
                {
                    string windowRootLeftAsString = concatenated.Substring(0, sepIndex);
                    string windowRootTopAsString  = concatenated.Substring(sepIndex + 1);
#if BRIDGE
                    windowRootLeft = double.Parse(windowRootLeftAsString, global::System.Globalization.CultureInfo.InvariantCulture); //todo: verify that the locale is OK. I think that JS by default always produces numbers in invariant culture (with "." separator).
                    windowRootTop  = double.Parse(windowRootTopAsString, global::System.Globalization.CultureInfo.InvariantCulture);  //todo: read note above
#else
                    //JSIL doesn't have a double.Parse with localization:
                    windowRootLeft = double.Parse(windowRootLeftAsString); //todo: verify that the locale is OK. I think that JS by default always produces numbers in invariant culture (with "." separator).
                    windowRootTop  = double.Parse(windowRootTopAsString);  //todo: read note above
#endif
                }
                else
                {
                    windowRootLeft = Double.NaN;
                    windowRootTop  = Double.NaN;
                }

                // Substract the XAML Window position, to get the pointer position relative to the XAML Window root:
                _pointerAbsoluteX = _pointerAbsoluteX - windowRootLeft;
                _pointerAbsoluteY = _pointerAbsoluteY - windowRootTop;
            }
        }
Example #17
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication,
                                               double yOffsetToApplyBeforeMultiplication,
                                               double xOffsetToApplyAfterMultiplication,
                                               double yOffsetToApplyAfterMultiplication,
                                               double horizontalMultiplicator,
                                               double verticalMultiplicator,
                                               object canvasDomElement,
                                               Point previousLastPoint)
        {
            //HOW IT WORKS IN WINRT:
            //  - Starting point and ending point are two fixed points that will belong to the curve
            //  - we find the two possible ellipses that pass on these two points, with the given width, height and angle
            //  - We chose one ellipse depending on the IsLargeArc combined with SweepDirection property
            //  - we draw the arc connecting the two points on the ellipse starting on the startpoint and ending on the endpoint, folowing the sweepdirection.


            //we use canvas' arc method since it is the easiest way to do this. Another solution would have been bezier segments but defining the angle would be harder.
            //JAVASCRIPT
            //  // cx,cy - center, r - horizontal radius X
            //function drawEllipseWithArcAndScale(ctx, cx, cy, rx, ry, style) {
            //  ctx.save(); // save state
            //  ctx.translate(cx-rx, cy-ry);
            //  ctx.scale(rx, ry);
            //  ctx.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //  //ctx.arc(centerX, centerY, Radius, StartingAngle, EndAngle, isCounterClockwise)
            //  ctx.restore(); // restore to original state
            //  ctx.save();
            //  if(style)
            //    ctx.strokeStyle=style;
            //  ctx.stroke();
            //  ctx.restore();
            //}
            //END OF JAVASCRIPT

            UpdateStartPosition(previousLastPoint);
            UpdateStrokeThickness(this.ParentPath.StrokeThickness);

            UpdateArcData();


            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.save(); // save state
            context.translate(xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                              yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            context.scale(horizontalMultiplicator, verticalMultiplicator);
            context.rotate(RotationAngle * Math.PI / 180);
            double horizontalScaling = (Size.Width) / (Size.Height);

            context.scale(horizontalScaling, 1);

            double centerX = _ellipseCenterInCircleCoordinates.X;
            double centerY = _ellipseCenterInCircleCoordinates.Y;

            context.arc(centerX,
                        centerY,
                        Size.Height * _additionalScalingForShapetoSmallToReachEndPoint,
                        _angle1,
                        _angle2,
                        SweepDirection == SweepDirection.Counterclockwise);

            context.restore(); // restore to original state
            context.stroke();

            return(Point);
        }
        static void AttachVisualChild_Private_MainSteps(UIElement child,
                                                        UIElement parent,
                                                        bool doesParentRequireToCreateAWrapperForEachChild,
                                                        object innerDivOfWrapperForChild,
                                                        object domElementWhereToPlaceChildStuff,
                                                        object wrapperForChild)
        {
#if REWORKLOADED
            if (INTERNAL_VisualTreeOperation.Current.Root == null)
            {
                INTERNAL_VisualTreeOperation.Current.Root = parent;
            }
#endif
            //#if CSHTML5BLAZOR && DEBUG
            //            string childIndentity = child + (child != null ? " (" + child.GetHashCode() + ")" : "");
            //            string parentIndentity = parent + (parent != null ? " (" + parent.GetHashCode() + ")" : "");
            //            Console.WriteLine("OPEN SILVER DEBUG: VisualTreeManager : AttachVisualChild_Private_FinalStepsOnlyIfControlIsVisible: " + childIndentity + " attached to " + parentIndentity);
            //#endif

            //--------------------------------------------------------
            // CREATE THE DIV FOR THE MARGINS (OPTIONAL):
            //--------------------------------------------------------

#if PERFSTAT
            var t1 = Performance.now();
#endif

            // Determine if an additional DIV for handling margins is needed:
            object additionalOutsideDivForMargins = null;
            var    margin = ((FrameworkElement)child).Margin;
            bool   containsNegativeMargins = (margin.Left < 0d || margin.Top < 0d || margin.Right < 0d || margin.Bottom < 0d);
#if ONLY_ADD_DIV_FOR_MARGINS_WHEN_MARGINS_NOT_ZERO
            bool isADivForMarginsNeeded = !(parent is Canvas) && !(child is Inline) && child is FrameworkElement;  // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
            if (isADivForMarginsNeeded)
            {
                var horizontalAlign = ((FrameworkElement)child).HorizontalAlignment;
                var verticalAlign   = ((FrameworkElement)child).VerticalAlignment;
                isADivForMarginsNeeded = !(margin.Left == 0 && margin.Top == 0 && margin.Right == 0 && margin.Bottom == 0 && horizontalAlign == HorizontalAlignment.Stretch && verticalAlign == VerticalAlignment.Stretch);
            }
#else
            bool isADivForMarginsNeeded = !(parent is Canvas) && // Note: In a Canvas, we don't want to add the additional DIV because there are no margins and we don't want to interfere with the pointer events by creating an additional DIV.
                                          !(child is Inline);      // Note: inside a TextBlock we do not want the HTML DIV because we want to create HTML SPAN elements only (otherwise there would be unwanted line returns).
#endif
            if (isADivForMarginsNeeded)
            {
                // Determine where to place it:
                object whereToPlaceDivForMargins =
                    (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff);

                // Create and append the DIV for handling margins and append:
                additionalOutsideDivForMargins = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", whereToPlaceDivForMargins, parent); //todo: check if the third parameter should be the child or the parent (make something with margins and put a mouseenter in the parent then see if the event is triggered).

                // Style the DIV for handling margins:
                var style = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(additionalOutsideDivForMargins);
                style.boxSizing = "border-box";
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).HorizontalAlignment == HorizontalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Width)))
                {
                    if (!containsNegativeMargins)
                    {
                        style.width = "100%";
                    }
                }
                if (child is FrameworkElement &&
                    (((FrameworkElement)child).VerticalAlignment == VerticalAlignment.Stretch && double.IsNaN(((FrameworkElement)child).Height)))
                {
                    style.height = "100%";
                }
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Create the DIV for the margin", t1);
#endif

            //--------------------------------------------------------
            // PREPARE THE CHILD:
            //--------------------------------------------------------

#if PERFSTAT
            var t2 = Performance.now();
#endif

            // Determine where to place the child:
            object whereToPlaceTheChild = (isADivForMarginsNeeded
                ? additionalOutsideDivForMargins : (doesParentRequireToCreateAWrapperForEachChild
                    ? innerDivOfWrapperForChild
                    : domElementWhereToPlaceChildStuff));

            // Set the "Parent" property of the Child (IMPORTANT: we need to do that before child.CreateDomElement because the type of the parent is used to display the child correctly):
            child.INTERNAL_VisualParent = parent;

            // Set the "ParentWindow" property so that the element knows where to display popups:
            child.INTERNAL_ParentWindow = parent.INTERNAL_ParentWindow;

            // Create and append the DOM structure of the Child:
            object domElementWhereToPlaceGrandChildren = null;
            object outerDomElement;
            bool   isChildAControl = child is Control;
            if (child.INTERNAL_HtmlRepresentation == null)
            {
                bool hasTemplate = isChildAControl && ((Control)child).HasTemplate;
                if (hasTemplate)
                {
                    outerDomElement = ((Control)child).CreateDomElementForControlTemplate(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
                else
                {
                    outerDomElement = child.CreateDomElement(whereToPlaceTheChild, out domElementWhereToPlaceGrandChildren);
                }
            }
            else
            {
                outerDomElement = INTERNAL_HtmlDomManager.CreateDomFromStringAndAppendIt(child.INTERNAL_HtmlRepresentation, whereToPlaceTheChild, child);
            }

            // Initialize the "Width" and "Height" of the child DOM structure:
            if (child is FrameworkElement)
            {
                FrameworkElement.INTERNAL_InitializeOuterDomElementWidthAndHeight(((FrameworkElement)child), outerDomElement);
            }

            // Update the DOM structure of the Child (for example, if the child is a Grid, this will render its rows and columns):
            child.INTERNAL_UpdateDomStructureIfNecessary();

            // For debugging purposes (to better read the output html), add a class to the outer DIV that tells us the corresponding type of the element (Border, StackPanel, etc.):
            INTERNAL_HtmlDomManager.SetDomElementAttribute(outerDomElement, "class", child.GetType().ToString());

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Prepare the child", t2);
#endif

            //--------------------------------------------------------
            // REMEMBER ALL INFORMATION FOR FUTURE USE:
            //--------------------------------------------------------

#if PERFSTAT
            var t3 = Performance.now();
#endif

            // Remember the DIVs:
            child.INTERNAL_OuterDomElement = outerDomElement;
            child.INTERNAL_InnerDomElement = domElementWhereToPlaceGrandChildren;
            child.INTERNAL_AdditionalOutsideDivForMargins            = additionalOutsideDivForMargins ?? outerDomElement;
            child.INTERNAL_InnerDivOfTheChildWrapperOfTheParentIfAny = doesParentRequireToCreateAWrapperForEachChild ? innerDivOfWrapperForChild : null;

            // Remember the information about the "VisualChildren":
            if (parent.INTERNAL_VisualChildrenInformation == null)
            {
                parent.INTERNAL_VisualChildrenInformation = new Dictionary <UIElement, INTERNAL_VisualChildInformation>();
            }
            parent.INTERNAL_VisualChildrenInformation.Add(child,
                                                          new INTERNAL_VisualChildInformation()
            {
                INTERNAL_UIElement = child,
                INTERNAL_OptionalChildWrapper_OuterDomElement             = wrapperForChild,
                INTERNAL_OptionalChildWrapper_ChildWrapperInnerDomElement = innerDivOfWrapperForChild
            });

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Remember all info for future use", t3);
#endif

            //--------------------------------------------------------
            // HANDLE SPECIAL CASES:
            //--------------------------------------------------------

#if PERFSTAT
            var t4 = Performance.now();
#endif

            // If we are inside a canvas, we set the position to "absolute":
            if (parent is Canvas)
            {
                INTERNAL_HtmlDomManager.GetDomElementStyleForModification(outerDomElement).position = "absolute"; //todo: test if this works properly
            }

            UIElement.SynchronizeForceInheritProperties(child, parent);

#if REVAMPPOINTEREVENTS
            UIElement.INTERNAL_UpdateCssPointerEvents(child);
#else
            // If the current element is inside a Grid, we need to explicitly set its CSS property "PointerEvents=auto" because its parent child wrapper has "PointerEvents=none" in order to prevent its child wrappers from overlapping each other and thus preventing clicks on some children.
            if (parent is Grid && child is FrameworkElement) //todo: generalize this code so that we have no hard-reference on the Grid control, and third-party controls can use the same mechanics.
            {
                var frameworkElement = ((FrameworkElement)child);
                FrameworkElement.INTERNAL_UpdateCssPointerEventsPropertyBasedOnIsHitTestVisibleAndIsEnabled(frameworkElement, frameworkElement.IsHitTestVisible, frameworkElement.IsEnabled);
            }
#endif

            // Reset the flag that tells if we have already applied the RenderTransformOrigin (this is useful to ensure that the default RenderTransformOrigin is (0,0) like in normal XAML, instead of (0.5,0.5) like in CSS):
            child.INTERNAL_RenderTransformOriginHasBeenApplied = false;

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle special cases", t4);
#endif

            //--------------------------------------------------------
            // HANDLE EVENTS:
            //--------------------------------------------------------

#if PERFSTAT
            var t5 = Performance.now();
#endif

            // Register DOM events if any:
            child.INTERNAL_AttachToDomEvents();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle events", t5);
#endif
            //--------------------------------------------------------
            // HANDLE INHERITED PROPERTIES:
            //--------------------------------------------------------

#if PERFSTAT
            var t6 = Performance.now();
#endif

            // Get the Inherited properties and pass them to the direct children:
            foreach (DependencyProperty dependencyProperty in
#if BRIDGE
                     INTERNAL_BridgeWorkarounds.GetDictionaryKeys_SimulatorCompatible(parent.INTERNAL_AllInheritedProperties)
#else
                     parent.INTERNAL_AllInheritedProperties.Keys
#endif
                     )
            {
                bool recursively = false; // We don't want a recursion here because the "Attach" method is already recursive due to the fact that we raise property changed on the Children property, which causes to reattach the subtree.
                INTERNAL_PropertyStorage storage = parent.INTERNAL_AllInheritedProperties[dependencyProperty];
                child.SetInheritedValue(dependencyProperty, INTERNAL_PropertyStore.GetEffectiveValue(storage), recursively);
            }

#if PERFSTAT
            Performance.Counter("Handle inherited properties", t6);
#endif

            //--------------------------------------------------------
            // SET "ISLOADED" PROPERTY AND CALL "ONATTACHED" EVENT:
            //--------------------------------------------------------

            // Tell the control that it is now present into the visual tree:
            child._isLoaded = true;

            // Raise the "OnAttached" event:
            child.INTERNAL_OnAttachedToVisualTree(); // IMPORTANT: Must be done BEFORE "RaiseChangedEventOnAllDependencyProperties" (for example, the ItemsControl uses this to initialize its visual)

            //--------------------------------------------------------
            // RENDER THE ELEMENTS BY APPLYING THE CSS PROPERTIES:
            //--------------------------------------------------------

            // Defer rendering when the control is not visible to when becomes visible (note: when this option is enabled, we do not apply the CSS properties of the UI elements that are not visible. Those property are applied later, when the control becomes visible. This option results in improved performance.)
            bool enableDeferredRenderingOfCollapsedControls =
                EnableOptimizationWhereCollapsedControlsAreNotRendered ||
                EnableOptimizationWhereCollapsedControlsAreLoadedLast ||
                EnableOptimizationWhereCollapsedControlsAreNotLoaded;

            if (enableDeferredRenderingOfCollapsedControls && !child.IsVisible)
            {
                child.INTERNAL_DeferredRenderingWhenControlBecomesVisible = () =>
                {
                    RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
                };
            }
            else
            {
                RenderElementsAndRaiseChangedEventOnAllDependencyProperties(child);
            }

            //--------------------------------------------------------
            // HANDLE BINDING:
            //--------------------------------------------------------

#if PERFSTAT
            var t9 = Performance.now();
#endif

            child.INTERNAL_UpdateBindingsSource();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Handle binding", t9);
#endif

            //--------------------------------------------------------
            // HANDLE TABINDEX:
            //--------------------------------------------------------

            // For GotFocus and LostFocus to work, the DIV specified by "INTERNAL_OptionalSpecifyDomElementConcernedByFocus"
            // (or the OuterDomElement otherwise) needs to have the "tabIndex" attribute set. Therefore we need to always set
            // it (unless IsTabStop is False) to its current value (default is Int32.MaxValue). At the time when this code was
            // written, there was no way to automatically call the "OnChanged" on a dependency property if no value was set.

#if !REWORKLOADED
            // IMPORTANT: This needs to be done AFTER the "OnApplyTemplate" (for example, the TextBox sets the "INTERNAL_OptionalSpecifyDomElementConcernedByFocus" in the "OnApplyTemplate").
            if (isChildAControl)
            {
                if (!(child is ContentPresenter) && !(child is TextBlock)) //ContentPresenter should not count in tabbing, as well as TextBlock (especially since TextBlock is not supposed to be a Control).
                {
                    Control.TabIndexProperty_MethodToUpdateDom(child, ((Control)child).TabIndex);
                }
            }
#endif

            //--------------------------------------------------------
            // APPLY THE VISIBILITY:
            //--------------------------------------------------------

            Visibility childVisibility = child.Visibility;
            if (childVisibility == Visibility.Collapsed)
            {
                UIElement.INTERNAL_ApplyVisibility(child, childVisibility);
            }

            //--------------------------------------------------------
            // RAISE THE "SIZECHANGED" EVENT:
            //--------------------------------------------------------
#if !REWORKLOADED
#if PERFSTAT
            var t10 = Performance.now();
#endif

            // Raise the "SizeChanged" event: (note: in XAML, the "SizeChanged" event is called before the "Loaded" event)
            // IMPORTANT: This event needs to be raised AFTER the "OnApplyTemplate" and AFTER the "IsLoaded=true" (for example, it is used in the ScrollBar implementation).
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_SizeChangedWhenAttachedToVisualTree();
            }

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise size changed event", t10);
#endif

            //--------------------------------------------------------
            // RAISE THE "LOADED" EVENT:
            //--------------------------------------------------------
#if PERFSTAT
            var t11 = Performance.now();
#endif

            // Raise the "Loaded" event: (note: in XAML, the "loaded" event of the children is called before the "loaded" event of the parent)
            if (child is FrameworkElement)
            {
                ((FrameworkElement)child).INTERNAL_RaiseLoadedEvent();
            }

            child.StartManagingPointerPositionForPointerExitedEventIfNeeded();

#if PERFSTAT
            Performance.Counter("VisualTreeManager: Raise Loaded event", t11);
#endif
#else
            INTERNAL_VisualTreeOperation.Current.Enqueue(child);
#endif
        }
Example #19
0
        private static void ApplyPropertyChanged(DependencyObject sender, CSSEquivalent cssEquivalent, object oldValue, object newValue)
        {
            //if (cssEquivalent.ApplyWhenControlHasTemplate) //Note: this is to handle the case of a Control with a ControlTemplate (some properties must not be applied on the control itself)

            if (cssEquivalent.Name != null && cssEquivalent.Name.Count > 0 || cssEquivalent.CallbackMethod != null)
            {
                UIElement uiElement = cssEquivalent.UIElement ?? (sender as UIElement); // If no UIElement is specified, we assume that the property is intended to be applied to the instance on which the PropertyChanged has occurred.

                bool hasTemplate = (uiElement is Control) && ((Control)uiElement).HasTemplate;

                if (!hasTemplate || cssEquivalent.ApplyAlsoWhenThereIsAControlTemplate)
                {
                    if (cssEquivalent.CallbackMethod != null)// && cssEquivalent.UIElement != null) //Note: I don't see when the commented part of this test could be false so I'm commenting it and we'll put it back if needed.
                    {
                        //PropertyInfo propertyInfo = uiElement.GetType().GetProperty(cssEquivalent.DependencyProperty.Name);

                        //Type propertyType = propertyInfo.PropertyType;
                        //var castedValue = DynamicCast(newValue, propertyType); //Note: we put this line here because the Xaml could use a Color gotten from a StaticResource (which was therefore not converted to a SolidColorbrush by the compiler in the .g.cs file) and led to a wrong type set in a property (Color value in a property of type Brush).
                        //uiElement.SetVisualStateValue(cssEquivalent.DependencyProperty, castedValue);

                        cssEquivalent.CallbackMethod(cssEquivalent.UIElement, new DependencyPropertyChangedEventArgs(oldValue, newValue, cssEquivalent.DependencyProperty));
                    }
                    else
                    {
                        if (cssEquivalent.DomElement == null && uiElement != null)
                        {
                            cssEquivalent.DomElement = uiElement.INTERNAL_OuterDomElement; // Default value
                        }
                        if (cssEquivalent.DomElement != null)
                        {
                            if (newValue is ICanConvertToCSSValue)
                            {
                                cssEquivalent.Value = (finalInstance, value) => { return(((ICanConvertToCSSValue)value).ConvertToCSSValue()); };
                            }
                            if (newValue is ICanConvertToCSSValues)
                            {
                                cssEquivalent.Values = (finalInstance, value) => { return(((ICanConvertToCSSValues)value).ConvertToCSSValues(sender)); };
                            }
                            if (cssEquivalent.Value == null)
                            {
                                cssEquivalent.Value = (finalInstance, value) => { return(value ?? ""); }; // Default value
                            }
                            if (cssEquivalent.Values != null)
                            {
                                List <object> cssValues = cssEquivalent.Values(sender, newValue);

                                if (cssEquivalent.OnlyUseVelocity)
                                {
                                    foreach (object cssValue in cssValues)
                                    {
                                        INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(cssEquivalent.DomElement, cssEquivalent.Name, cssValue);
                                    }
                                }
                                else
                                {
                                    foreach (object cssValue in cssValues)
                                    {
                                        INTERNAL_HtmlDomManager.SetDomElementStyleProperty(cssEquivalent.DomElement, cssEquivalent.Name, cssValue);
                                    }
                                }
                            }
                            else if (cssEquivalent.Value != null) //I guess we cannot have both defined
                            {
                                object cssValue = cssEquivalent.Value(sender, newValue);

                                if (!(cssValue is Dictionary <string, object>))
                                {
                                    if (cssEquivalent.OnlyUseVelocity)
                                    {
                                        INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(cssEquivalent.DomElement, cssEquivalent.Name, cssValue);
                                    }
                                    else
                                    {
                                        INTERNAL_HtmlDomManager.SetDomElementStyleProperty(cssEquivalent.DomElement, cssEquivalent.Name, cssValue);
                                    }
                                }
                                else
                                {
                                    //Note: currently, only Color needs to set multiple values when using Velocity (which is why cssValue is a Dictionary), which is why it has a special treatment.
                                    //todo: if more types arrive here, find a way to have a more generic way of handling it ?
                                    if (newValue is Color)
                                    {
                                        Color newColor = (Color)newValue;
                                        if (cssEquivalent.OnlyUseVelocity)
                                        {
                                            INTERNAL_HtmlDomManager.SetDomElementStylePropertyUsingVelocity(cssEquivalent.DomElement, cssEquivalent.Name, newColor.INTERNAL_ToHtmlStringForVelocity());
                                        }
                                        else
                                        {
                                            INTERNAL_HtmlDomManager.SetDomElementStyleProperty(cssEquivalent.DomElement, cssEquivalent.Name, newColor.INTERNAL_ToHtmlString(1d));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                throw new InvalidOperationException("Please set the Name property of the CSSEquivalent class.");
            }
        }
Example #20
0
        private static void Source_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control  = (MediaElement)d;
            var newValue = (Uri)e.NewValue;

            // Always check that the control is in the Visual Tree before modifying its HTML representation
            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(control))
            {
                string newUri = newValue.ToString();

                // If the new Source is an empty string, we avoid the error messages:
                if (!string.IsNullOrWhiteSpace(newUri))
                {
                    string tagString = "none";

                    string valueForHtml5SourceProperty = INTERNAL_UriHelper.ConvertToHtml5Path(newValue.ToString(), control);

                    string newExtensionLowercase = GetExtension(newUri).ToLower();

                    if (SupportedVideoTypes.Contains(newExtensionLowercase))
                    {
                        if (control.IsAudioOnly || control._mediaElement == null) //note: I chose to use IsAudioOnly here because using e.oldValue would make it recreate the video tag when it was already a video tag.
                        {
                            tagString           = "video";
                            control.IsAudioOnly = false;
                        }
                    }
                    else if (SupportedAudioTypes.Contains(newExtensionLowercase))
                    {
                        if (!control.IsAudioOnly || control._mediaElement == null) //note: I chose to use IsAudioOnly here because using e.oldValue would make it recreate the audio tag when it was already a audio tag.
                        {
                            tagString           = "audio";
                            control.IsAudioOnly = true;
                        }
                    }
                    else
                    {
                        throw new NotSupportedException("ERROR: The MediaElement control only supports files of the following types: VIDEO: mp4, ogv, webm, 3gp - AUDIO: mp3, ogg - Note: for best browser compatibility, it is recommended to use only MP3 and MP4 files.");
                    }
                    if (tagString != "none") //tagString != "none" means that the new Uri has a different type (audio VS video) than the old one, so we need to (re)create the dom tag.
                    {
                        if (control._mediaElement != null)
                        {
                            INTERNAL_HtmlDomManager.RemoveFromDom(control._mediaElement); //note: there can be only one child element.
                        }
#if OPENSILVER
                        if (!INTERNAL_InteropImplementation.IsRunningInTheSimulator_WorkAround() || tagString == "video")
#else
                        if (CSharpXamlForHtml5.Environment.IsRunningInJavaScript || tagString == "video")
#endif
                        {
                            object element      = null;
                            object outerDiv     = control.INTERNAL_OuterDomElement;
                            var    elementStyle = INTERNAL_HtmlDomManager.CreateDomElementAppendItAndGetStyle(tagString, outerDiv, control, out element);

                            control._mediaElement_ForAudioOnly_ForSimulatorOnly = null;

                            control._mediaElement = element;

                            if (tagString == "video")
                            {
                                elementStyle.width  = "100%";
                                elementStyle.height = "100%";
                            }

                            control.Refresh(); //we refresh all the values of the element in the visual tree
                        }
                        else //when we are in the simulator, we don't want to use the <audio> tag, we will use a wpf one instead (because awesomium doesn't support .mp3 for example)
                        {
#if !CSHTML5NETSTANDARD
                            if (control._mediaElement_ForAudioOnly_ForSimulatorOnly == null)
                            {
                                control._mediaElement_ForAudioOnly_ForSimulatorOnly = INTERNAL_Simulator.WpfMediaElementFactory.Create((Action)control.SimulatorMediaElement_Loaded, (Action)control.SimulatorMediaElement_MediaEnded);
                            }
                            control._mediaElement_ForAudioOnly_ForSimulatorOnly.Source = new Uri(valueForHtml5SourceProperty);
                            control.Refresh_SimulatorOnly();
#endif
                            return;
                        }
                    }

                    // Update the "src" property of the <video> or <audio> tag
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(control._mediaElement, "src", valueForHtml5SourceProperty, forceSimulatorExecuteImmediately: true);
                }
                else
                {
                    if (control._mediaElement != null)
                    {
                        // Remove previous video/audio if any:
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(control._mediaElement, "src", "", forceSimulatorExecuteImmediately: true);
                    }
                }
            }
        }
Example #21
0
        protected internal override void INTERNAL_OnAttachedToVisualTree()
        {
            base.INTERNAL_OnAttachedToVisualTree();

            INTERNAL_HtmlDomManager.SetContentString(this, this.Text);
        }
Example #22
0
        ///// <summary>
        ///// Occurs when the value of the CurrentState property changes.
        ///// </summary>
        //public event RoutedEventHandler CurrentStateChanged;

        ///// <summary>
        ///// Occurs when the MediaElement is no longer playing audio or video.
        ///// </summary>
        //public event RoutedEventHandler MediaEnded;

        ///// <summary>
        ///// Occurs when there is an error associated with the media Source.
        ///// </summary>
        //public event ExceptionRoutedEventHandler MediaFailed;

        ///// <summary>
        ///// Occurs when the media stream has been validated and opened, and the file
        ///// headers have been read.
        ///// </summary>
        //public event RoutedEventHandler MediaOpened;

        ///// <summary>
        ///// Occurs when the value of the Volume property changes.
        ///// </summary>
        //public event RoutedEventHandler VolumeChanged;

        /// <summary>
        /// Returns an enumeration value that describes the likelihood that the current
        /// MediaElement and its client configuration can play that media source.
        /// </summary>
        /// <param name="type">A string that describes the desired type as a string.</param>
        /// <returns>
        /// A value of the enumeration that describes the likelihood that the current
        /// media engine can play the source.
        /// </returns>
        public MediaCanPlayResponse CanPlayType(string type)
        {
            string canplay = INTERNAL_HtmlDomManager.CallDomMethod(_mediaElement, "canPlayType", type).ToString();

            return(ConvertHtmlCanPlayTypeResult(canplay));
        }
Example #23
0
        public override object CreateDomChildWrapper(object parentRef, out object domElementWhereToPlaceChild, int index)
        {
            if (Orientation == Orientation.Horizontal)
            {
                //------v1------//


                //NOTE: here, we are in a table

                //wrapper for each child:
                //<td style="padding:0px">
                //  <div style="width: inherit;position:relative">
                //      ...(child)
                //  </div>
                //</td>

                //var td = INTERNAL_HtmlDomManager.CreateDomElement("td");
                //td.style.position = "relative";
                //td.style.padding = "0px";
                ////var div = INTERNAL_HtmlDomManager.CreateDomElement("div");
                ////div.style.height = "inherit"; //todo: find a way to make this div actually inherit the height of the td... (otherwise we cannot set its verticalAlignment)
                ////div.style.position = "relative";
                ////INTERNAL_HtmlDomManager.AppendChild(td, div);

                //domElementWhereToPlaceChild = td;

                //return td;



                //------v2------// = better because we only use divs, it's more simple and verticalAlignment.Stretch works when the stackPanel's size is hard coded (but it still doesn't work when it's not).


                //wrapper for each child - v2
                //<div style="display: table-cell;height:inherit;>
                // ...
                //</div>

                var div      = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", parentRef, this, index);
                var divStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(div);
                divStyle.position      = "relative";
                divStyle.display       = "table-cell";
                divStyle.height        = "100%";   //this allow the stretched items to actually be stretched to the size of the tallest element when the stackpanel's size is only defined by this element.
                divStyle.verticalAlign = "middle"; // We use this as a default value for elements that have a "stretch" vertical alignment

                domElementWhereToPlaceChild = div;


                return(div);
            }
            else if (Orientation == Orientation.Vertical) //when we arrive here, it should always be true but we never know...
            {
                //NOTE: here, we are in a div


                //wrapper for each child:
                //<div style="width: inherit">... </div>

                var div      = INTERNAL_HtmlDomManager.CreateDomElementAndAppendIt("div", parentRef, this, index);
                var divStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(div);
                divStyle.position = "relative";
                divStyle.width    = "100%"; // Makes it possible to do horizontal alignment of the element that will be the child of this div.

                domElementWhereToPlaceChild = div;
                return(div);
            }
            else
            {
                throw new NotSupportedException();
            }
        }
Example #24
0
        public Application()
        {
#if CSHTML5BLAZOR
            // we change the resource manager for every resource registered
            ClientSideResourceRegister.Startup();
#endif
            // Keep a reference to the startup assembly:
            StartupAssemblyInfo.StartupAssembly = this.GetType().Assembly;

            // Remember whether we are in "SL Migration" mode or not:
#if MIGRATION
            CSHTML5.Interop.ExecuteJavaScript(@"document.isSLMigration = true");
#else
            CSHTML5.Interop.ExecuteJavaScript(@"document.isSLMigration = false");
#endif

            //Interop.ExecuteJavaScript("document.raiseunhandledException = $0", (Action<object>)RaiseUnhandledException);


            // Inject the "DataContractSerializer" into the "XmlSerializer" (read note in the "XmlSerializer" implementation to understand why):
            if (!CSHTML5.Interop.IsRunningInTheSimulator) //Note: in case of the Simulator, we reference the .NET Framework version of "System.xml.dll", so we cannot inject stuff because the required members of XmlSerializer would be missing.
            {
                InjectDataContractSerializerIntoXmlSerializer();
            }

#if !CSHTML5NETSTANDARD
            // Fix the freezing of the Simulator when calling 'alert' using the "Interop.ExecuteJavaScript()" method by redirecting the JavaScript "alert" to the Simulator message box:
            if (CSHTML5.Interop.IsRunningInTheSimulator)
            {
                RedirectAlertToMessageBox_SimulatorOnly();
            }
#endif

            // Keep a reference to the app:
            Application.Current = this;

            // Initialize the window:
            if (_mainWindow == null) // Note: it could be != null if the user clicks "Restart" from the Simulator advanced options.
            {
                _mainWindow    = new Window();
                Window.Current = _mainWindow;
                object applicationRootDomElement = INTERNAL_HtmlDomManager.GetApplicationRootDomElement();
                _mainWindow.AttachToDomElement(applicationRootDomElement);

                // Listen to clicks anywhere in the window (this is used to close the popups that are not supposed to stay open):
#if MIGRATION
                _mainWindow.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(INTERNAL_PopupsManager.OnClickOnPopupOrWindow), true);
#else
                _mainWindow.AddHandler(UIElement.PointerPressedEvent, new PointerEventHandler(INTERNAL_PopupsManager.OnClickOnPopupOrWindow), true);
#endif

#if !CSHTML5NETSTANDARD
                // Workaround an issue on Firefox where the UI disappears if the window is resized and on some other occasions:
                if (INTERNAL_HtmlDomManager.IsFirefox())
                {
                    _mainWindow.SizeChanged += MainWindow_SizeChanged;
                    _timerForWorkaroundFireFoxIssue.Interval = new TimeSpan(0, 0, 2);
                    _timerForWorkaroundFireFoxIssue.Tick    += TimerForWorkaroundFireFoxIssue_Tick;
                }
#endif
            }

            // We call the "Startup" event and the "OnLaunched" method using the Dispatcher, because usually the user registers the "Startup" event in the constructor of the "App.cs" class, which is derived from "Application.cs", and therefore when we arrive here the event is not yet registered. Executing the code in the Dispatcher ensures that the constructor of the "App.cs" class has finished before running the code.
#if MIGRATION
            Dispatcher
#else
            CoreDispatcher
#endif
            .INTERNAL_GetCurrentDispatcher().BeginInvoke((Action)(() =>
            {
                // Raise the "Startup" event:
                if (this.Startup != null)
                {
                    Startup(this, new StartupEventArgs());
                }

                // Call the "OnLaunched" method:
                this.OnLaunched(new LaunchActivatedEventArgs());
            }));
        }
Example #25
0
 /// <summary>
 /// Retrieves an object that is located within a specified point of an object's coordinate space.
 /// </summary>
 /// <param name="intersectingPoint">The point to use as the determination point.</param>
 /// <returns>The UIElement object that is determined to be located
 /// in the visual tree composition at the specified point.</returns>
 internal static UIElement FindElementInHostCoordinates(Point intersectingPoint)
 {
     return(INTERNAL_HtmlDomManager.FindElementInHostCoordinates_UsedBySimulatorToo(intersectingPoint.X, intersectingPoint.Y));
 }
        internal static object ExecuteJavaScript_SimulatorImplementation(string javascript, bool runAsynchronously, bool noImpactOnPendingJSCode = false, params object[] variables)
        {
#if !BUILDINGDOCUMENTATION
            //---------------
            // Due to the fact that it is not possible to pass JavaScript objects between the simulator JavaScript context
            // and the C# context, we store the JavaScript objects in a global dictionary inside the JavaScript context.
            // This dictionary is named "jsSimulatorObjectReferences". It associates a unique integer ID to each JavaScript
            // object. In C# we only manipulate those IDs by manipulating instances of the "JSObjectReference" class.
            // When we need to re-use those JavaScript objects, the C# code passes to the JavaScript context the ID
            // of the object, so that the JavaScript code can retrieve the JavaScript object instance by using the
            // aforementioned dictionary.
            //---------------

            // Verify the arguments:
            if (noImpactOnPendingJSCode && runAsynchronously)
            {
                throw new ArgumentException("You cannot set both 'noImpactOnPendingJSCode' and 'runAsynchronously' to True. The 'noImpactOnPendingJSCode' only has meaning when running synchronously.");
            }

            // Make sure the JS to C# interop is set up:
            if (!IsJavaScriptCSharpInteropSetUp)
            {
#if !CSHTML5NETSTANDARD
                // Adding a property to the JavaScript "window" object:
                JSObject jsWindow = (JSObject)INTERNAL_HtmlDomManager.ExecuteJavaScriptWithResult("window");
                jsWindow.SetProperty("onCallBack", new OnCallBack(CallbacksDictionary));
#else
                OnCallBack.SetCallbacksDictionary(CallbacksDictionary);
#endif
                IsJavaScriptCSharpInteropSetUp = true;
            }

            // If the javascript code has references to previously obtained JavaScript objects, we replace those references with calls to the "document.jsSimulatorObjectReferences" dictionary.
            for (int i = variables.Length - 1; i >= 0; i--) // Note: we iterate in reverse order because, when we replace ""$" + i.ToString()", we need to replace "$10" before replacing "$1", otherwise it thinks that "$10" is "$1" followed by the number "0". To reproduce the issue, call "ExecuteJavaScript" passing 10 arguments and using "$10".
            {
                var variable = variables[i];
                if (variable is INTERNAL_JSObjectReference)
                {
                    //----------------------
                    // JS Object References
                    //----------------------

                    var    jsObjectReference = (INTERNAL_JSObjectReference)variable;
                    string jsCodeForAccessingTheObject;

                    if (jsObjectReference.IsArray)
                    {
                        jsCodeForAccessingTheObject = string.Format(@"document.jsSimulatorObjectReferences[""{0}""][{1}]", jsObjectReference.ReferenceId, jsObjectReference.ArrayIndex);
                    }
                    else
                    {
                        jsCodeForAccessingTheObject = string.Format(@"document.jsSimulatorObjectReferences[""{0}""]", jsObjectReference.ReferenceId);
                    }

                    javascript = javascript.Replace("$" + i.ToString(), jsCodeForAccessingTheObject);
                }
                else if (variable is INTERNAL_HtmlDomElementReference)
                {
                    //------------------------
                    // DOM Element References
                    //------------------------

                    string id = ((INTERNAL_HtmlDomElementReference)variable).UniqueIdentifier;
                    javascript = javascript.Replace("$" + i.ToString(), string.Format(@"document.getElementById(""{0}"")", id));
                }
                else if (variable is INTERNAL_SimulatorJSExpression)
                {
                    //------------------------
                    // JS Expression (simulator only)
                    //------------------------

                    string expression = ((INTERNAL_SimulatorJSExpression)variable).Expression;
                    javascript = javascript.Replace("$" + i.ToString(), expression);
                }
                else if (variable is Delegate)
                {
                    //-----------
                    // Delegates
                    //-----------

                    Delegate callback = (Delegate)variable;

                    // Add the callback to the document:
                    int callbackId = ReferenceIDGenerator.GenerateId();
                    CallbacksDictionary.Add(callbackId, callback);

#if CSHTML5NETSTANDARD
                    //Console.WriteLine("Added ID: " + callbackId.ToString());
#endif

                    // Change the JS code to point to that callback:
                    javascript = javascript.Replace("$" + i.ToString(), string.Format(
                                                        @"(function() {{
                        var argsArray = Array.prototype.slice.call(arguments);
                        var idWhereCallbackArgsAreStored = ""callback_args_"" + Math.floor(Math.random() * 1000000);
                        document.jsSimulatorObjectReferences[idWhereCallbackArgsAreStored] = argsArray;
                        setTimeout(
                            function() 
                            {{
                               window.onCallBack.OnCallbackFromJavaScript({0}, idWhereCallbackArgsAreStored, argsArray);
                            }}
                            , 1);
                      }})", callbackId));

                    // Note: generating the random number in JS rather than C# is important in order to be able to put this code inside a JavaScript "for" statement (cf. deserialization code of the JsonConvert extension, and also ZenDesk ticket #974) so that the "closure" system of JavaScript ensures that the number is the same before and inside the "setTimeout" call, but different for each iteration of the "for" statement in which this piece of code is put.
                    // Note: we store the arguments in the jsSimulatorObjectReferences that is inside the JS context, so that the user can access them from the callback.
                    // Note: "Array.prototype.slice.call" will convert the arguments keyword into an array (cf. http://stackoverflow.com/questions/960866/how-can-i-convert-the-arguments-object-to-an-array-in-javascript )
                    // Note: in the command above, we use "setTimeout" to avoid thread/locks problems.
                }
                else if (variable == null)
                {
                    //--------------------
                    // Null
                    //--------------------

                    javascript = javascript.Replace("$" + i.ToString(), "null");
                }
                else
                {
                    //--------------------
                    // Simple value types or other objects (note: this includes objects that override the "ToString" method, such as the class "Uri")
                    //--------------------

                    javascript = javascript.Replace("$" + i.ToString(), INTERNAL_HtmlDomManager.ConvertToStringToUseInJavaScriptCode(variable));
                }
            }

            // Surround the javascript code with some code that will store the result into the "document.jsSimulatorObjectReferences" for later use in subsequent calls to this method:
            int referenceId = ReferenceIDGenerator.GenerateId();
            javascript = string.Format(
                @"var result = eval(""{0}"");
document.jsSimulatorObjectReferences[""{1}""] = result;
result;
", INTERNAL_HtmlDomManager.EscapeStringForUseInJavaScript(javascript), referenceId);

            // Execute the javascript code:
            object value = null;
            if (!runAsynchronously)
            {
                value = CastFromJsValue(INTERNAL_HtmlDomManager.ExecuteJavaScriptWithResult(javascript, noImpactOnPendingJSCode: noImpactOnPendingJSCode));
            }
            else
            {
                INTERNAL_HtmlDomManager.ExecuteJavaScript(javascript);
            }

            var objectReference = new INTERNAL_JSObjectReference()
            {
                Value       = value,
                ReferenceId = referenceId.ToString()
            };

            return(objectReference);
#else
            return(null);
#endif
        }
Example #27
0
        internal static void PrepareEllipse(object canvasDomElement, double ellipseWidth, double ellipseHeight, double centerX, double centerY)
        {
            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            //todo: StrokeThickness --> ?


            //solutions below have been found at http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
            //todo: check which version is the most effective (note, there are other implementation possibilities in the link above so we might check with those too)
            //todo: once todo above done, apply result on EllipseGeometry class too

            #region using bezier's curves

            //JAVASCRIPT
            //function drawEllipseWithBezier(ctx, x, y, w, h, style) {
            //    var kappa = .5522848,
            //        ox = (w / 2) * kappa, // control point offset horizontal
            //        oy = (h / 2) * kappa, // control point offset vertical
            //        xe = x + w,           // x-end
            //        ye = y + h,           // y-end
            //        xm = x + w / 2,       // x-middle
            //        ym = y + h / 2;       // y-middle

            //    ctx.save();
            //    ctx.beginPath();
            //    ctx.moveTo(x, ym);
            //    ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
            //    ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
            //    ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
            //    ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
            //    if(style)
            //      ctx.strokeStyle=style;
            //    ctx.stroke();
            //    ctx.restore();
            //  }
            //END OF JAVASCRIPT


            //    ctx.bezierCurveTo(x, y + h / 2 - oy, x + w / 2 - ox, y, x + w / 2, y);
            //    ctx.bezierCurveTo(x + w / 2 + ox, y, xe, y + h / 2 - oy, xe, y + h / 2);
            //    ctx.bezierCurveTo(xe, y + h / 2 + oy, x + w / 2 + ox, ye, x + w / 2, ye);
            //    ctx.bezierCurveTo(x + w / 2 - ox, ye, x, y + h / 2 + oy, x, y + h / 2);

            double kappa = .5522848;
            double ox    = (ellipseWidth / 2) * kappa;  // control point offset horizontal
            double oy    = (ellipseHeight / 2) * kappa; // control point offset vertical

            Point topPoint    = new Point(centerX, centerY - ellipseHeight / 2);
            Point leftPoint   = new Point(centerX - ellipseWidth / 2, centerY);
            Point rightPoint  = new Point(centerX + ellipseWidth / 2, centerY);
            Point bottomPoint = new Point(centerX, centerY + ellipseHeight / 2); //the "+ 1" are so that the ellipse is not cut on the edges.

            context.beginPath();
            context.moveTo(leftPoint.X, leftPoint.Y); //start on the leftmost point of the ellipse
            context.bezierCurveTo(centerX - ellipseWidth / 2, centerY - oy,
                                  centerX - ox, centerY - ellipseHeight / 2,
                                  topPoint.X, topPoint.Y); //bezier to the topmost point of the ellipse
            context.bezierCurveTo(centerX + ox, centerY - ellipseHeight / 2,
                                  centerX + ellipseWidth / 2, centerY - oy,
                                  rightPoint.X, rightPoint.Y); //bezier to the rightmost point of the ellipse
            context.bezierCurveTo(centerX + ellipseWidth / 2, centerY + oy,
                                  centerX + ox, centerY + ellipseHeight / 2,
                                  bottomPoint.X, bottomPoint.Y); //bezier to the bottommost point of the ellipse
            context.bezierCurveTo(centerX - ox, centerY + ellipseHeight / 2,
                                  centerX - ellipseWidth / 2, centerY + oy,
                                  leftPoint.X, leftPoint.Y); //bezier to the first point (leftmost point of the ellipse)
            #endregion

            #region using arc and scale

            //JAVASCRIPT
            //  // cx,cy - center, r - horizontal radius X
            //function drawEllipseWithArcAndScale(ctx, cx, cy, rx, ry, style) {
            //  ctx.save(); // save state
            //  ctx.beginPath();
            //  ctx.translate(cx-rx, cy-ry);
            //  ctx.scale(rx, ry);
            //  ctx.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //  ctx.restore(); // restore to original state
            //  ctx.save();
            //  if(style)
            //    ctx.strokeStyle=style;
            //  ctx.stroke();
            //  ctx.restore();
            //}
            //END OF JAVASCRIPT


            //context.save(); // save state
            //context.beginPath();
            //context.scale(actualWidth / 2, actualHeight / 2); ///2 because in context.arc, we put 1 as the radius, so 2 as the perimeter --> 2 as the initial width
            //context.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //context.restore(); // restore to original state
            //context.save();
            //context.strokeStyle = strokeAsString;
            //context.lineWidth = StrokeThickness;
            //context.restore();
            //context.stroke();
            #endregion
        }
Example #28
0
        internal void LocallyManageChildrenChanged_CSSVersion()
        {
            int maxRow    = 0;
            int maxColumn = 0;

            if (RowDefinitions != null && RowDefinitions.Count > 0)
            {
                maxRow = RowDefinitions.Count - 1;
            }
            if (ColumnDefinitions != null && ColumnDefinitions.Count > 0)
            {
                maxColumn = ColumnDefinitions.Count - 1;
            }

            //UIElement[,] lastElements = new UIElement[maxRow + 1, maxColumn + 1];


            foreach (UIElement uiElement in Children)
            {
                if (INTERNAL_VisualTreeManager.IsElementInVisualTree(uiElement))
                {
                    // Note: the code between here and the "until here" comment can be read as:
                    //  ApplyRowPosition(uiElement);
                    //  ApplyColumnPosition(uiElement);
                    // It has not been implemented that way because this is slightly more efficient and we need elementRow and elementColumn afterwards.
                    int elementRow    = GetRow(uiElement);
                    int elementColumn = GetColumn(uiElement);
                    MakeGridPositionCorrect(ref elementRow, maxRow);
                    MakeGridPositionCorrect(ref elementColumn, maxColumn);

                    int rowSpan = GetRowSpan(uiElement);
                    if (rowSpan < 1)
                    {
                        rowSpan = 1;
                    }
                    int columnSpan = GetColumnSpan(uiElement);
                    if (columnSpan < 1)
                    {
                        columnSpan = 1;
                    }
                    int elementLastRow    = rowSpan + elementRow - 1;
                    int elementLastColumn = columnSpan + elementColumn - 1;
                    MakeGridPositionCorrect(ref elementLastRow, maxRow);
                    MakeGridPositionCorrect(ref elementLastColumn, maxColumn);

                    var style = INTERNAL_HtmlDomManager.GetFrameworkElementBoxSizingStyleForModification(uiElement);

                    style.zIndex   = Canvas.GetZIndex(uiElement).ToString(); // we need this because for some reason, shapes overlap everything in their cell unless everyone has their zIndex set, in which case it depends of the order of the grid's children (which i the normal behaviour).
                    style.position = "relative";

                    bool isMsGrid = Grid_InternalHelpers.isMSGrid();
                    if (!isMsGrid)
                    {
                        style.gridRowStart    = (elementRow + 1).ToString();        //Note: +1 because rows start from 1 instead of 0 in js.
                        style.gridColumnStart = (elementColumn + 1).ToString();     //Note: +1 because rows start from 1 instead of 0 in js.
                        style.gridRowEnd      = (elementLastRow + 2).ToString();    //Note: +1 because rows start from 1 instead of 0 in js and another + 1 because the gridRowEnd seems to be the row BEFORE WHITCH the span ends.
                        style.gridColumnEnd   = (elementLastColumn + 2).ToString(); //Note: +1 because columns start from 1 instead of 0 in js and another + 1 because the gridColumnEnd seems to be the column BEFORE WHITCH the span ends.
                    }
                    else
                    {
                        //probably doesn't work, it probably requires to use msGridRow and msGridColumn and msGridRowSpan and msGridColumnSpan
                        style.msGridRow        = (elementRow + 1).ToString();    //Note: +1 because rows start from 1 instead of 0 in js.
                        style.msGridColumn     = (elementColumn + 1).ToString(); //Note: +1 because rows start from 1 instead of 0 in js.
                        style.msGridRowSpan    = (rowSpan).ToString();           //Note: +1 because rows start from 1 instead of 0 in js and another + 1 because the gridRowEnd seems to be the row BEFORE WHITCH the span ends.
                        style.msGridColumnSpan = (columnSpan).ToString();        //Note: +1 because columns start from 1 instead of 0 in js and another + 1 because the gridColumnEnd seems to be the column BEFORE WHITCH the span ends.
                    }
                    //-------------------------until here-------------------------

                    style.pointerEvents = "none";
                    //style.position = "absolute";
                    //lastElements[elementRow, elementColumn] = uiElement;


                    //---------------------------------------------------------------
                    // Handle the column visibility (mainly changed by the DataGrid)
                    //---------------------------------------------------------------
                    if (Grid_InternalHelpers.IsAllCollapsedColumns(this, elementColumn, elementLastColumn))
                    {
                        CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0.style.overflow = 'hidden'", uiElement.INTERNAL_OuterDomElement);
                        CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0.setAttribute('data-isCollapsedDueToHiddenColumn', true)", uiElement.INTERNAL_OuterDomElement);
                    }
                    else
                    {
                        // Note: we set to Visible only if it was previously Hidden due to the fact that a Grid column is hidden, to avoid conflicts such as replacing the "overflow" property set by the ScrollViewer or by the "ClipToBounds" property.
                        CSHTML5.Interop.ExecuteJavaScriptAsync(@"
if ($0.getAttribute('data-isCollapsedDueToHiddenColumn' == true)){
    $0.style.overflow = 'visible';
    $0.setAttribute('data-isCollapsedDueToHiddenColumn', false);
}", uiElement.INTERNAL_OuterDomElement);
                    }
                }
            }
        }
Example #29
0
 public void appendChild(object domElementRef)
 {
     INTERNAL_HtmlDomManager.AppendChild_ForUseByPublicAPIOnly_SimulatorOnly(((DynamicDomElement)domElementRef)._domElementRef, this._domElementRef);
 }
Example #30
0
 public void removeAttribute(string attributeName) //todo: generalize to all the methods (thanks to DynamicObject)
 {
     INTERNAL_HtmlDomManager.RemoveDomElementAttribute(_domElementRef, attributeName, forceSimulatorExecuteImmediately: true);
 }