1(function($){ 2 const $backdrop = $('#mBackdrop'); 3 const $dialog = $('#mDialog'); 4 const $title = $('#mTitle'); 5 const $body = $('#mBody'); 6 7 let lastFocus = null; 8 9 function trapFocus(e){ 10 if(e.key !== 'Tab') return; 11 const f = $dialog.find('a,button,input,textarea,select,[tabindex]:not([tabindex="-1"])') 12 .filter(':visible:not([disabled])'); 13 if(!f.length) return; 14 const first = f[0], last = f[f.length-1]; 15 if(e.shiftKey && document.activeElement === first){ e.preventDefault(); last.focus(); } 16 else if(!e.shiftKey && document.activeElement === last){ e.preventDefault(); first.focus(); } 17 } 18 19 function openModal(opts){ 20 const o = Object.assign({ title:'', html:'', focus: null }, opts||{}); 21 lastFocus = document.activeElement; 22 23 $title.text(o.title || ''); 24 (typeof o.html === 'string') ? $body.html(o.html) : $body.empty().append(o.html); 25 26 $('body').addClass('has-modal-open'); 27 $backdrop.prop('hidden', false).addClass('is-open'); 28 $dialog.prop('hidden', false).addClass('is-open'); 29 30 setTimeout(function(){ 31 const $focusEl = o.focus ? $dialog.find(o.focus) : $dialog.find('.m-close'); 32 ($focusEl[0] || $dialog[0]).focus(); 33 }, 0); 34 35 $(document).on('keydown.modal', function(e){ 36 if(e.key === 'Escape') closeModal(); 37 trapFocus(e); 38 }); 39 } 40 41 function closeModal(){ 42 $backdrop.removeClass('is-open'); 43 $dialog.removeClass('is-open'); 44 setTimeout(function(){ 45 $backdrop.prop('hidden', true); 46 $dialog.prop('hidden', true); 47 $('body').removeClass('has-modal-open'); 48 $(document).off('keydown.modal'); 49 if(lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus(); 50 }, 150); 51 } 52 53 // Public API 54 window.openModal = openModal; 55 window.closeModal = closeModal; 56 57 // Close bằng backdrop 58 $backdrop.on('click', closeModal); 59 60 // Close bằng nút trong dialog (bind TRá»°C TIẾP Äá» không phụ thuá»c bubbling) 61 $dialog.on('click', '.m-close,[data-modal-close]', function(e){ 62 e.preventDefault(); 63 e.stopPropagation(); 64 closeModal(); 65 }); 66 67 // (KHÃNG) chặn ná»i bá»t cho toà n modal nữa â Äá» nút Äóng hoạt Äá»ng bình thưá»ng 68 // $dialog.on('click', function(e){ e.stopPropagation(); }); 69 70 // DEMO: nút má» modal 71 $(document).on('click', '.open-modal', function(e){ 72 e.preventDefault(); 73 const title = $(this).data('title') || 'Thông tin'; 74 const html = $(this).data('html') || '<p>Không có ná»i dung.</p>'; 75 openModal({ title, html }); 76 }); 77 78})(jQuery); 79
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.