Browse Source

HW<22>begin

Gennadysht 2 years ago
parent
commit
4f3c15880a
3 changed files with 206 additions and 23 deletions
  1. 57 11
      js/22/hw_22_01.html
  2. 64 12
      js/22/hw_22_02 .html
  3. 85 0
      js/22/hw_22_03 thunk.html

+ 57 - 11
js/22/hw_22_01.html

@@ -1,5 +1,5 @@
 <head>
-01 to ES6
+    01 to ES6
 </head>
 
 <body>
@@ -8,23 +8,69 @@
             #reducer;
             #state;
             #cbs = []
-
-            constructor() {
-
+            get state() {
+                return this.#state;
             }
-
-            getState() {
-
+            getState() { return this.#state; }                   //функция, возвращающая переменную из замыкания
+            subscribe(cb) {
+                this.#cbs.push(cb);            //запоминаем подписчиков в массиве
+                return  (cb) => {
+                    this.#cbs = this.#cbs.filter(c => c !== cb)
+                }
+            }     //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
+            dispatch(action) {
+                /*   
+                    if (typeof action === 'function') {         //если action - не объект, а функция
+                        return action(dispatch, getState)       //запускаем эту функцию и даем ей dispatch и getState для работы
+                    }
+                */
+                const newState = this.#reducer(this.#state, action)      //пробуем запустить редьюсер
+                if (newState !== this.#state) {                    //проверяем, смог ли редьюсер обработать action
+                    this.#state = newState                        //если смог, то обновляем state 
+                    for (let cb of this.#cbs) cb()                //и запускаем подписчиков
+                }
             }
-
-            subscribe() {
+            constructor(reducer) {
+                this.#reducer = reducer;
+                this.#state = this.#reducer(undefined, {})              //стартовая инициализация состояния, запуск редьюсера со state === undefined
 
             }
+        }
+        const seller = (state, { type, item, amount, cash, price }) => {
+            if (state === undefined) {
+                state = {
+                    beer: { amount: 20, price: 10 },
+                    vodka: { amount: 10, price: 30 },
+                    cigars: { amount: 100, price: 20 },
+                    cashbox: 0,
+                }
+            }
+            if (type === 'BUY' &&
+                item in state &&
+                typeof amount == "number" &&
+                typeof cash == "number" &&
+                state[item].amount >= amount &&
+                amount > 0 &&
+                cash > 0 &&
+                state[item].price <= cash / amount) { //если тип action - КУПИТЬ, то:
 
-            dispatch() {
-
+                return {
+                    ...state, //берем все что было из ассортимента
+                    [item]: { amount: state[item].amount - amount, price: state[item].price },  //и уменьшаем то, что покупается на количество
+                    cashbox: state.cashbox + amount * state[item].price,
+                }
             }
+            return state;
         }
 
+        let store = new Store(seller);
+
+        const unsubscribe = store.subscribe(() => console.log(store.getState()))
+
+        store.dispatch({ type: 'BUY', item: 'cigars', amount: 3, cash: 58 });
+        store.dispatch({ type: 'BUY', item: 'vodka', amount: 3, cash: 92 });
+        unsubscribe();
+        console.log(store.state);
+
     </script>
 </body>

+ 64 - 12
js/22/hw_22_02 .html

@@ -1,30 +1,82 @@
 <head>
-01 to ES6
+    02 to ES6 Password
 </head>
 
 <body>
     <script>
-        class Store {
-            #reducer;
-            #state;
-            #cbs = []
-
-            constructor() {
-
+        class AuthInput {
+            #input = document.createElement("input");
+            onChange;
+            get input() {
+                return this.#input;
+            }
+            /*set value(val) {
+                 this.#input.value = val;
+             }*/
+            get value() {
+                return this.#input.value;
             }
 
-            getState() {
-
+            constructor(parent) {
+                parent.append(this.#input);
+                this.#input.oninput = this.#input.onchange = function () {
+                    if (this.onChange)
+                        this.onChange(this.value);
+                }.bind(this);
             }
+        }
+        class Login extends AuthInput { }
 
-            subscribe() {
+        class Password extends AuthInput {
+            #check = document.createElement("input");
+            set open(val) {
+                this.input.type = val ? "text" : "password";
+            }
+            get open() {
+                return this.input.type == "text";
+            }
 
+            constructor(parent, open) {
+                super(parent);
+                parent.append(this.#check);
+                this.#check.onchange = function () {
+                    this.open = this.#check.checked;
+                    if (this.onOpenChange)
+                        this.onOpenChange(this.open);
+                }.bind(this);
+                this.#check.checked = open;
+                this.#check.value = "open";
+                this.#check.type = "checkbox";
+                this.open = open;
             }
+        }
 
-            dispatch() {
+        class LoginForm {
+            #form = document.createElement("form");
+            #login = new Login(this.#form);
+            #password = new Password(this.#form, open);
+            #button = document.createElement("button");
+            onLogin;
+            constructor(parent, open) {
+                parent.append(this.#form);
+                this.#button.innerText = "OK";
+                this.#button.classList.add('btn');
+                this.#button.classList.add('ref-button');
+                this.#form.append(this.#button);
 
+                let setButtonStateCallback = function setButtonState() {
+                    this.#button.disabled = !this.#login.value || !this.#password.value;
+                }.bind(this);
+                this.#login.onChange = setButtonStateCallback;
+                this.#password.onChange = setButtonStateCallback;
+                this.#button.disabled = true;
+                this.#button.onclick = function () {
+                    if (this.onLogin)
+                        this.onLogin(this.#login.value, this.#password.value);
+                }.bind(this);
             }
         }
 
+        const form = new LoginForm(document.body, true);
     </script>
 </body>

+ 85 - 0
js/22/hw_22_03 thunk.html

@@ -0,0 +1,85 @@
+<head>
+    store Thunk
+</head>
+
+<body>
+    <script>
+        class Store {
+            #reducer;
+            #state;
+            #cbs = []
+            get state() {
+                return this.#state;
+            }
+            getState() { return this.#state; }                   //функция, возвращающая переменную из замыкания
+            subscribe(cb) {
+                this.#cbs.push(cb);            //запоминаем подписчиков в массиве
+                return (cb) => {
+                    this.#cbs = this.#cbs.filter(c => c !== cb)
+                }
+            }     //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
+            dispatch(action) {
+                /*   
+                   
+                */
+                const newState = this.#reducer(this.#state, action)      //пробуем запустить редьюсер
+                if (newState !== this.#state) {                    //проверяем, смог ли редьюсер обработать action
+                    this.#state = newState                        //если смог, то обновляем state 
+                    for (let cb of this.#cbs) cb()                //и запускаем подписчиков
+                }
+            }
+            constructor(reducer) {
+                this.#reducer = reducer;
+                this.#state = this.#reducer(undefined, {})              //стартовая инициализация состояния, запуск редьюсера со state === undefined
+
+            }
+        }
+        class StoreThunk extends Store {
+            dispatch(action) {
+                if (typeof action === 'function') {         //если action - не объект, а функция
+                    return action(this.dispatch.bind(this), this.getState.bind(this))       //запускаем эту функцию и даем ей dispatch и getState для работы
+                }
+                super.dispatch(action);
+            }
+        }
+
+
+
+        const seller = (state, { type, item, amount, cash, price }) => {
+            if (state === undefined) {
+                state = {
+                    beer: { amount: 20, price: 10 },
+                    vodka: { amount: 10, price: 30 },
+                    cigars: { amount: 100, price: 20 },
+                    cashbox: 0,
+                }
+            }
+            if (type === 'BUY' &&
+                item in state &&
+                typeof amount == "number" &&
+                typeof cash == "number" &&
+                state[item].amount >= amount &&
+                amount > 0 &&
+                cash > 0 &&
+                state[item].price <= cash / amount) { //если тип action - КУПИТЬ, то:
+
+                return {
+                    ...state, //берем все что было из ассортимента
+                    [item]: { amount: state[item].amount - amount, price: state[item].price },  //и уменьшаем то, что покупается на количество
+                    cashbox: state.cashbox + amount * state[item].price,
+                }
+            }
+            return state;
+        }
+
+
+        let store = new StoreThunk(seller);
+
+        const unsubscribe = store.subscribe(() => console.log(store.getState()))
+        store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'cigars', amount: 3, cash: 58 }));
+        store.dispatch((dispatch, getStore) => dispatch({ type: 'BUY', item: 'vodka', amount: 3, cash: 92 }));
+        unsubscribe();
+        console.log(store.state);
+
+    </script>
+</body>