hw 15 - garevna/js-course GitHub Wiki

hw-40 Homework

point-30 Required

Напилить код класса ClimaticZones,

экземпляры которого имеют собственное свойство region,

и наследуют неперечислимое свойство climates следующего содержания:

{
    "Экваториальные области Африки": "Экваториальный",
    "Экваториальные области Южной Америки": "Экваториальный",
    "Экваториальные области Океании": "Экваториальный",
    "Южная и Юго-Восточная Азия": "Тропический муссонный",
    "Западная и Центральная Африка": "Тропический муссонный",
    "Северная Австралия": "Тропический муссонный",
    "Северная Африка": "Тропический сухой",
    "Центральная Австралия": "Тропический сухой",
    "Средиземноморье": "Средиземноморский",
    "Южный берег Крыма": "Средиземноморский",
    "Южная Африка": "Средиземноморский",
    "Юго-Западная Австралия": "Средиземноморский",
    "Западная Калифорния": "Средиземноморский",
    "Западные части Евразии": "Умеренный морской",
    "Западные части Северной Америки": "Умеренный морской",
    "Внутренние части материков": "Умеренный континентальный",
    "Восточная окраина Евразии": "Умеренный муссонный",
    "Северные окраины Евразии": "Субарктический",
    "Северные окраины Северной Америки": "Субарктический",
    "Акватория Северного Ледовитого океана": "Арктический"
}

Собственное свойство region может принимать одно из значений, перечисленных в унаследованном свойстве climates

Унаследованный метод getClimate() должен возвращать климат для региона, который указан в значении свойства region


ok-30 Additionally

Заверните в оболочку класса свой чатик на json-server


super-30 Additionally

Соберите приложение

Запустите json-server

Откройте index.html в нескольких вкладках

В одной вкладке задаете вопрос

В другой вкладке отвечаете

Вопросы приведены в конце

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>REST API samples</title>
    <meta name="description" content="JSON server: Simple chat"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="shortcut icon" href="chat/a-level-ico.png" type="image/x-icon">
    <link rel="stylesheet" href="chat/main.css">
  </head>

  <body>
    <script src = "chat/index.js"></script>
  </body>

</html>
chat/main.css
* {
  font-family: Roboto, monospace, Arial;
}
.inputMessage {
  position: fixed;
  bottom: 20px;
  left: 3%;
  right: 3%;
  height:70px;
  width: 95%;
  border: inset 1px;
  padding: 5px 10px;
  overflow: auto;
}
.chatContainer {
  position: fixed;
  top: 3%;
  bottom: 100px;
  left: 3%;
  right: 3%;
  border: inset 1px;
  padding: 10px 20px;
  overflow: auto;
}
sup {
  font-size: 9px;
  position: absolute;
  right: 20px;
  color: #888;
}
.ico {
  margin-right: 10px;
}

chat/index.js
class SimpleChat {
    constructor () {
        if ( this.constructor.instance ) {
            console.warn ( "It's a singleton. You can't create one more instance of this class" )
            return null
        }
	window.addEventListener( "unload", function ( event ) {
            SimpleChat.closeChat ()
        })
        this.constructor.instance = this
        this.users = null
        this.currentUser = null
        this.getAllData ()
        this.chatContainer = this.addElement ( "section" )
        this.chatContainer.id = "chatContainer"
        this.chatContainer.className = "chatContainer"
        this.chatContainer.addEventListener ( "updated", this.updateChat.bind ( this ) )

        this.inputMessage = this.addElement ( "input" )
        this.inputMessage.className = "inputMessage"
        this.inputMessage.onchange = function ( event ) {
            fetch ( "http://localhost:3000/messages", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify ({
                    user: this.currentUser.id,
                    date: new Date().toLocaleString(),
                    body: event.target.value
                })
            })
            fetch ( "http://localhost:3000/lastUpdate", {
                method: "PUT",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify ({
                    date: new Date().toLocaleString()
                })
            })
            event.target.value = ""
        }.bind ( this )

        this.interval = setInterval (
            function() {
                document.querySelector ( "section#chatContainer" )
                    .dispatchEvent ( new Event ( "updated" ))
            },
            500
        )
    }

    addElement ( tagName, container ) {
        return ( container && container.nodeType === 1 ?
            container : document.body )
                .appendChild (
		    document.createElement ( tagName )
		)
    }
    getData ( ref ) {
        return fetch ( `http://localhost:3000/${ref}` )
            .then ( response => response.json() )
    }
    createUserAvatar ( user ) {
        return fetch( `https://api.github.com/users/${user.id}` )
            .then ( response => response.json()
                .then ( response => {
                    let img = new Image ( 40 )
                    img.src = response.avatar_url
                    img.className = "ico"
                    return img
                })
            )
    }

    async updateChat () {
        let updated = await this.getData ( "lastUpdate" )
        if ( updated.date === this.lastUpdate.date || !this.users ) return
        this.lastUpdate.date = updated.date
        this.messages = await this.getData ( "messages" )
        this.initChat()
    }

    async getAllData () {
        this.lastUpdate = await this.getData ( "lastUpdate" )
        let users = await this.getData ( "users" )
        this.currentUser = users.filter ( user => !user.active )[0]
        if ( this.currentUser ) {
            this.currentUser.active = true
            fetch ( `http://localhost:3000/users/${this.currentUser.id}`, {
                method: "PUT",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify ( this.currentUser )
            })
        }
        async function mutateUser ( user, callback ) {
            return Object.assign ( {},
                { [ user.id ]: await callback ( user ) }
            )
        }
        let lim = users.length
        let k = 0
        while ( k++ < lim ) {
            users.push (
                await mutateUser ( users.shift(), this.createUserAvatar )
            )
        }
        this.users = Object.assign ( {}, ...users )

        this.messages = await this.getData ( "messages" )
        this.initChat ()
    }

    initChat () {
        this.chatContainer.innerHTML = ""
        this.messages.forEach (
            message => {
                let mess = this.addElement ( "div", this.chatContainer )
                mess.appendChild ( this.users [ message.user ] )
                this.addElement ( "span", mess ).innerText = message.user
                this.addElement ( "span", mess ).innerHTML = `<sup>${message.date}</sup>`
                this.addElement ( "p", mess ).innerText = message.body
            }, this
        )
        this.chatContainer.scrollTop = this.chatContainer.offsetHeight
    }
    static closeChat () {
        this.instance.currentUser.active = false
        fetch ( `http://localhost:3000/users/${this.instance.currentUser.id}`, {
            method: "PUT",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify ( this.instance.currentUser )
        })
    }
}

Object.defineProperty (
    SimpleChat.prototype,
    "messages",
    {
        enumerable: false,
        writable: true,
        value: []
    }
)

const chat = new SimpleChat

const oneMoreChat = new SimpleChat

chat.json
{
  "lastUpdate": {
    "date": "15.03.2019, 12:03:10"
  },
  "users": [
    {
      "id": "jvantuyl",
      "active": false
    },
    {
      "id": "BrianTheCoder",
      "active": false
    },
    {
      "id": "freeformz",
      "active": false
    },
    {
      "id": "hassox",
      "active": false
    },
    {
      "id": "automatthew",
      "active": false
    },
    {
      "id": "mojombo",
      "active": false
    },
    {
      "id": "defunkt",
      "active": false
    },
    {
      "id": "queso",
      "active": false
    },
    {
      "id": "lancecarlson",
      "active": false
    },
    {
      "id": "lukesutton",
      "active": false
    },
    {
      "id": "garevna",
      "active": false
    }
  ],
  "messages": [
    {
      "id": 1,
      "date": "05.02.2019, 10:18:32",
      "user": "mojombo",
      "body": "Hello everybody here! What do you prefer: static or dynamic import?"
    },
    {
      "id": 2,
      "date": "05.02.2019, 10:19:11",
      "user": "hassox",
      "body": "The static import syntax can only be used at the top-level of the file"
    },
    {
      "id": 3,
      "user": "BrianTheCoder",
      "date": "05.02.2019, 10:22:15",
      "body": "Dynamic import() introduces a new function-like form of import that caters to those use cases"
    },
    {
      "id": 4,
      "date": "05.02.2019, 11:10:18",
      "user": "defunkt",
      "body": "Since import() returns a promise, it's possible to use async/await instead of the then-based callback style"
    },
    {
      "id": 5,
      "date": "07.02.2019, 18:34:12",
      "user": "queso",
      "body": "Although import() looks like a function call, it is specified as syntax that just happens to use parentheses"
    },
    {
      "id": 6,
      "date": "07.02.2019, 18:38:05",
      "user": "lancecarlson",
      "body": "The lazy-loading capabilities enabled by dynamic import() can be quite powerful when applied correctly"
    },
    {
      "id": 7,
      "date": "13.03.2019, 10:21:20",
      "user": "lukesutton",
      "body": "Static import and dynamic import() are both useful"
    },
    {
      "id": 8,
      "date": "13.03.2019, 11:14:33",
      "user": "garevna",
      "body": "ws-json-server adds a little abstraction to websocket"
    }
  ]
}

Вопросы:
  1. Что делает функция mutateUser ?
  2. Что возвращает метод createUserAvatar ?
  3. Что происходит при вводе сообщения ?
  4. Можно ли создать в одной вкладке более одного экземпляра класса SimpleChat ?
  5. Откуда берутся аватарки пользователей чата ?
  6. Совпадает ли структура данных о юзерах чата на клиенте со структорой данных в базе на сервере ?
  7. Как определяется логин нового пользователя чата при подключении ?
  8. Что делает метод closeChat и когда он вызывается ?

.

⚠️ **GitHub.com Fallback** ⚠️