Марафон. Фронтенд. Створення jQuery плагін для вікторини.

Фронтенд розробка JavaScript. -> Формулювання задачі.

Формулювання задачі.

Взяти готовий шаблон фронтенд програми.

start page

посилання на репозиторій із шаблоном

Використовуючи REST API бекенд, розташований за адресою http://quiz.webmonstr.com/

Адмінка http://quiz.webmonstr.com/admin

Логін - admin

Пароль - admin

Створити програму, використовуючи бібліотеку jQuery у вигляді плагіна.

Підключення плагіна на сторінці.

  <script src="app.js"></script>
  <script>
      var app = $('#rootBlock').quizPlugin();
      app.start();
  </script>

Суть роботи програми:

Спочатку перевіряється змінна username в localStorage браузера.

Якщо цієї змінної немає, користувачу виводиться форма авторизації зі списком стікерів і полем, де він вказує своє ім’я.

Стікери запитуються за адресою http://quiz.webmonstr.com/v1/quiz/sticker/list

Після введення імені та вибору стікера надіслати на адресу http://quiz.webmonstr.com/v1/quiz/player/join POST запит із даними json у форматі:

{
  "name": "string",
  "sticker_id": 0
}

Проаналізуйте відповідь від сервера.

У разі успішної відповіді (відсутність у ньому поля error):

  1. Зберегти ім’я користувача localStorage.

  2. Забрати форму авторизації.

  3. Вивести чат-кімнату.

У разі помилки вивести її на сторінку над кнопкою форми червоним кольором.

Виведення чат-кімнати.

  1. Запросити поточних гравців та вивести у блоці #playerListBlock згідно з дизайном.

Виводимо стікер та ім’я користувача.

Замість слова Admin виводить поточний рахунок користувача.

Запросити список гравців можна за адресою:

http://quiz.webmonstr.com/v1/quiz/player/list
  1. Запитати поточне питання вікторини та вивести в блоці #questionBlock

Адреса запиту:

http://quiz.webmonstr.com/v1/quiz/get_current_question

Формат відповіді.

{
  "lang": "ru",
  "level": 3,
  "tp": "questionend",
  "mode": "fullmatch",
  "theme": 4,
  "question": "Яке слово утворене від початкових слів пісні «Чарівна Катарина»?",
  "answers": "ШАРМАНКА",
  "is_published": true,
  "order": 1
}
  1. Запитати список відповідей та вивести у блоці chatMessageBlock згідно з дизайном.

Адреса запиту.

Формат відповіді.

Відповіді, позначені як неправильні, виводити на рожевому фоні, правильні – на салатовому.

  1. Під час введення відповіді та натискання на кнопку Send або клавіші Enter надсилати POST повідомлення на сервер.

Відповідь надсилатиме лише у випадку не порожнього повідомлення.

Адреса.

http://localhost:7777/v1/quiz/save_message

Формат даних, що надсилаються:

{
  "message": "string",
  "playername": "string"
}

Відповідь ігнорувати.

  1. Створити веб-сокет з’єднання із сервером.

Адреса веб-сокет з’єднання.

ws://localhost:7777/quiz/

Забезпечити реакцію програми на такі повідомлення.

Повідомлення про нове повідомлення.

Формат повідомлення:

{ 
    'type': 'quiz_message', 
    'message': {...}
}

При надходженні повідомлення:

  1. Вивести його у списку повідомлень згідно з дизайном та логікою описаною вище.

  2. Якщо повідомлення позначене як правильне,

    2.1 Оновити список гравців (або використовувати повідомлення про оновлення облікового запису див. нижче) та програти довільний звук.

    2.2 Запитати наступне питання та оновити блок #questionBlock

Повідомлення про видалення повідомлення.

Формат.

{ 
    'type': 'quiz_delete_message', 
    'message': {...}
}

При надходженні повідомлення видаляти його зі списку ID у повідомленні.

Повідомлення про оновлення облікового запису.

{ 
    'type': 'quiz_update_account', 
    'message': {...}
}

При надходженні повідомлення оновити обліковий запис користувача за його ID.

Фронтенд розробка JavaScript. -> Завдання для вікторини.

Завдання вікторини.

Створити фронтенд програму “Попутник” використовуючи бібліотеку jQuery.

Посилання на бекенд

Бекенд відрадить всі можливі запити на сервер, формати запитів та відповідей.

Суть програми.

Користувачеві доступно 4 розділи.

  1. Форма замовлення.

  2. Пошук замовлень.

  3. Особистий кабінет.

  4. Реєстрація.

Реєстрація.

При реєстрації користувач вводить своє ім’я та обирає місто.

Форма замовлення.

Користувач заповнює такі поля.

  1. Початкова точка подорожі.

  2. Кінцева точка подорожі.

  3. Дата та час поїздки.

Пошук замовлень.

У даному розділі користувач може провести пошук замовлень, що цікавлять, за обраним районом міста.

Далі користувач може приєднатися до подорожі.

Личный кабинет.

Особистий кабінет.

У цьому розділі користувач бачить свої замовлення або замовлення, до яких він приєднаний.

За кожним замовленням він може надіслати повідомлення всім, хто до нього приєднано.

Технічні вимоги.

Дизайн взяти на основі bootstrap та зорієнтувати на мобільну версію клієнта.

Фронтенд розробка JavaScript. -> Створення jQuery плагін для вікторини.

Фронтенд. Чат-вікторина. JQuery

Встановлення готового шаблону.

git clone git@github.com:zdimon/marafon-js-quiz-template.git

Скопіюємо його до папки public проекту.

Сервер розробки.

Поставимо простенький сервер.

npm install lite-server

Запуск.

cd public
../node_modules/lite-server/bin/lite-server

Працюватимемо всередині файлу app.js.

Пишемо плагін.

Нам спочатку необхідно створити ізольовану область видимості змінних.

(function( $ ) {
    $.fn.quizPlugin = function() {

        console.log('my plugin');

    };
})(jQuery);

В jQuery fn - це псевдонім прототипу.

Ключове слово jQuery (або $) - це лише функція-конструктор, і всі об’єкти, створювані цим конструктором будуть успадковувати всі властивості та методи його прототипу.

$.fn.quizPlugin = function() {..}

Так ми створюємо нову властивість-функцію для об’єкта jQuery, де ім’ям нової властивості буде ім’я нашого плагіна.

Для того, щоб не було конфліктів зі знаком $ рекомендується «обернути» об’єкт jQuery в функцію-вираз, що безпосередньо виконується.

Застосовуємо плагін.

<script>
      var app = $('#myapp').quizPlugin();
</script>

Перевіряємо залогіненість.

    app.start = function() {

        if(sessionStorage.getItem('username')) { 
            this.initRoom();
        } else {
            this.loginForm()
        }
    }

    app.loginForm = function() {

    }

    app.initRoom = function() {

    }

Тут ми припускаємо, що у випадку авторизованого користувача у нас існуватиме змінна username в локальному сховищі браузера.

Функція виведення форми логіну із запитом та вставкою стікерів.

    app.loginForm = function() {
        let form = $('#loginForm').show();
        let url = 'http://quizapi.webmonstr.com/v1/quiz/sticker/list';
        $.get( url, function( data ) {
            data.forEach((el) => {
                let img_tag = `<img width="50" src="${el.get_url}" />`;
                let parent = $('#stickers').append(img_tag);
             })
          });
    }

$.get - функція jQuery, що відсилає http запит.

data.forEach((el) => {}) - функція, що перебирає список.

$(‘#stickers’).append() - додавання html у вибраний елемент.

Прив’язуємо колбек до кліку на стікер, прибираючи клас активності.

 let img_tag = `<img data-id="${el.id}" class="sticker" width="50" src="${el.get_url}" />`;
...
 $('.sticker').on('click',(event)=>{
     $('.sticker').each((indx,el)=>{
         $(el).removeClass('active-sticker');
     })
     $(event.target).addClass('active-sticker');
 })

start page

$(‘.sticker’).on(‘click’,(event)=>{}) - прив’язка подій до колббека у jQuery.

Тут ми накидаємо клас sticker на елемент img щоб далі по них пройтися циклом і прибрати клас active-sticker. Далі ми встановлюємо клас active-sticker на тому зображенні, на яке клацнув користувач.

Стилізуємо клас.

.active-sticker {
    border: 1px solid red;
}

Сабмітім форму логіну.

Створимо функцію надсилання даних методом post з передачею json у запиті.

    app.submitLogin = function() {
        let data = {
            name: $('#userName').val(),
            sticker_id: this.sticker
        };
        let url = 'http://quizapi.webmonstr.com/v1/quiz/player/join';
        $.post( url, data, ( response ) => {
            sessionStorage.setItem('username',response.name);
            let form = $('#loginForm').hide();
        });
    }

$(‘#userName’).val() - отримання даних, що вводяться користувачем елемент input.

$.post( url, data, ( response ) => {}) - передача даних POST в jQuery.

Прив’яжемо функцію натискання кнопки з id = “chat-start”.

    app.loginForm = function() {
        ...
          $('#chat-start').on('click',() => {this.submitLogin()});
    }

Отримання та відображення поточного питання.

    app.getCurrentQuestion = function() {
        let url = 'http://quizapi.webmonstr.com/v1/quiz/get_current_question';
        $.get( url, ( response ) => {
            $('#currentQuestionBlock').html(response.question);
        });

    }

$(‘…’).html(content) - забрасываение html внутрь полученного элемента.

Отримання та відображення поточного питання.

    app.getMessages = function() {
        let url = 'http://quizapi.webmonstr.com/v1/quiz/message/list';
        $.get( url, ( response ) => {
            response.forEach((el)=> {
                let tpl = `                                             <div class="chat">
                <div class="chat-user">
                   <a class="avatar m-0">
                   <img src="${el.playerimage}" alt="avatar" class="avatar-35 ">
                   </a>
                   <span class="chat-time mt-1">${el.playername}</span>
                </div>
                <div class="chat-detail">
                   <div class="chat-message">
                      <p>${el.text}</p>
                   </div>
                </div>
             </div>`;
             $('#chatContent').append(tpl);
            })
        });
    };

Веб-сокет з’єднання.

    ...

    app.socketConnection = function() {
        let webSocket = new WebSocket('ws://quizapi.webmonstr.com:7777/quiz/');

        webSocket.onerror = (evt) => {

        }

        webSocket.onmessage = (event) => {
            var payload = JSON.parse(event.data)
            console.log(payload);
        }

        webSocket.onclose =  (event) => {
            console.log('Close connection');
        };

        webSocket.onopen =  (event) => {
            console.log('Connection established');
        };
    }

При створенні об’єкта з’єднання необхідно визначити кілька обробників.

onerror - при помилці

onmessage - надходження нового повідомлення

onopen, onclose - відкриття та закриття з’єднання.

Надсилання відповіді на сервер.

    app.sendMessage = function() {
        let data = {
            message: $('#messageBox').val(),
            playername: sessionStorage.getItem('username')
        }
        let url = 'http://quizapi.webmonstr.com/v1/quiz/save_message';
        $.post( url, data, ( response ) => {
            $('#messageBox').val('');
        });
    };

$(‘#messageBox’).val(‘’) - очищення input-а.

Реагуємо на надходження повідомлення по веб-сокету.

    ....

    webSocket.onmessage = (event) => {
        var payload = JSON.parse(event.data)
        if(payload.type === 'message'){
            this.getMessages();
        }
    }

    ...

Відображаємо список гравців.

    ...
    app.getUserList = function() {
        $('#playerListBlock').empty();
        let url = 'http://quizapi.webmonstr.com/v1/quiz/player/list';
        $.get( url, ( response ) => {
            response.forEach((el) => {
                let tpl = `<div class="media-height p-3">
                <div class="media align-items-center mb-4">
                   <div class="iq-profile-avatar status-online">
                      <img class="rounded-circle avatar-50" src="${el.sticker.get_url}" alt="">
                   </div>
                   <div class="media-body ml-3">
                      <h6 class="mb-0"><a href="#">${el.name}</a></h6>
                      <p class="mb-0">${el.account}</p>
                   </div>
                </div>
             </div>`;
                $('#playerListBlock').append(tpl);
            });
        });
    };

Повна версія ініціалізації кімнати.

    app.initRoom = function() {
        this.setCurrentUser();
        this.getUserList();
        this.getCurrentQuestion();
        this.getMessages();
        this.socketConnection();
        $('#sendButton').on('click',()=>{
            this.sendMessage();
        });
    }