Introduction
I recently worked on the
BACK Navigation
in a project where a great B2B Portal has been created via a custom BSP application designed according to the MVC pattern.APPROACH 1 - SETTINGS - Tuning cache settings
Via SE80 it is possible to specify caching parameters on each controller.
An example:
The first thing to know is that the "Page has Expired" warning page is generated by the browser only if Browser or Server cache value is not set.> No cache, then get "Warning: Page has Expired. ...". <
Are you working with
stateless
applications? If yes, set the Browser cache to 3600 and skip the rest of the Blog.statefull
applications to use cache.> Statefull application with cache, then get the client (Browser) to be NOT synchronized with the server (BSP application) <
Let me explain: let's take a shopping cart application.
The collection of items in the cart will be maintained in an ABAP internal table binded in the cart view. Then, if a user perform a BACK Navigation he/she will see a previous cart; different items will be displayed in the browser then what are in the ABAP table.
I don't want to think what will happen if an action is requested for an item that is no more in the cart (add_item(1),add_item(2),drop_item(1),BACK Navigation, BACK Navigation, update_item(1))...
APPROACH 2 - SETTINGS - Hiding BACK Button to the user
> Statefull application in a window without buttons - If your users like it... <
Please note that
right-clicking
on the page the Back command is still there..In any case, in order to disable the Backspace Navigation,
> do not forget to make use of the <htmlb:document disableBackspaceNavigation="TRUE"> <
APPROACH 3 - JAVASCRIPT - An easy and powerful solution
> With <B>history.forward()</B>, BACK Navigation is no more a Nightmare <
Picture - BSP Extension - DisableBackspaceNavigation
Picture - BSP Extension - DisableBackspaceNavigation - Attributes
Picture - BSP Extension - Class - Attribute
Picture - BSP Extension - Class - Methods
DO_AT_BEGINNING source code:
Version improved by Mario Vangerven (it uses a cookie):
WHEN 'TRUE'.
Get returnPage
DATA: l_return_page TYPE string.
DATA: o_http_request_warning_page TYPE REF TO if_http_request.
o_http_request_warning_page = me->m_page_context->get_request( ).
l_return_page = o_http_request_warning_page->if_http_entity~get_form_field( name = 'returnPage' ).
Render A HREF TAG
CONCATENATE html cl_abap_char_utilities=>cr_lf 'Server Step Id: ' me->server_step_id ' '');'
cl_abap_char_utilities=>cr_lf '' cl_abap_char_utilities=>cr_lf
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
''
''');' cl_abap_char_utilities=>cr_lf
'document.write(''
Render client-side Java Script function history.forward()
WHEN 'CLIENT'.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'Server Step Id: ' me->server_step_id ' '');' cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
Get AgentStepId
INTO html.
WHEN 'SERVER'.
Get the cookie from the root path
=> now we can even jump from one application to the other and still disable the back button
DATA: o_http_request TYPE REF TO if_http_request.
o_http_request = me->m_page_context->get_request( ).
CALL METHOD o_http_request->if_http_entity~get_cookie
EXPORTING
name = 'AgentStepId'
path = '/'
IMPORTING
Calculate ServerStepId
value = me->agent_step_id.
DATA: l_server_step_id_int TYPE i.
DATA: l_server_step_id_str TYPE string.
IF me->agent_step_id IS INITIAL.
me->server_step_id = '0'.
ELSE.
IF me->agent_step_id > me->server_step_id.
me->server_step_id = me->agent_step_id.
ADD 1 TO me->server_step_id.
ELSE.
me->server_step_id = me->agent_step_id.
ADD 1 TO me->server_step_id.
Render complex client-side Java Script function
ENDIF.
ENDIF.
me->agent_step_id = o_http_request->if_http_entity~get_form_field( name = 'AgentStepId' ).
DATA: o_bsp_runtime TYPE REF TO if_bsp_runtime.
o_bsp_runtime = me->m_page_context->get_runtime( ).
CONCATENATE html cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
''
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'Server Step Id: ' me->server_step_id ' '');'
Set the cookie from the root path
=> now we can even jump from one application to the other and still disable the back button
cl_abap_char_utilities=>cr_lf
'jsv_cookie = "AgentStepId="+history.length+"; path=/";' cl_abap_char_utilities=>cr_lf
'document.cookie=jsv_cookie' cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
'' cl_abap_char_utilities=>cr_lf
INTO html.
ENDCASE.
ENDCASE.
*
prev_out->print_string( html ).
*
rc = co_element_continue.
ENDMETHOD.
Replace < with <
Replace > with >
that because in the weblog special characters are not fully supported in the text
Version without cookie:
*!!!!!!!! ATTENTION !!!!!!!!!*
********************************
METHOD if_bsp_element~do_at_beginning .
DATA: html TYPE string.
DATA: prev_out TYPE REF TO if_bsp_writer.
Get returnPage
prev_out = me->get_previous_out( ).
CASE me->returnlinkgenerate.
WHEN 'TRUE'.
DATA: l_return_page TYPE string.
Render A HREF TAG
DATA: o_http_request_warning_page TYPE REF TO if_http_request.
o_http_request_warning_page = me->m_page_context->get_request( ).
l_return_page = o_http_request_warning_page->if_http_entity~get_form_field( name = 'returnPage' ).
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<script>' cl_abap_char_utilities=>cr_lf
'document.write(''<B>Server Step Id: </B> ' me->server_step_id '</br>'');' cl_abap_char_utilities=>cr_lf
'</script>' cl_abap_char_utilities=>cr_lf
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<!-- DisableBackNavigation Extension - Begin --!>'
'<script language=JavaScript>' cl_abap_char_utilities=>cr_lf
'document.write(''<form method="POST" name="formWBN" action="' l_return_page '">'');' cl_abap_char_utilities=>cr_lf
'document.write(''<input name="AgentStepId" type="HIDDEN" value="''+history.length+''"/>'');' cl_abap_char_utilities=>cr_lf
'document.write(''<A HREF="javascript:void(document.formWBN.submit())">' me->returnlinktext '</A>'');' cl_abap_char_utilities=>cr_lf
'document.write(''</form>'');' cl_abap_char_utilities=>cr_lf
'</script>' cl_abap_char_utilities=>cr_lf
'<!-- DisableBackNavigation Extension - End --!>' cl_abap_char_utilities=>cr_lf
INTO html.
Render client-side Java Script function history.forward()
WHEN OTHERS.
CASE me->type.
WHEN 'CLIENT'.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<script>' cl_abap_char_utilities=>cr_lf
'document.write(''<B>Server Step Id: </B> ' me->server_step_id '</br>'');' cl_abap_char_utilities=>cr_lf
'</script>' cl_abap_char_utilities=>cr_lf
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<!-- DisableBackNavigation Extension - Begin --!>' cl_abap_char_utilities=>cr_lf
'<script language=JavaScript>' cl_abap_char_utilities=>cr_lf
'history.forward();' cl_abap_char_utilities=>cr_lf
'</script>' cl_abap_char_utilities=>cr_lf
Get AgentStepId
'<!-- DisableBackNavigation Extension - End --!>' cl_abap_char_utilities=>cr_lf
INTO html.
WHEN 'SERVER'.
Calculate ServerStepId
DATA: o_http_request TYPE REF TO if_http_request.
o_http_request = me->m_page_context->get_request( ).
me->agent_step_id = o_http_request->if_http_entity~get_form_field( name = 'AgentStepId' ).
DATA: l_server_step_id_int TYPE i.
DATA: l_server_step_id_str TYPE string.
IF me->agent_step_id IS INITIAL.
me->server_step_id = '0'.
ELSE.
IF me->agent_step_id > me->server_step_id.
me->server_step_id = me->agent_step_id.
ADD 1 TO me->server_step_id.
ELSE.
me->server_step_id = me->agent_step_id.
Render complex client-side Java Script function
ADD 1 TO me->server_step_id.
ENDIF.
me->agent_step_id = o_http_request->if_http_entity~get_form_field( name = 'AgentStepId' ).
ENDIF.
DATA: o_bsp_runtime TYPE REF TO if_bsp_runtime.
o_bsp_runtime = me->m_page_context->get_runtime( ).
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<!-- DisableBackNavigation Extension - Begin --!>' cl_abap_char_utilities=>cr_lf
'<script language=JavaScript>' cl_abap_char_utilities=>cr_lf
' if (' me->server_step_id '>0)' cl_abap_char_utilities=>cr_lf
' {' cl_abap_char_utilities=>cr_lf
' if (history.length<' me->server_step_id ')' cl_abap_char_utilities=>cr_lf
' history.forward();' cl_abap_char_utilities=>cr_lf
' else ' cl_abap_char_utilities=>cr_lf
' {' cl_abap_char_utilities=>cr_lf
' if (history.length>' me->server_step_id ')' cl_abap_char_utilities=>cr_lf
' {' cl_abap_char_utilities=>cr_lf
' location.href=''' me->warningpage '?returnPage=' o_bsp_runtime->page_name ''';' cl_abap_char_utilities=>cr_lf
' }' cl_abap_char_utilities=>cr_lf
' }' cl_abap_char_utilities=>cr_lf
' }' cl_abap_char_utilities=>cr_lf
'</script>'
INTO html.
CONCATENATE html cl_abap_char_utilities=>cr_lf
'<script language=JavaScript>' cl_abap_char_utilities=>cr_lf
'document.write(''<B>Server Step Id: </B> ' me->server_step_id '</br>'');' cl_abap_char_utilities=>cr_lf
'document.write(''<input name="AgentStepId" type="HIDDEN" value="''history.length''"/>'');' cl_abap_char_utilities=>cr_lf
'</script>' cl_abap_char_utilities=>cr_lf
'<!-- DisableBackNavigation Extension - End --!>' cl_abap_char_utilities=>cr_lf
INTO html.
ENDCASE.
ENDCASE.
*
prev_out->print_string( html ).
*
rc = co_element_continue.
*
ENDMETHOD.
A SAMPLE APPLICATION
Create a statefull BSP application:
Picture - Web application
Create following controllers:
Picture - Controller for the client implementation
Picture - Controller for the Server implementation
Picture - Controller for the warning Page
Create following views:
mainClientimplementation.htm
That's all.