You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2016/10/05 15:53:08 UTC

svn commit: r1763461 - in /myfaces/tobago/trunk: tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/ tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/ tobago-the...

Author: lofwyr
Date: Wed Oct  5 15:53:08 2016
New Revision: 1763461

URL: http://svn.apache.org/viewvc?rev=1763461&view=rev
Log:
TOBAGO-1607: Focus attribute doesn't work inside popup (since bootstrap modal implementation)

Added:
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/
    myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/focus.xhtml
Modified:
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java
    myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js

Added: myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/focus.xhtml
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/focus.xhtml?rev=1763461&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/focus.xhtml (added)
+++ myfaces/tobago/trunk/tobago-example/tobago-example-demo/src/main/webapp/content/30-concept/77-focus/focus.xhtml Wed Oct  5 15:53:08 2016
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<ui:composition template="/main.xhtml"
+                xmlns:tc="http://myfaces.apache.org/tobago/component"
+                xmlns:ui="http://java.sun.com/jsf/facelets"
+                xmlns:f="http://java.sun.com/jsf/core">
+  <ui:param name="title" value="Focus"/>
+
+  <p>
+    After a page is loaded, some input element may have the focus, so the user
+    can immediately begin typing information in the form. There is a ruleset to define
+    which element have the focus, at first.
+  </p>
+  <p>
+    The boolean focus attribute of an input field sets the focus to the element explicitly.
+  </p>
+  <p>
+    The priority order is:
+    <ul>
+      <li>error (the first error element gets the focus)</li>
+      <li>auto (the element with the tobago tag attribute focus="true" gets the focus)</li>
+      <li>last (the element from the last request with same id gets the focus, not AJAX)</li>
+      <li>page (use the focusId attribute of the tc:page)</li>
+      <li>first (the first input element (without tabindex=-1) gets the focus, not AJAX)</li>
+    </ul>
+  </p>
+
+</ui:composition>

Modified: myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java?rev=1763461&r1=1763460&r2=1763461&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java (original)
+++ myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/java/org/apache/myfaces/tobago/renderkit/html/standard/standard/tag/PageRenderer.java Wed Oct  5 15:53:08 2016
@@ -269,6 +269,7 @@ public class PageRenderer extends Render
     writer.writeAttribute(HtmlAttributes.TYPE, HtmlInputTypes.HIDDEN);
     writer.writeNameAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "lastFocusId");
     writer.writeIdAttribute(clientId + ComponentUtils.SUB_SEPARATOR + "lastFocusId");
+    writer.writeAttribute(HtmlAttributes.VALUE, FacesContextUtils.getFocusId(facesContext), true);
     writer.endElement(HtmlElements.INPUT);
 
     if (TobagoConfig.getInstance(FacesContext.getCurrentInstance()).isCheckSessionSecret()) {

Modified: myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js?rev=1763461&r1=1763460&r2=1763461&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js (original)
+++ myfaces/tobago/trunk/tobago-theme/tobago-theme-standard/src/main/resources/org/apache/myfaces/tobago/renderkit/html/standard/standard/script/tobago.js Wed Oct  5 15:53:08 2016
@@ -41,16 +41,6 @@ var Tobago = {
    */
   form: null,
 
-  /**
-   * The id of the element which should became the focus after loading.
-   * Set via renderer if requested.
-   */
-  focusId: undefined,
-
-  errorFocusId: undefined,
-
-  lastFocusId: undefined,
-
   htmlIdIndex: 0,
 
   createHtmlId: function() {
@@ -156,7 +146,6 @@ var Tobago = {
     this.initMarker = true;
 
     console.time("[tobago] init"); // @DEV_ONLY
-    console.time("[tobago] init (main thread)"); // @DEV_ONLY
     this.addBindEventListener(Tobago.findForm().get(0), 'submit', this, 'onSubmit');
 
     this.addBindEventListener(window, 'unload', this, 'onUnload');
@@ -176,12 +165,6 @@ var Tobago = {
     }
     console.timeEnd("[tobago] applicationOnload"); // @DEV_ONLY
 
-    window.setTimeout(Tobago.finishPageLoading, 1);
-    console.timeEnd("[tobago] init (main thread)"); // @DEV_ONLY
-  },
-
-  finishPageLoading: function() {
-    Tobago.setFocus();
     console.timeEnd("[tobago] init"); // @DEV_ONLY
   },
 
@@ -269,7 +252,6 @@ var Tobago = {
     }
     this.jsObjects.length = 0;
     delete this.jsObjects;
-    delete this.lastFocusId;
   },
 
   removeEventListeners: function() {
@@ -318,15 +300,12 @@ var Tobago = {
    * Submitting the page with specified actionId.
    * options.transition
    * options.target
-   * options.focus
    */
   submitAction: function(source, actionId, options) {
     options = options || {};
 
     var transition = options.transition === undefined || options.transition == null || options.transition;
 
-    Tobago.findSubElementOfPage("lastFocusId").val(options.focus);
-
     Tobago.Transport.request(function() {
       if (!this.isSubmit) {
         this.isSubmit = true;
@@ -504,12 +483,7 @@ var Tobago = {
   initDom: function(elements) {
 
     // focus
-    var autofocus = Tobago.Utils.selectWithJQuery(elements, '[autofocus]');
-    autofocus.each(function () {
-      // setupFocus
-      Tobago.focusId = jQuery(this).attr("id");
-      Tobago.setFocus();
-    });
+    Tobago.initFocus(elements);
 
     // commands
     Tobago.Utils.selectWithJQuery(elements, '[data-tobago-commands]')
@@ -654,96 +628,65 @@ var Tobago = {
   /**
    * Sets the focus to the requested element or to the first possible if
    * no element is explicitly requested.
+   *
+   * The priority order is:
+   * - error (the first error element gets the focus)
+   * - auto (the element with the tobago tag attribute focus="true" gets the focus)
+   * - last (the element from the last request with same id gets the focus, not AJAX)
+   * - first (the first input element (without tabindex=-1) gets the focus, not AJAX)
    */
-  setFocus: function() {
-    var elementId;
-    if (this.errorFocusId !== undefined) {
-      elementId = this.errorFocusId;
-    } else if (this.lastFocusId !== undefined) {
-      elementId = this.lastFocusId;
-    } else {
-      elementId = this.focusId;
-    }
-    if (elementId != null) {
-      var $focusElement = jQuery(Tobago.Utils.escapeClientId(elementId));
-      if ($focusElement.size() > 0) {
-        try { // focus() on not visible elements breaks IE
-          $focusElement.focus();
-          return;
-        } catch (ex) {
-          console.warn('Exception when setting focus on : \"' + elementId + '\"'); // @DEV_ONLY
-        }
-      }
+  initFocus: function(elements) {
+
+    var $focusable = jQuery(":input:enabled:visible:not(button):not([tabindex='-1'])");
+    $focusable.focus(function () {
+      // remember the last focused element, for later
+      Tobago.findSubElementOfPage("lastFocusId").val(jQuery(this).attr("id"));
+    });
+
+    var $hasDanger = Tobago.Utils.selectWithJQuery(elements, '.has-danger');
+    var $dangerInput = $hasDanger.find("*").filter(":input:enabled:visible:first");
+    if ($dangerInput.size() > 0) {
+      Tobago.setFocus($dangerInput);
+      return;
     }
 
-    if (typeof this.focusId == 'undefined') {
-      var lowestTabIndex = 32768; // HTML max tab index value + 1
-      var candidate = null;
-      var candidateWithTabIndexZero = null;
-      foriLoop: for (var i = 0; i < document.forms.length; i++) {
-        var form = document.forms[i];
-        if (form != null) {
-          for (var j = 0; j < form.elements.length; j++) {
-            var element = form.elements[j];
-            if (element != null) {
-              if (!element.disabled && !element.readOnly
-                  && this.isFocusType(element.type)) {
-                if (lowestTabIndex > element.tabIndex && element.tabIndex > 0) {
-                  lowestTabIndex = element.tabIndex;
-                  candidate = element;
-                  if (lowestTabIndex == 1) {
-                    // optimization: stop on first field with lowest possible tab index 1
-                    break foriLoop;
-                  }
-                }
-                if (candidateWithTabIndexZero == null && element.tabIndex == 0) {
-                  candidateWithTabIndexZero = element;
-                }
-              }
-            }
-          }
-        }
-      }
-      if (candidate != null) {
-        try {
-          // focus() on not visible elements breaks IE
-          candidate.focus();
-        } catch (ex) {
-        }
-      } else if (candidateWithTabIndexZero != null) {
-        try {
-          // focus() on not visible elements breaks IE
-          candidateWithTabIndexZero.focus();
-        } catch (ex) {
-        }
-      }
-    } else if (this.focusId.length > 0) {
-      console.warn('Cannot find component to set focus : \"' + this.focusId + '\"'); // @DEV_ONLY
+    var $autoFocus = Tobago.Utils.selectWithJQuery(elements, '[autofocus]');
+    var hasAutoFocus = $autoFocus.size() > 0;
+    if (hasAutoFocus) {
+      // nothing to do, because the browser make the work.
+
+      // autofocus in popups doesn't work automatically... so we fix that here
+      jQuery('.modal').on('shown.bs.modal', function() {
+        Tobago.setFocus(jQuery(this).find('[autofocus]'));
+      });
+
+      return;
     }
 
-  },
+    if (elements) {
+      // seems to be AJAX, so end here
+      return;
+    }
 
+    var lastFocusId = Tobago.findSubElementOfPage("lastFocusId").val();
+    if (lastFocusId) {
+      Tobago.setFocus(jQuery(Tobago.Utils.escapeClientId(lastFocusId)));
+      return;
+    }
 
-  /**
-   * check if a component type is valid to receive the focus
-   */
-  isFocusType: function(type) {
-    if (type == 'text'
-        || type == 'textarea'
-        || type == 'select-one'
-        || type == 'select-multiple'
-      //       ||  type == 'button'
-        || type == 'checkbox'
-      // || type == 'file'
-        || type == 'password'
-        || type == 'radio'
-        || type == 'reset'
-        || type == 'submit'
-        ) {
-      return true;
+    var $firstInput = jQuery(":input:enabled:visible:not(button):not([tabindex='-1']):first");
+    if ($firstInput.size() > 0) {
+      Tobago.setFocus($firstInput);
+      return;
     }
-    else {
-      return false;
+  },
+
+  setFocus: function($element) {
+    try {
+      // focus() on not visible elements breaks some IE
+      $element.focus();
+    } catch (e) {
+      console.error("element-id=" + $element.attr("id") + " exception=" + e); // @DEV_ONLY
     }
   },