Using the error-summary links, the focus jumps to the wrong offset with css fixed position

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi,

My problem is the following:
I have a page that has a menu bar at the top that has CSS attribute "position" set to fixed to prevent scrolling of the menu bar. If I use the form-runner error summary component on a long page, and use one of the links provided in this component to jump to the invalid field, then the field is shown too high on the page and is hidden behind my menu bar.

I have provided a simplified example in attachment.

The example has a 40 pixel menu bar. The content of the page has a margin of 40 pixels to display below the menu bar. The page has to be pretty long to view the wrong positioning, hence the long text after the input fields.


I have looked on GitHub to the error-summary xbl component and this is the code for the links used in the error summary:
<xf:trigger ref=".[$has-label and not(property('xxf:noscript'))]" appearance="minimal" class="fr-error-label">
<xf:label mediatype="text/html" value="@label"/>
<!-- Set focus to control using absolute id -->
<xf:setfocus ev:event="DOMActivate" control="{{@absolute-id}}"/>
</xf:trigger>
The xf:setfocus sets focus to the selected input field.


In Firebug I saw that this posts following event:

With the following response:
<xxf:event-response xmlns:xxf="http://orbeon.org/oxf/xml/xforms">
<xxf:action>
<xxf:control-values/>
<xxf:focus control-id="xf-11"/>
</xxf:action>
</xxf:event-response>
The control-id on xxf:focus is the id of my input-field.


Now my question:
Is there a way to work around this problem? A CSS or JavaScript fix or something I can add to my page to make sure the focus jumps to the correct offset? If there is a solution with JavaScript, could you please provide me with an example, because I am not very good with JavaScript.

Thanks in advance.

Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].

focus-testcase.xhtml (6K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Erik Bruchez
Administrator
Toon,

I ran your example, but I am not sure what to look at. I:

- tabbed through the fields so that errors appear in the error summary
- scrolled down to the error summary
- clicked on the link
- the page focuses on the control (see screenshot)

This is with Chrome.

The focus is done with the native browser focus, using `element.focus()`. So it's the browser which scrolls the viewport to position.



-Erik
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi Erik,

You are correct that this does work in Chrome. There, the component jumps to the center of the page instead of to the top. However, in Firefox and Internet Explorer, focus jumps to the top of the page, where the problem occurs.
I have attached a screenshot for Firefox and Chrome when I select the link for "Name". In both cases, the input field is hidden behind the blue menu bar.

For our customer project, we need to make sure our application works in Internet Explorer (I think IE9).

Do you think there is a solution for this problem?

Thanks in advance.

Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers


Op donderdag 10 april 2014 03:15:59 UTC+2 schreef ebruchez:
Toon,

I ran your example, but I am not sure what to look at. I:

- tabbed through the fields so that errors appear in the error summary
- scrolled down to the error summary
- clicked on the link
- the page focuses on the control (see screenshot)

This is with Chrome.

The focus is done with the native browser focus, using `element.focus()`. So
it's the browser which scrolls the viewport to position.

<<a href="http://discuss.orbeon.com/file/n4658252/focus.png" target="_blank" onmousedown="this.href='http://www.google.com/url?q\75http%3A%2F%2Fdiscuss.orbeon.com%2Ffile%2Fn4658252%2Ffocus.png\46sa\75D\46sntz\0751\46usg\75AFQjCNEwgJq-hl9PwlStS_V64MAcfT18DA';return true;" onclick="this.href='http://www.google.com/url?q\75http%3A%2F%2Fdiscuss.orbeon.com%2Ffile%2Fn4658252%2Ffocus.png\46sa\75D\46sntz\0751\46usg\75AFQjCNEwgJq-hl9PwlStS_V64MAcfT18DA';return true;">http://discuss.orbeon.com/file/n4658252/focus.png>

-Erik

--
View this message in context: <a href="http://discuss.orbeon.com/Using-the-error-summary-links-the-focus-jumps-to-the-wrong-offset-with-css-fixed-position-tp4658236p4658252.html" target="_blank" onmousedown="this.href='http://www.google.com/url?q\75http%3A%2F%2Fdiscuss.orbeon.com%2FUsing-the-error-summary-links-the-focus-jumps-to-the-wrong-offset-with-css-fixed-position-tp4658236p4658252.html\46sa\75D\46sntz\0751\46usg\75AFQjCNHeC4jRivW5dAz2GoCwFW3kNsga3w';return true;" onclick="this.href='http://www.google.com/url?q\75http%3A%2F%2Fdiscuss.orbeon.com%2FUsing-the-error-summary-links-the-focus-jumps-to-the-wrong-offset-with-css-fixed-position-tp4658236p4658252.html\46sa\75D\46sntz\0751\46usg\75AFQjCNHeC4jRivW5dAz2GoCwFW3kNsga3w';return true;">http://discuss.orbeon.com/Using-the-error-summary-links-the-focus-jumps-to-the-wrong-offset-with-css-fixed-position-tp4658236p4658252.html
Sent from the Orbeon Forms community mailing list mailing list archive at Nabble.com.

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].

Firefox.PNG (65K) Download Attachment
Internet Explorer.PNG (37K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Alessandro  Vernet
Administrator
Hi Toon,

This is a tricky one. When doing a focus(), the browser brings the input in the viewport, but doesn't check if there is a fixed box displayed over the input. I also saw the problem with Chrome in some cases.

One suggestion I found while searching for this, was to remove the fixed box when the input gets the focus, and to show it back when the input looses the focus (see link below). This also leaves more space for users to see what they're typing in, since the soft keyboard already takes quite a bit of space on screen. Would that be an acceptable solution in your case?

http://code.tutsplus.com/tutorials/ios-5-fixed-positioning-and-content-scrolling--mobile-8332#comment-689559400

Alex
--
Follow Orbeon on Twitter: @orbeon
Follow me on Twitter: @avernet
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi Alessandro,

If I understand correctly, the solution you suggest will hide the fixed bar at the top if an input field has focus and shows the fixed bar if focus is removed from the input field?
If so, I am afraid that this will be very confusing to the users of our application. It is an acceptable solution for the test project I included, but the real project has over fifty input fields per form and the menu bar holds the action buttons like "Preview", "Send", "Request validation" and more. If these buttons are constantly disappearing and reappearing, this will seriously decrease the usability of the application.

The application will be used by users with a desktop PC using Internet Explorer, so the application is not designed for mobile. I just mention this so there is no confusion there.

I had a look at the ScrollFix.js example on GitHub, but I don't quite understand what it does. I tested it in different browsers, but I'm not sure what I'm supposed to see. If I disable the JavaScript in the example, I see the exact same thing as with JavaScript enabled.

Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Alessandro  Vernet
Administrator
Hi Toon,

OK, got it; indeed hiding the fixed toolbar when an input has the focus is a solution/workaround that would only make sense if your web app was targeting phones or tablets.

So I am not sure there really is a simple solution. What you could do is to write some JavaScript code that does the scrolling instead of relying on focus(). I've prototyped this in the JS Bin linked below. Click on the button and note how the input "moves" just below the fixed block. Of course, this would need to be improved, for instance not to do any scrolling of the input is already visible to start with.

http://jsbin.com/pizuk/1/edit

I hope this helps,

Alex
--
Follow Orbeon on Twitter: @orbeon
Follow me on Twitter: @avernet
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi Allessandro,

I am trying to find out if I can catch an event sent when the error summary link is clicked, to perform a bit of JavaScript when it happens. I was looking in the console logs which events are sent and found the following request:
<xxf:event-request xmlns:xxf="http://orbeon.org/oxf/xml/xforms">
    <xxf:uuid>9786702dc74e21a68dff07ada4d630f0c4d00a45</xxf:uuid>
    <xxf:sequence>3</xxf:sequence>
    <xxf:action>
        <xxf:event name="xforms-focus" source-control-id="form-error-summary=xf-28719?1"></xxf:event>
        <xxf:event name="DOMActivate" source-control-id="form-error-summary=xf-28719?1"></xxf:event>
        <xxf:event name="xxforms-repeat-activate" source-control-id="form-error-summary=er?1"></xxf:event>
    </xxf:action>
</xxf:event-request>


It seems that the "xforms-focus" event sets the focus in the input field matching the link (xf-28719?1). If I could catch this event in my form, and check that the control-id starts with "form-error-summary", I could then use some JavaScript.
I tried with following piece of code for testing:
<xf:action ev:event="xforms-focus">
    <xxf:var name="focus-control" value="event('control')" />
    <xf:message level="xxf:log-error"><xf:output value="concat('Control: ', $focus-control)" /></xf:message>
    <xxf:var name="focus-source-control-id" value="event('source-control-id')" />
    <xf:message level="xxf:log-error"><xf:output value="concat('Source control ID: ', $focus-source-control-id)" /></xf:message>
</xf:action>

I tried both "control" and "source-control-id" as parameter, because I was not sure which one I had to use. However, this action is never triggered, and I get nothing in my log.

Am I trying to catch the wrong event, or can I get this some other way?

Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi,

I worked some more on this today and I managed to make the JavaScript that does the scrolling:

<xhtml:script>
        // Scroll to the object with ID objID and adjust position downwards with fixed offset.
        function scrollTo(objID, fixedID) {
               // Get object matching the ID and calculate the offset.
               var obj = document.getElementById(objID);
               var offset = document.getElementById(fixedID).offsetHeight + 10;
              
               // Scroll to location of obj with adjusted offset on load.
               window.scroll(0,findPos(obj, offset));
         }

         // Finds y value of given object and add offset.
         function findPos(obj, offset) {
               var curtop = 0;
               if (obj.offsetParent) {
                   do {
                       curtop += obj.offsetTop;
                   } while (obj = obj.offsetParent);
                  
                   // Adjust position with offset.
                   curtop -= [offset];
                   return [curtop];
               }
         }
</xhtml:script>


I have an action in my form that handles the JavaScript when it receives an event with parameter "element-id". This is an event I would like to dispatch myself when I know that the error summary link has been clicked:

<xf:action ev:event="e-element-focus">
         <xxf:var name="element-id" value="event('element-id')" />
         <!-- Call JavaScript to fix the position after clicking the error summary links. Give clicked element ID as parameter and the ID of the navigation bar. -->
         <xxf:script>javascript:scrollTo($element-id, 'navigation');</xxf:script>
</xf:action>


Now the problem however remains that I am not sure how I can monitor the focus event to send this dispatch.
I had a look at XML event listeners (http://www.w3.org/TR/xml-events2/#section-listener-element), but I am not sure how I could use this to send the dispatch to my action with the target-id of the focus as parameter.

I tried with following code, but this doesn't work (probably because the xforms-focus event has a specific target and I would have to monitor it in the target element?):

<xf:action ev:event="xforms-focus">
       <xxf:var name="target-id" value="event('xxf:targetid')" />
       <xf:dispatch target="m-default" name="e-element-focus">
              <xf:property name="element-id" value="$target-id" />
       </xf:dispatch>
</xf:action>


Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Alessandro  Vernet
Administrator
Hi Toon,

Alternatively, could you catch a focus event purely in JavaScript, and then run your code that makes sure that whatever got the focus isn't behind the fixed box? This would remove a dependency on the error summary, and would work in other cases where the focus is set on a control (when a form is loaded, if you're using the wizard when switching "pages", or even when users tabs to a field, as that field could conceivably be behind the fixed box). Is this something that could make sense?

Alex
--
Follow Orbeon on Twitter: @orbeon
Follow me on Twitter: @avernet
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Toon Andries-2
Hi Alex,

With some help of a colleague, I managed to find a solution (all JavaScript and JQuery) for the problem. It works most of the time, but has a border case where it can behave a little strange. However, I can live with that :-)

Here is my code:

var fixingFocus = false;

// JQuery click handler for error summary links, setting the variable fixingFocus
$("span:has(a[id*='form-error-summary'])").click(function() {
    fixingFocus = true;
});

// JQuery focus function event handler
$("input, textarea, select").focus(function() {
    if(fixingFocus) {
        scrollTo(this, 'navigation-bar');
        fixingFocus = false;
    }
});

// Scroll to the object obj and adjust position downwards with fixed offset.
function scrollTo(obj, fixedID) {
    // Get object matching the ID and calculate the offset.
    var offset = document.getElementById(fixedID).offsetHeight + 20;
   
    // Scroll to location of obj with adjusted offset on load.
    window.scroll(0,findPos(obj, offset));
}

// Finds y value of given object and add offset.
function findPos(obj, offset) {
    var curtop = 0;
    if (obj.offsetParent) {
        do {
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
       
        // Adjust position with offset.
        curtop -= [offset];
        return [curtop];
    }
}


The problem for the border case is the following. The error summary links are dynamically added when a bind error occurs. This means that the <a> element and surrounding <span> element does not exist on page load. Therefore, the JavaScript is not added to this part. My code could be 100% foolproof if I could add a class selector for "fr-error-label" to the span selector for registering the click, if this was available to add the JavaScript. Now, the function also triggers if you click somewhere in the error summary box, next to the links (one of the higher level <span> elements).
The border case happens when you click somewhere in the box, but not on a link, then scroll up the page manually (error-summary is at the bottom of the form) and click in an input control. The page will then scroll the input field to just below my navigation bar. This is not that bad though, and I don't think this will happen very often.

I have also tried to only trigger the scroll if the input field receiving focus is not in the visible window, but I could not find a good function to calculate the absolute position on the screen of a component. All functions I tried (scrollTop, offsetTop, JQuery position, and some others) gave me the position of the component relative to the top of my page, not factoring in the scrolled distance from the window top. This did not allow me to calculate if a component was hidden behind the navigation bar or not.

Thank you for your help on this matter.

Kind regards,

Toon Andries
Professional Services Consultant
Inventive Designers

--
You received this message because you are subscribed to the Google Groups "Orbeon Forms" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Reply | Threaded
Open this post in threaded view
|

Re: Using the error-summary links, the focus jumps to the wrong offset with css fixed position

Erik Bruchez
Administrator
Toon,

Thanks for sharing. It is tricky!

-Erik