peckadesign / pd-naja

1 stars 0 forks source link

Ajax modal history broken #1

Closed zipper closed 4 months ago

zipper commented 1 year ago

Ajax modal might break browser history in some circumstances. Steps to reproduce:

  1. In new window, navigate to page with some ajax modal links.
  2. Click such a link, leading to a page, that also has ajax modal link. The modal should open.
  3. While modal from step (2) is opened, refresh the page. The same page should appear, but outside the modal window.
  4. On page from step (3), click to open another ajax modal.
  5. Then use browser history to navigate back.
    1. First click will close the modal and change url properly. The page will get reloaded.
    2. Second navigate back results in URL changing to first page, but the content is not changed, because Naja handled the navigation, but had not enough information. We need to reload this page as wel.

The issue is, that inside buildState event handler, the pdModal object gets overriden, in step (4). The page has been refreshed in (3), so HistoryHandler.initialized is false, therefore HistoryHandler.replaceInitialState is being called, leading to buildState, where we can't tell, that the pdModal should remains untouched.

Proposed (and tested) solution would be replacing AjaxModalExtension.ts:176-180 with:

// If Naja is replacing the initial state (`HistoryHandler.replaceInitialState` call) and there already is
// `pdModal` configuration in history state, we need to preserve that configuration.
if (options.replaceInitialState && window.history.state.pdModal) {
    state.pdModal = window.history.state.pdModal
} else {
    state.pdModal = {
        isShown,
        historyDirection: isShown ? this.historyDirection : null,
        options: isShown ? this.modalOptions : null
    }
}

This requires possibility to distinguish between new state being pushed and initial state being replaced. That information is currently not available in Naja, see https://github.com/naja-js/naja/issues/380. In code snippet above, that is represented by options.replaceInitialState.