Requirement

For a customer I needed to integrate the possibility to use the function key (Fx) on keyboard in a specific page in ADF to control button actions alternatively and in a fast way. The idea was to navigate the dataset via PageUp/PageDown and save the data on F5.

ADF does not offer functionalities like these and we have to keep in mind that we are living in a browser environment where control keys are catched by the browser as default.

Solution

One of the further problems is that we want this shortcut functionality only in a specific page fragment and not everywhere! Only here we have the buttons we want to click with the help of the shortcuts. Of cause we don’t want to hardcode something to be flexible where to place the taskflow in a region.

Base integration

The base idea is to catch the function key events via javascript and press the button for the specific action from client side. First obvious problem is that we don’t know for sure what is the absolut ID of the buttons in my taskflow. We could run in a popup or in a very deep level inside the DOM.

So the best idea is to pass this information to the javascript logic from server side!

First we place a function to javascript of the fragment where we want to have the shortcut keys. A good source to find the key codes is this url:

https://www.mediaevent.de/javascript/Extras-Javascript-Keycodes.html

function fallTasten(e, bSave) {

  e = e || window.event;

  if (e.keyCode == 116) {
  
    // F5 key preshed - prevent default action from browser (here: Refresh Page)
    e.preventDefault();
    var saveButton = AdfPage.PAGE.findComponentByAbsoluteId(bSave);
    
    if (!saveButton.getProperty("disabled")) {
      AdfActionEvent.queue(saveButton, saveButton.getPartialSubmit());
    }

  }

}

On server side we need to call logic one time on fragment entry. For this I used an af:poll component inside this fragment which has a pollListener. This poll has an intervall of short 100ms and it deactiveates itself after the listener run one time. Via this javascript code I call the predefined function.

<af:poll id="pTasten" interval="100" immediate="true"
                                 pollListener="#{backingBeanScope.einzelfallZe.pollTastenListener}"/>

I add a new event listener to the document which handles key events globally and trigger our own handler function.

public void pollTastenListener(PollEvent pollEvent) {

  String script =
  "function tastenEvent(e) {fallTasten(e, '" + getSaveButton().getClientId() + "');}"+
  "document.addEventListener('keydown', tastenEvent);";

  injectJSToPage(script);

  // deactivation of further poll events
  RichPoll poll = (RichPoll) pollEvent.getComponent();
  poll.clearInitialState();
  poll.setInterval(-1);
  poll.setRendered(false);
  AdfFacesContext.getCurrentInstance().addPartialTarget(poll.getParent().getParent());

}

private void injectJSToPage(String script) {
  FacesContext facesContext = FacesContext.getCurrentInstance();
  ExtendedRenderKitService erks = Service.getService(facesContext.getRenderKit(), ExtendedRenderKitService.class);
  erks.addScript(facesContext, script);
}

After we leave the fragment we have to remove this event listener to avoid unwanted actions via shortcuts on other fragments. You could use the „back“ button action or whatever you use to navigation to another taskflow or close it.

injectJSToPage("document.removeEventListener('keydown', tastenEvent);");