Cara membuat tampilan khusus untuk lansiran (), konfirmasi () dan prompt () untuk digunakan dalam JavaScript

Saya telah lama berpikir untuk menyesuaikan tampilan fungsi interaksi pengguna pada JavaScript - alert (), confirm () dan prompt () (selanjutnya modal windows).
Memang, mereka sangat nyaman digunakan, tetapi berbeda di browser yang berbeda dan sangat tidak enak dipandang.
Akhirnya, tangan-tangan itu meraih.
Apa masalahnya? Cara biasa untuk mengeluarkan dialog (misalnya, bootstrap) tidak dapat digunakan semudah mengingatkan, di mana browser mengatur kode JavaScript untuk berhenti mengeksekusi dan menunggu tindakan pengguna (mengklik tombol tutup). Modal dalam bootstrap akan membutuhkan penanganan acara terpisah - mengklik tombol, menutup jendela modal ...
Namun demikian, saya telah menggunakan penyesuaian lansiran di game untuk mengganti pesan standar dengan pesan yang sesuai dengan gaya desain game. Ini berfungsi dengan baik, termasuk pesan kesalahan koneksi dan situasi sistem lainnya. Tetapi ini tidak akan berfungsi jika pengguna perlu menunggu jawaban!
gambar
Dengan munculnya Janji dalam ECMAScript 6 (ES6), semuanya mungkin!
Saya menerapkan pendekatan memisahkan desain modal windows dan kode (alert (), confirm () dan prompt ()). Tetapi Anda dapat menyembunyikan semua yang ada dalam kode. Apa yang menarik dari pendekatan semacam itu - desain dapat diubah dalam proyek yang berbeda, tetapi hanya pada halaman yang berbeda atau tergantung pada situasinya.
Poin buruk tentang pendekatan ini adalah perlunya menggunakan nama markup (id) dalam kode modal windows, dan bahkan dalam lingkup global. Tapi ini hanya contoh dari prinsip, jadi saya tidak akan fokus pada ini.

Mendapatkan kode untuk lansiran


Jadi, mari kita lihat markup (bootstrap dan Font Awesome untuk ikon font) dan kode peringatan (saya menggunakan jQuery):
    <div id="PromiseAlert" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-exclamation-triangle text-warning"></i> <span>The app reports</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">ร—</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">OK</button>
                </div>
            </div>
        </div>
    </div>

    window.alert = (message) => {
        $('#PromiseAlert .modal-body p').html(message);
        var PromiseAlert = $('#PromiseAlert').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        return new Promise(function (resolve, reject) {
            PromiseAlert.on('hidden.bs.modal', resolve);
        });
    };

Seperti yang saya katakan di atas, nama global PromiseAlert dan kelas markup html digunakan untuk kode. Di baris pertama kode, parameter fungsi peringatan dilewatkan ke badan pesan. Setelah itu, metode bootstrap menampilkan jendela modal dengan opsi tertentu (mereka membuatnya lebih dekat dengan peringatan asli). Penting! Jendela modal diingat dalam variabel lokal, yang digunakan di bawah ini melalui penutupan.
Akhirnya, itu dibuat dan dikembalikan sebagai hasil dari Janji janji, di mana, sebagai akibat dari menutup jendela modal, menyelesaikan Janji ini dieksekusi.
Sekarang mari kita lihat bagaimana peringatan ini dapat digunakan:
    $('p a[href="#"]').on('click', async (e) => {
        e.preventDefault();
        await alert('Promise based alert sample');
    });

Dalam contoh ini, sebuah pesan ditampilkan saat mengklik tautan kosong dalam paragraf. Memperhatikan! Untuk memenuhi spesifikasi, fungsi peringatan harus didahului oleh kata kunci yang menunggu, dan hanya dapat digunakan di dalam fungsi dengan kata kunci async. Ini memungkinkan Anda untuk mengharapkan di tempat ini (skrip akan berhenti, seperti dalam kasus dengan peringatan asli), penutupan jendela modal.
Apa yang akan terjadi jika ini tidak dilakukan? Tergantung pada logika aplikasi Anda (contoh dari pendekatan seperti pada gambar di atas). Jika ini adalah akhir dari kode atau tindakan selanjutnya dari kode tidak membebani halaman, maka semuanya mungkin akan baik-baik saja! Jendela modal melorot sampai pengguna menutupnya. Tetapi jika masih ada modal windows atau jika halaman reload, ada transisi ke halaman lain, maka pengguna tidak akan melihat jendela modal Anda dan logikanya akan dihancurkan. Saya dapat mengatakan bahwa dari pengalaman, pesan tentang berbagai kesalahan server (status) atau dari pustaka kode berfungsi dengan baik dengan peringatan baru kami, meskipun mereka tidak menggunakan menunggu.

Kami mengembangkan pendekatan untuk konfirmasi


Mari kita melangkah lebih jauh. Tanpa ragu, konfirmasi hanya dapat digunakan dalam pengikatan async / wait, as ia harus memberi tahu kode hasil pilihan pengguna. Ini juga berlaku untuk prompt. Jadi konfirmasikan:
    <div id="PromiseConfirm" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-check-circle text-success"></i> <span>Confirm app request</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">ร—</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p></p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-success" data-dismiss="modal">OK</button>
                    <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    window.confirm = (message) => {
        $('#PromiseConfirm .modal-body p').html(message);
        var PromiseConfirm = $('#PromiseConfirm').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        let confirm = false;
        $('#PromiseConfirm .btn-success').on('click', e => {
            confirm = true;
        });
        return new Promise(function (resolve, reject) {
            PromiseConfirm.on('hidden.bs.modal', (e) => {
                resolve(confirm);
            });
        });
    };

Hanya ada satu perbedaan - kita perlu menginformasikan tentang pilihan pengguna. Ini dilakukan dengan menggunakan variabel lokal lain dalam penutupan - konfirmasi. Jika tombol konfirmasi ditekan, variabel diatur ke true, dan secara default nilainya salah. Nah, saat memproses penutupan modal window, resolusinya mengembalikan variabel ini.
Berikut adalah penggunaannya (diperlukan dengan async / menunggu):
    $('p a[href="#"]').on('click', async (e) => {
        e.preventDefault();
        if (await confirm('Want to test the Prompt?')) {
            let prmpt = await prompt('Entered value:');
            if (prmpt) await alert(`entered: ยซ${prmpt}ยป`);
            else await alert('Do not enter a value');
        }
        else await alert('Promise based alert sample');
    });

Pindah - pendekatan untuk prompt


Logika di atas juga diimplementasikan dengan prompt tes. Dan markup dan logikanya adalah sebagai berikut:
    <div id="PromisePrompt" class="modal">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title"><i class="fas fa-question-circle text-primary"></i> <span>Prompt request</span></h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">ร—</span>
                    </button>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="PromisePromptInput"></label>
                        <input type="text" class="form-control" id="PromisePromptInput">
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-success" data-dismiss="modal">OK</button>
                    <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </div>

    window.prompt = (message) => {
        $('#PromisePrompt .modal-body label').html(message);
        var PromisePrompt = $('#PromisePrompt').modal({
            keyboard: false,
            backdrop: 'static'
        }).modal('show');
        $('#PromisePromptInput').focus();
        let prmpt = null;
        $('#PromisePrompt .btn-success').on('click', e => {
            prmpt = $('#PromisePrompt .modal-body input').val();
        });
        return new Promise(function (resolve, reject) {
            PromisePrompt.on('hidden.bs.modal', (e) => {
                resolve(prmpt);
            });
        });
    };

Perbedaan antara logika dan konfirmasi adalah minimal. Variabel lokal tambahan dalam penutupan adalah prmpt. Dan itu tidak memiliki nilai logis, tetapi string yang dimasukkan pengguna. Melalui penutupan, nilainya teratasi. Dan nilai diberikan hanya ketika tombol konfirmasi ditekan (dari kolom input). Ngomong-ngomong, di sini saya menyia-nyiakan variabel global lain, PromisePromptInput, hanya untuk steno dan kode alternatif. Dengan itu, saya mengatur fokus input (meskipun dapat dilakukan dalam satu pendekatan - baik dengan cara yang sama atau dalam mendapatkan nilai).
Anda dapat mencoba pendekatan ini dalam tindakan di sini . Kode ini terletak di tautan .
Kelihatannya seperti ini (meskipun tautan di atas lebih beragam):
gambar

AIDS


Mereka tidak berhubungan langsung dengan topik artikel, tetapi mereka mengungkapkan fleksibilitas penuh dari pendekatan tersebut.
Ini termasuk tema bootstrap. Saya mengambil tema gratis di sini .
Beralih bahasa menggunakan instalasi otomatis sesuai dengan bahasa browser. Ada tiga mode - otomatis (melalui browser), Rusia atau Inggris (dipaksakan). Mesin diinstal secara default.
Cookie ( dari sini ) Saya biasa menghafal tema dan pergantian bahasa.
Tema beralih hanya dengan menginstal segmen href css dari situs di atas:
    $('#themes a.dropdown-item').on('click', (e) => {
        e.preventDefault();
        $('#themes a.dropdown-item').removeClass('active');
        e.currentTarget.classList.add('active');
        var cur = e.currentTarget.getAttribute('href');
        document.head.children[4].href = 'https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/' + cur + 'bootstrap.min.css';
        var ed = new Date();
        ed.setFullYear(ed.getFullYear() + 1);
        setCookie('WebApplicationPromiseAlertTheme', cur, ed);
    });

Yah, saya ingat di Cookies untuk pemulihan saat boot:
    var cookie = getCookie('WebApplicationPromiseAlertTheme');
    if (cookie) {
        $('#themes a.dropdown-item').removeClass('active');
        $('#themes a.dropdown-item[href="' + cookie + '"]').addClass('active');
        document.head.children[4].href = 'https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/' + cookie + 'bootstrap.min.css';
    }

Untuk pelokalan, saya menggunakan file localization.json di mana saya membuat kamus kunci dalam bahasa Inggris dan nilainya dalam bahasa Rusia. Untuk kesederhanaan (meskipun markup menjadi lebih rumit di beberapa tempat), saya hanya memeriksa node teks murni ketika menerjemahkan, mengganti kunci dari nilai.
    var translate = () => {
        $('#cultures .dropdown-toggle samp').text({ ru: '  ', en: ' English ' }[culture]);
        if (culture == 'ru') {
            let int;
            if (localization) {
                for (let el of document.all)
                    if (el.childElementCount == 0 && el.textContent) {
                        let text = localization[el.textContent];
                        if (text) el.textContent = text;
                    }
            }
            else int = setInterval(() => {
                if (localization) {
                    translate();
                    clearInterval(int);
                }
            }, 100);
        }
        else location.reload();
    };
    if (culture == 'ru') translate();

jadi sulit melakukan produksi (lebih baik di server), tapi di sini saya bisa menunjukkan semuanya pada klien. Saya mengakses server hanya ketika mengubah dari bahasa Rusia ke bahasa Inggris - Saya hanya membebani markup asli (location.reload).
Yang terakhir, seperti yang diharapkan, pesan di onbeforeunload dikeluarkan sesuai dengan algoritma browser dan konfirmasi kami tidak memengaruhi ini. Di akhir kode ada versi komentar dari pesan semacam itu - Anda dapat mencobanya saat Anda mentransfernya sendiri.
    //window.onbeforeunload = function (e) {
    //    e.returnValue = 'Do you really want to finish the job?';
    //    return e.returnValue;
    //};

All Articles