[Javascript] Bootstrap Modal 위 Modal

2016. 5. 4. 16:52Coders

Bootstrap에서, 모달 위에 모달을 띄울 경우, tabindex 속성을 -1 로 주면 Escape 키로 닫히게 됩니다. 웹 표준을 지키려면(?) 내지는 깔끔한 웹 페이지를 위해선, 모달 위에 모달을 띄워선 안 되겠지만, 부득이한 이유로, 또는 내 페이지를 누군가 호출할 때 등등 모달 위에 모달을 띄울 경우가 있게 됩니다.


Escape키 문제는 제껴두더라도, 이런 때에 우선적으로 jQuery의 포커스 주기가 무한루프로 맛이 가게 됩니다. 화면상에서 맛이 가진 않지만, 콘솔로 보면 알 수 있으며, 특히, tabindex가 -1로 설정되어 있을 경우에는 Escape 키를 누르게 되면, 먼저 띄운 모달 창이 먼저 닫히는 불상사가 일어나게 됩니다. (우리가 모달을 쓰는 주 목적이 그 부모 윈도우가 포커스를 받지 못하도록 하는 거 잖아요.)


그래서, 꼼수를 좀 부리면, 일단, 무한루프 오류는 다음과 같이 document.ready에서 잡아주면,  해결이 됩니다.

$.fn.modal.Constructor.prototype.enforceFocus = function () { };


그러나 이도 좀 모자란 것이 이러한 형태로 jQuery의 오류를 잡는다 하더라도, 모달위의 모달 창을 닫으면, 그 이후 포커스가 부모 모달로 전달되지 않는 문제가 있습니다.

이에 대해서 꼼수를 더해 보면, 모달을 띄울 때마다 해당 모달 객체를 리스트에 저장해 놓고, (리스트의 끝 부분에는 항상 마지막에 띄운 모달 객체가 들어가겠죠.) 모달이 닫힐 때에 해당 모달 객체를 리스트에서 제거하면서, 그 이전 항목에게 포커스를 주면 되겠다 싶은 생각에 착안하여, 다음과 같은 스크립트를 만들어 보았습니다.

//모달 목록 (Modal List)
var recentModalList = [];

$(document).ready(function () {
    //Modal on Modal : jquery-1.9.1.js:3257 Uncaught RangeError: Maximum call stack size exceeded.
    $.fn.modal.Constructor.prototype.enforceFocus = function () { };

    //모달이 뜰 때 객체를 리스트에 추가 (Add modal to list)
    $('.modal').on('shown.bs.modal', function (e) {
        recentModalList.push(e.target);
    });

    //모달이 닫힐 때 객체를 리스트에서 삭제. (Remove modal from list)
    $('.modal').on('hide.bs.modal', function (e) {
        customModalClosed(e);
        console.log(recentModalList.length);
    });
});

var customModalClosed = function (e) {
    //나를 지운다.(Remove me in list)
    for (var i = recentModalList.length - 1; i >= 0; i--) {
        if (recentModalList[i] == e.target) {
            recentModalList.splice(i, 1);
        }
    }

    //이전 모달이 있으면 포커싱.(Focus to before modal)
    if (recentModalList.length > 0) {
        recentModalList[recentModalList.length - 1].focus();
    }
};

//동적 모달일 경우, document.ready의 이벤트가 안 먹기 때문에 이걸로 호출.
var showModalCustom = function (modalObj) {

    //모달이 뜰 때 객체를 리스트에 추가 (Add modal to list)
    modalObj.on('shown.bs.modal', function (e) {
        $(this).off(e); //이벤트 제거
        recentModalList.push(e.target);
    });

    modalObj.on('hide.bs.modal', function (e) {
        $(this).off(e); //이벤트 제거
        customModalClosed(e);
        console.log(recentModalList.length);
    });

    modalObj.modal('show');
};

사용은, 일반적인 모달일 경우(html 코드에 원래 존재하는 모달) 다음과 같이 그냥 띄우면 됩니다.

$('#myModal').modal('show');


만약, 동적으로 삽입된 모달이 있을 경우에는, showModalCustom 함수를 사용하여 띄우면 됩니다.

showModalCustom($('#myModal'));


customModalClosed 의 for-loop 의 "나를 지운다" 에서 지우고 break; 를 넣지 않은 건, 그래선 안 되겠지만 혹시라도 스크립트의 오류로 목록에서 제거되지 못한 모달이 있을 경우도 싸그리 밀어 버리기 위해서 입니다.


Javascript, jQuery는 빡세지만 좀 재미 있네요.

'Coders' 카테고리의 다른 글

[Javascript] 내 이름을 찾아줘  (0) 2016.05.04
[MSSQL] 중복 데이터 조회, 삭제  (0) 2016.02.02
[C#]즐기는 코딩 생활(WinForm)  (0) 2016.01.26