13 |
54 |
55 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Sun Sep 24 2017 11:47:21 GMT+0300 (+03)
3 |
4 | module.exports = (config) => {
5 | config.set({
6 | // base path that will be used to resolve all patterns (eg. files, exclude)
7 | basePath: '',
8 |
9 | // frameworks to use
10 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
11 | frameworks: ['mocha', 'chai'],
12 |
13 | // list of files / patterns to load in the browser
14 | files: ['js/*.js', '**/*.js '],
15 |
16 | // list of files to exclude
17 | exclude: [],
18 |
19 | // preprocess matching files before serving them to the browser
20 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
21 | preprocessors: {},
22 |
23 | // test results reporter to use
24 | // possible values: 'dots', 'progress'
25 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
26 | reporters: ['progress'],
27 |
28 | // web server port
29 | port: 9876,
30 |
31 | // enable / disable colors in the output (reporters and logs)
32 | colors: true,
33 |
34 | // level of logging
35 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
36 | logLevel: config.LOG_INFO,
37 |
38 | // enable / disable watching file and executing tests whenever any file changes
39 | autoWatch: true,
40 |
41 | // start these browsers
42 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
43 | browsers: ['ChromeHeadless'],
44 |
45 | // Continuous Integration mode
46 | // if true, Karma captures browsers, runs the tests and exits
47 | singleRun: false,
48 |
49 | // Concurrency level
50 | // how many browser should be started simultaneous
51 | concurrency: 2,
52 | });
53 | };
54 |
--------------------------------------------------------------------------------
/10/cls/notes/01 - 05 - state/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Basic React element via JSX
10 |
11 |
12 |
13 |
52 |
53 |
--------------------------------------------------------------------------------
/04/ht/NOTES.md:
--------------------------------------------------------------------------------
1 | Информацию о REST API Firebase можно найти здесь https://firebase.google.com/docs/database/rest/start
2 |
3 | Для базы нужно отключить проверку прав доступа (`Project -> Database -> Rules`)
4 |
5 | ```javascript
6 | {
7 | "rules": {
8 | ".read": true,
9 | ".write": true
10 | }
11 | }
12 | ```
13 |
14 | Добавление записи в Firebase
15 |
16 | ```javascript
17 | fetch(config.databaseURL + '/messages.json', {
18 | method: 'PUT',
19 | body: JSON.stringify([
20 | {
21 | user: from,
22 | message: text,
23 | date: date,
24 | title: counter++ + 'message',
25 | },
26 | ]),
27 | headers: {
28 | Accept: 'application/json',
29 | 'Content-Type': 'application/json',
30 | },
31 | })
32 | .then(function(response) {
33 | return response.json();
34 | })
35 | .then(console.log);
36 | ```
37 |
38 | Добавление записи в список Firebase
39 |
40 | ```javascript
41 | fetch(config.databaseURL + '/messages.json', {
42 | method: 'POST',
43 | body: JSON.stringify([
44 | {
45 | user: from,
46 | message: text,
47 | date: date,
48 | title: counter++ + 'message',
49 | },
50 | ]),
51 | headers: {
52 | Accept: 'application/json',
53 | 'Content-Type': 'application/json',
54 | },
55 | })
56 | .then(function(response) {
57 | return response.json();
58 | })
59 | .then(console.log);
60 | ```
61 |
62 | Чтение записи / списка
63 |
64 | ```javascript
65 | fetch(config.databaseURL + '/messages.json', {
66 | headers: {
67 | Accept: 'application/json',
68 | 'Content-Type': 'application/json',
69 | },
70 | })
71 | .then(function(response) {
72 | return response.json();
73 | })
74 | .then(console.log);
75 | ```
76 |
77 | Чтение всей структуры базы
78 |
79 | ```javascript
80 | fetch(config.databaseURL + '/.json', {
81 | headers: {
82 | Accept: 'application/json',
83 | 'Content-Type': 'application/json',
84 | },
85 | })
86 | .then(function(response) {
87 | return response.json();
88 | })
89 | .then(console.log);
90 | ```
91 |
--------------------------------------------------------------------------------
/08/ht/README.md:
--------------------------------------------------------------------------------
1 | # Проект "Жизнь"
2 |
3 | Описание правил игры можно найти на странице в википедии [Жизнь (игра)](https://ru.wikipedia.org/wiki/%D0%96%D0%B8%D0%B7%D0%BD%D1%8C_(%D0%B8%D0%B3%D1%80%D0%B0))
4 |
5 |
6 | Проект представляет из себя одностраничное приложение со страницами
7 | - текстовая игра (без разметки - тег `pre` и текстом отображние игры )
8 | - игра на Canvas
9 | - игра на SVG
10 | - About - с информацией о проекте
11 |
12 | 
13 |
14 | На страницах с игрой ( кроме страницы *About* ) в центре страницы находится поле, реализованное на соответствующей технологии. Внизу страницы находится блок с контролами состояния игры.
15 |
16 | ### Поле
17 |
18 | Отображает текущее поколение. И позволяет пользователю взаимодействовать с игрой. Клик по полю вызывает инверсию состояния клетки, по которой пользователь кликнул ( живая - умирает, мертвая - оживает ).
19 |
20 | ### Блок с контролами
21 |
22 | Позволяет
23 | - запускать и останавливать игру
24 | - изменять скорость игры с помощью регулятора
25 | - изменять размеры поля при помощи выпадающих списков с размерами поля по горизонтали и вертикали
26 | - при остановленной игре путешествовать назад и вперед по истории ( пока это возможно ). При этом состояние игры можно измененить на любой момент времени и запустить игру вновь
27 |
28 | ### Навигация
29 |
30 | Переход по страницам с разными реализациями поля не останавливает игру - она продолжается с заданными параметрами. Меняется только способ отображения игры.
31 |
32 | При уходе на страницу About - игра останавливается и ее состояние сохраняется. При возврате на страницу с полями подхватывается сохраненное состояние.
33 |
34 | Обновление страницы подхватывает технологию ( которая отображается на URL адресе ). Состояние игры сохранять в url или в хранилище по желанию.
35 |
36 | # Видео
37 |
38 | - [Паттерны проектирования JavaScript на 2017 год](https://www.youtube.com/watch?v=GjtfXIaQq7g)
39 |
--------------------------------------------------------------------------------
/01/ht/example/script.js:
--------------------------------------------------------------------------------
1 | /* eslint no-var: "off" */
2 | /* eslint no-unused-vars: "off" */
3 | /* eslint max-len: "off" */
4 |
5 | /**
6 | * Функция вывода строк для работы в fizzBuzz
7 | * @param {*} a
8 | */
9 | function log(a) {
10 | console.log(a);
11 | }
12 |
13 | /* Раместите ваш код ниже */
14 |
15 | /**
16 | * реализовать фукнцию `fizzBuzz`
17 | * которая выводит числа от 1 до 100.
18 | * Если число кратно 3 - вместо числа вывести `Fizz`.
19 | * Если кратно 5 - вывести вместо числа `Buzz`.
20 | * Если число кратно и 3 и 5 - вывести вместо числа `FizzBuzz`.
21 | * Для вывода использовать фукнцию `log` (аналогично заданию в классе).
22 | * В теле функции нельзя использовать `if`, `switch`, тернарный оператор `? :`
23 | */
24 | function fizzBuzz() {
25 | /* Ваше решение */
26 | }
27 |
28 |
29 | /**
30 | * реализовать фукнцию `isPolindrom`,
31 | * которая принимает на вход строку и возвращает результат проверки (`true`/ `false` ),
32 | * является строка полндромом (одинакого читается с лева на право и с права на лево ) или нет
33 | * @param {string} textString
34 | * @return {boolean} Является строка полндромом (одинакого читается с лева на право и с права на лево ) или нет
35 | */
36 | function isPolindrom(textString) {
37 | /* Ваше решение */
38 | return undefined;
39 | }
40 |
41 |
42 | /**
43 | * Реализовать фукнцию `drawCalendar` ,
44 | * которая принимает три аргумента - год, месяц, htmlElement
45 | * и выводит в этот элемент календарь на месяц (дни недели начинаются с понедельника ).
46 | * @param {number} year
47 | * @param {number} month - номер месяца, начиная с 1
48 | * @param {external:HTMLElement} htmlEl
49 | */
50 | function drawCalendar(year, month, htmlEl) {
51 | /* Ваше решение */
52 | }
53 |
54 |
55 | /**
56 | * Написать функцию `isDeepEqual`
57 | * которая принимает на вход двe переменных
58 | * и проверяет идентичны ли они по содержимому. Например
59 | * @param {*} objA
60 | * @param {*} objB
61 | * @return {boolean} идентичны ли параметры по содержимому
62 | */
63 | function isDeepEqual(objA, objB) {
64 | /* Ваше решение */
65 | return undefined;
66 | }
67 |
--------------------------------------------------------------------------------
/10/cls/notes/01 - 06 - control state and pass props/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Basic React element via JSX
10 |
11 |
12 |
13 |
64 |
65 |
--------------------------------------------------------------------------------
/.ht/diff/promisify.test.js:
--------------------------------------------------------------------------------
1 | /* global mocha, chai, describe, it */
2 | /* global promisify, Hr, beforeEach */
3 | mocha.setup({
4 | ui: 'bdd',
5 | bail: true,
6 | });
7 | const assert = chai.assert;
8 |
9 | describe('promisify', () => {
10 | it('is a function', () => assert.equal(typeof promisify, 'function'));
11 | it('returns function', () => {
12 | assert.equal(typeof promisify(() => null), 'function');
13 | });
14 | it('result calls original function', () => {
15 | var x = 0;
16 | var fn = (_) => x++;
17 | var pFn = promisify(fn);
18 | assert.equal(x, 0);
19 | pFn();
20 | assert.equal(x, 1);
21 | });
22 | it('passes params into original function', () => {
23 | var x = 0;
24 | var fn = (y) => (x += y);
25 | var pFn = promisify(fn);
26 | assert.equal(x, 0);
27 | pFn(2);
28 | assert.equal(x, 2);
29 | });
30 | it('passes callback to original function', () => {
31 | var list = [];
32 | promisify((cb) => list.push(cb))();
33 | promisify((x, cb) => list.push(cb))(1);
34 | promisify((x, y, cb) => list.push(cb))(1, 2);
35 | promisify((x, y, z, c, a, b, cb) => list.push(cb))(1, 2, 3, 4, 5, 6);
36 | assert.equal(list.length, 4);
37 | list.forEach((i) => assert.isFunction(i));
38 | });
39 | it('calls original function in correct context', () => {
40 | var o = { name: 'Bob' };
41 | var x = null;
42 | var fn = function() {
43 | x = this;
44 | };
45 | o.pfn = promisify(fn);
46 | o.pfn();
47 | assert.equal(x, o);
48 | });
49 | describe('promisified', () => {
50 | it('returns promise', () => {
51 | var fn = () => null;
52 | assert.isOk(promisify(fn)() instanceof Promise);
53 | });
54 | it('rejects promise on error and pass error', (done) => {
55 | promisify((cb) => cb('xxx'))().catch((err) => {
56 | assert.equal(err, 'xxx');
57 | done();
58 | });
59 | });
60 | it('resolves promise on success and pass data', (done) => {
61 | promisify((cb) => cb(null, 'data'))().then((data) => {
62 | assert.equal(data, 'data');
63 | done();
64 | });
65 | });
66 | });
67 | });
68 |
69 | mocha.run();
70 |
--------------------------------------------------------------------------------
/10/ht/README.md:
--------------------------------------------------------------------------------
1 | # Практика
2 |
3 | ## Todo App
4 |
5 | Создать приложение **_Todo List_**
6 |
7 | 
8 |
9 | Реализовать приложение в отдельном репозитории. Заготовку создать с помощью
10 | `create-react-app`.
11 |
12 | Приложение состоих из трех частей
13 |
14 | ### Форма добавления задач
15 |
16 | Позволяет добавить в список задачи. Поля задачи, доступные для заполнения (
17 | обязательным является только заголовок ):
18 |
19 | * Заголовок
20 | * Описание
21 | * Дата
22 | * Приоритет (выпадающий список с больше, чем одним значением )
23 |
24 | При добавлении задачи в список поля формы сбрасываются в начальное значение
25 | (все, кроме даты).
26 |
27 | ### Фильтр для списка задач
28 |
29 | Фильт регулирует то, какие задачи будут доступны в списке ниже. Фильтр позволяет
30 | регулировать следующие настройки
31 |
32 | * показывать ли выполненные задачи
33 | * поиск по тексту ( регистронезависимый, поиск как в заголовке, так и в описании
34 | )
35 | * фильтр по дате (минимальная и максимальная даты - заданы могут обе,
36 | одна-любая, ниодной)
37 |
38 | Изменения на списке отражаются сразу при изменении полей в фильтре - при вводе
39 | текста в фильтр, при изменении дат или состоянии чекбокса
40 |
41 | ### Список задач
42 |
43 | Отображает список задач в виде таблицы. Заголовок таблицы содержит элементы
44 | управления, позволяющие сортировать таблицу по колонке (в прямом и обратном
45 | порядке)
46 |
47 | ## Теория
48 |
49 | Пройти официальное руководство
50 |
51 | * https://reactjs.org/tutorial/tutorial.html
52 | * https://reactjs.org/docs/hello-world.html (Quck Start пройти, Advanced Guides
53 | просмотреть)
54 |
55 | Полезным может оказаться
56 |
57 | * https://www.gitbook.com/book/maxfarseer/react-course-ru/details
58 | * https://abraxabra.ru/react.js/bystryy-start
59 | * http://thewebland.net/react-js/
60 |
61 |
62 | ### *** Дополнительно
63 |
64 | * Оформить приложение с использованием [React Semantic UI](https://react.semantic-ui.com/)
65 | * Двойной клик по строке с задачей ( если она не завершена ) открывает модальное окно для редактирования (с формой как при добавлении - те редактировать можно все поля). Для завершенных задач форма открывается в режиме для чтения, без возможности редактировать поля.
66 |
--------------------------------------------------------------------------------
/03/ht/README.md:
--------------------------------------------------------------------------------
1 | ### Теория
2 |
3 | Прочитать (желательно с выполнением задач) разделы из учебника:
4 |
5 | * [Современные возможности ES-2015](http://learn.javascript.ru/es-modern)
6 | * [Основы работы с событиями](http://learn.javascript.ru/events-and-interfaces)
7 | * [Создание графических компонентов](http://learn.javascript.ru/widgets)
8 | * [Формы, элементы управления](http://learn.javascript.ru/js-misc)
9 | * [Современные возможности ES-2015](http://learn.javascript.ru/forms-controls)
10 | * [AJAX и COMET](http://learn.javascript.ru/ajax)
11 | * [Управление историей браузера](https://developer.mozilla.org/ru/docs/Web/API/History_API)
12 |
13 | ---
14 |
15 | * [Путеводитель по JavaScript Promise для новичков](https://habrahabr.ru/company/zerotech/blog/317256/)
16 | * [Промисы в ES6: паттерны и анти-паттерны](https://habrahabr.ru/company/ruvds/blog/339414/)
17 |
18 | ### Вопросы
19 |
20 | * Что такое "стрелочная" ("arrow function") функция? Чем она отличается от обычной?
21 | * Что такое Promise? Какой стандарт отписывает поведение Promise? Основные пункты стандарта?
22 | * Чем куки (cookie) отличаются от localStorage ?
23 | * Что такое CORS?
24 | * Что такое и какие есть коды ответов HTTP?
25 | * Что такое jsonp-запрос?
26 | * Как код, написанный на ES6 (ES2015-2017) превратить в код, который поддерживается IE10?
27 | * Как реализовать простейший модуль на js?
28 | * Что такое и зачем нужен паттерн модуль? Какие модули существуют в JS?
29 | * Как реализовать подписку на клик по кнопке, которая отработает только один раз? ( с примером кода )
30 | * Какие события не "всплывают" ?
31 | * Что такое делегирование?
32 | * Преимущества и особенности работы с делегированием?
33 | * Какие вспомогательные методы есть для работы с промисами?
34 | * в чем разница между следующими кусками кода?
35 |
36 | ```javascript
37 | // promise - это экземпляр Promise
38 | // onSuccess - фукнция обработки успешного результата
39 | // onError - функция обработки ошибки
40 | // a:
41 | promise.then(onSuccess, onError);
42 | // b:
43 | promise.then(onSuccess).catch(onError);
44 | ```
45 |
46 | * в чем разница между следующими кусками кода?
47 |
48 | ```javascript
49 | doSomething().then(function() {
50 | return doSomethingElse();
51 | });
52 |
53 | doSomething().then(function() {
54 | doSomethingElse();
55 | });
56 |
57 | doSomething().then(doSomethingElse());
58 |
59 | doSomething().then(doSomethingElse);
60 | ```
61 |
--------------------------------------------------------------------------------
/08/cls/demo/script.js:
--------------------------------------------------------------------------------
1 | mocha.setup('bdd');
2 | const assert = chai.assert;
3 |
4 | // CODE
5 | const dummyDebounc = (func, delay) => {
6 | let timer;
7 | return () => {
8 | clearTimeout(timer);
9 | timer = setTimeout(func, delay);
10 | };
11 | };
12 |
13 | // TESTS below
14 | describe('Simple tests', () => {
15 | it('0 is equal to 0', () => assert.equal(0, 0, 'should be equal')); // http://chaijs.com/api/assert/#method_equal
16 | it('Math.random is function', () => assert.isFunction(Math.random)); // http://chaijs.com/api/assert/#method_isfunction
17 | });
18 |
19 | // https://mochajs.org/#asynchronous-code
20 | describe('dummyDebounce', () => {
21 | it('dummyDebounc is function', () => assert.isFunction(dummyDebounc));
22 | it('dummyDebounc returns function', () => assert.isFunction(dummyDebounc(() => null, 0)));
23 | it('call function with delay', (done) => {
24 | let counter = 0;
25 | const debouncedFunc = dummyDebounc(() => counter++, 0);
26 | debouncedFunc();
27 | assert.equal(counter, 0, 'should not incremenet counter');
28 | setTimeout(() => {
29 | assert.equal(counter, 1, 'should incremenet counter');
30 | done();
31 | }, 100);
32 | });
33 | it('call function twice cancel previous call', (done) => {
34 | // http://sinonjs.org/releases/v2.3.6/spies/
35 | const spy = sinon.spy();
36 | const debouncedFunc = dummyDebounc(spy, 0);
37 | debouncedFunc();
38 | // http://chaijs.com/api/assert/#method_isnotok
39 | assert.notOk(spy.called, 'should not be called');
40 | debouncedFunc();
41 | // http://chaijs.com/api/assert/#method_isok
42 | assert.isOk(spy.notCalled, 'should not be called');
43 | setTimeout(() => {
44 | // assert.isOk(spy.called, 'should be called');
45 | assert.equal(spy.callCount, 1, 'should be called once');
46 | done();
47 | }, 100);
48 | });
49 | });
50 |
51 | describe('Simple mock usage', () => {
52 | let eventBus;
53 | let element;
54 | let clicker;
55 |
56 | // https://mochajs.org/#hooks
57 | beforeEach(() => {
58 | eventBus = new EventBus();
59 | element = document.createElement('div');
60 | });
61 |
62 | it('should trigger event on click', () => {
63 | // http://sinonjs.org/releases/v2.0.0/spies/
64 | const spy = sinon.spy(eventBus, 'trigger');
65 |
66 | clicker = new Clicker(element, 0, eventBus);
67 | element.querySelector('button').click();
68 | assert.isOk(spy.called);
69 | });
70 | });
71 |
72 | mocha.run();
73 |
--------------------------------------------------------------------------------
/final/README.md:
--------------------------------------------------------------------------------
1 | ## Требования к финальному проекту (критерии оценки)
2 |
3 | * [ ] Полезно / красиво
4 | * [ ] SPA (роутинг, переходы без перезагрузки страницы)
5 | * [ ] Работа с удаленным API
6 | * [ ] ООП (разбитие на классы)
7 | * [ ] ES6 (синтаксис, сборка)
8 | * [ ] Хранение данных пользователя
9 | * [ ] настроенная система сборки, минимизация
10 | * [ ] Приложение задеплоено и есть скрипт деплоя
11 | * [ ] Используются сторонние модули/библиотеки
12 | * [ ] Есть обработка данных от пользователя ( обработка форм )
13 |
14 | ### Подготовка к защите
15 |
16 | * [ ] Код работает
17 | * [ ] Код почищен от ненужных коментариев, блоков кода и отформатирован в едином стиле
18 | * [ ] Все обновления залиты в гит.
19 | * [ ] К проекту добавлен README.md c описанием проекта ( назначение / структура / технологии и тп) и картинками ( структура/ скрины интерфейса и тп)
20 | * [ ] Собранный проект задеплоен на хостинг и проверен. В `README.md` добавлена ссылка на живое превью проекта на хостинге
21 | * [ ] Подготовлена презентация ( желательно на https://slides.com/ ) и ссылка на нее добавлена в файл `README.md` ( через короткую ссылку, например goo.gl )
22 | * [ ] На бумаге написан текст выступления-презентации в соответствии с планом презентации
23 |
24 | ### Презентация должна включать
25 |
26 | * [ ] Ваши имя / фамилию
27 | * [ ] Название проекта
28 | * [ ] Назначение проекта / для кого / зачем / почему выбрали эту тему
29 | * [ ] Описание проекта с скринами основных экранов и описанием их функционала
30 | * [ ] Демонстрацию работы проекта ( лучше снять видео или подготовить точный порядок - куда когда щелкать и что вводить - идеально оба пункта )
31 | * [ ] Обзор структуры проекта ( какие файлы / функциональные части где находятся )
32 | * [ ] Описание задач, решенных в ходе работы над проектом ( какие были проблемы, как решали, что применили ). Дополнительно осветить пункты из требований к финальному проекту
33 | * [ ] Описание сложностей и проблем, которые встретились в процессе работы
34 | * [ ] Какая часть проекта оказалась самой сложной ( и почему? )
35 | * [ ] Описание результата и процесса сборки - как выглядит собранный проект (число и размер файлов), как собрать и задеплоить проект (команды и что происходит при их выполнение)
36 | * [ ] Ваше мнение и выводы из проделанной работы
37 |
38 | #### Итого:
39 |
40 | В репозитории проекта создать Issue с короткими ссылками на проект на хостинге + на презентацию. Это нужно чтобы вы не искали флешки и прочее - с любого компьютера можно было открыть все, что нужно для знакомства с проектом и его кодом
41 |
--------------------------------------------------------------------------------
/09/ht/README.md:
--------------------------------------------------------------------------------
1 | # Создание аркадной игры
2 |
3 | Создать аркадную игру, с отрисовкой на canvas со следующим функционалом ( набор
4 | идет с возрастанием по сложности, последующие шаги полезно держать в голове, но
5 | делать после реализации предыдущих ). Вся игра сделана на базе роутера из
6 | прошлого задания. Минимум три роута - описание правил, сама игра, таблица
7 | рекородов. Примерный план:
8 |
9 | * Создать одностраничное приложение - на главной описание игры и правил, на
10 | отдельной странице сама игра, на отдельной история побед и таблица рекордов.
11 | * Игра ведется на прямоугольном поле
12 | * Управление персонажем производится при помощи клавиатуры (стрелки)
13 | * Для мобильных устройств поверх игры рисуются полупрозрачные контроля для
14 | стрелок
15 | * При старте персонаж неподвижен, но после первой же команды начинает постоянно
16 | двигаться. Нажатие управляющих кнопок меняет направление движения. При выходе
17 | за границы поля персонаж появляется с противоположной стороны.
18 | * Со старта игры начинается отсчет времени, каждые n-секунд / n - ходов
19 | происходит переход на новый уровень. При завершении игры - запрашивается имя
20 | пользователя и сохраняется время игры для таблицы рекордов.
21 | * Новый уровень - появление на поле новый врагов того или иного типа. Враги
22 | разного типа выглядят по-разному
23 | * Враги первого типа - постоянно двигаются не меняя направления. Скорость
24 | постоянная, но у разных врагов может быть разной.
25 | * Враги второго типа - ведут себя так же, но при появлении персонажа в радиусе m
26 | меняют свое направление и начинают его преследовать.
27 | * При столкновении персонажа с врагом - игра заканчивается.
28 | * Реализовать отображение персонажа и врагов на основе спрайтов с анимацией.
29 | * Реализовать режим записи / сохранения / воспроизведения игры (использовать
30 | отдельный роут)
31 | * Добавить в игру ( с некого уровня ) появление предметов-модификаторов, которые
32 | позволяют уничтожать врагов, в течении некоторого времени.
33 |
34 | ## Прочитать:
35 |
36 | * https://learn.javascript.ru/drag-and-drop
37 | * https://learn.javascript.ru/drag-and-drop-objects
38 |
39 | * https://habrahabr.ru/company/mailru/blog/207048/
40 | * https://habrahabr.ru/post/187582/
41 |
42 | * https://codelabs.developers.google.com/codelabs/firebase-web-ru/index.html?index=..%2F..%2Flang-ru#0
43 | * http://progcoder.blogspot.com.by/2016/03/firebase-firebase.html
44 | * Пройти курс (после создания игры) http://www.w3ii.com/ru/firebase/default.html
45 |
46 | ## Может пригодиться
47 |
48 | * http://gaurav.munjal.us/Universal-LPC-Spritesheet-Character-Generator/
49 |
--------------------------------------------------------------------------------
/06/ht/notes.md:
--------------------------------------------------------------------------------
1 | ****# Загрузка данных с удаленного сервера
2 |
3 | Актуальные варианты работы c `ajax`:
4 |
5 | - [XHR](https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest)
6 | - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
7 |
8 | Для загрузки прогноза погоды можно использовать, например одно из двух:
9 | - [DarkSky](https://darksky.net/) + [MapsGoogle](https://developers.google.com/maps/documentation/geocoding/intro)
10 | - [OpenWeather](http://openweathermap.org/api#)
11 |
12 | Данные для работы с сервисами (а еще лучше создать свой аккант и использовать свои ключи):
13 | ```javascript
14 | // Google API Key : AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY
15 | // DarkSky API Key: d113af5f82393ef553f48314ae9f42e8
16 | ```
17 |
18 | Пример получения координат по адресу с помощью GoogleMapsAPI:
19 | ```javascript
20 | // https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY
21 | let GOOGLE_API_KEY = `AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY
22 | let getLatLng = (addr) => fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${addr}&key=${GOOGLE_API_KEY}`)
23 | .then((req) => req.json())
24 | .then((data) => data.results[0].geometry.location);
25 | /* { lat: 53.890838, lng: 27.5372046 } */
26 | ```
27 |
28 | Пример получения прогноза по координатам:
29 | ```javascript
30 | // https://api.darksky.net/forecast/[key]/[latitude],[longitude]
31 | // https://api.darksky.net/forecast/SOME_KEY/53.890838,27.5372046
32 | // Для получения данных на русском + в метрической системе измерения нужно модицифровать запрос
33 | // https://api.darksky.net/forecast/SOME_KEY/53.890838,27.5372046?lang=ru&units=si
34 | // Для обхода CORS и запросов из браузера поднят прокси (именно поэтому в примере ниже адрес отличается от примеров для DarkSky )
35 | // https://shrouded-spire-35703.herokuapp.com/forecast/53.890838,27.5372046
36 | let getForecastByLatLng = (lat, lng) => fetch(`https://shrouded-spire-35703.herokuapp.com/forecast/${lat},${lng}?lang=ru&units=si`)
37 | .then((req) => req.json());
38 | ```
39 |
40 | Пример объединения двух функция для получения прогноза по адресу:
41 | ```javascript
42 | let getForecastByAddress = (str) => getLatLng(str)
43 | .then(({lat, lng}) => getForecastByLatLng(lat, lng))
44 | .catch((e) => {
45 | // здесь можно обработать ошибки, например
46 | });
47 | ```
48 |
49 | Пример использования CORS proxy:
50 | ```
51 | http://cors-proxy.htmldriven.com/?url=https://api.darksky.net/forecast/d113af5f82393ef553f48314ae9f42e8/53.890838,27.5372046?lang=ru&units=si
52 | ```
--------------------------------------------------------------------------------
/05/ht/README.md:
--------------------------------------------------------------------------------
1 | ## Теория
2 |
3 | ### Прочитать
4 | Прочитать книгу ["Паттерны для масштабируемых JavaScript-приложений" Автор: Эдди Османи.](http://largescalejs.ru/)
5 |
6 | ### Быть способным рассказать о:
7 |
8 | - Как работать с XHR
9 | - Что такое AJAX
10 | - Как работать с fetch
11 | - CDN
12 | - GitHub Pages
13 | - TDD
14 |
15 | ## Практика
16 |
17 | Через [TDD](https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) реализовать следующее:
18 |
19 | #### 1 Шаблонизатор
20 | Должен иметь следующую сигнатуру:
21 | ```
22 | // compileTemplate = (tpl) => (el, data)
23 | // Компиляция шаблона возвращает функцию
24 | // при передаче этой функции элемента и объекта с данными
25 | // элемент получает разметку в соответсвии с tpl из data
26 | var tpl = "{{name}} is {{age}} years old";
27 | var el = document.createElement('div');
28 | var template = compileTemplate(tpl);
29 | template(el, { name: 'Bob', age: 33 });
30 | el.innerHTML; // 'Bob is 33 years old
31 | ```
32 |
33 | #### 2 EventBus c реализацией интерфейса
34 | ```
35 | on(eventName, cb)
36 | off(eventName[, cb])
37 | trigger(eventName[, data1 [, data2 [...data]]])
38 |
39 | once(eventName, cb)
40 | ```
41 | #### 3 Router
42 |
43 | Поддерживающий описание роутов в формате
44 |
45 | ```
46 | IRoute {
47 | [name]: String optional
48 | [match]: String | RegExp | function
49 | onEnter([data]) | optional async function
50 | onLeave([data]) | optional async function
51 | onBeforeEnter([data]) | optional async function
52 | }
53 | ```
54 |
55 | При этом он должен работать [как обсуждалось](https://raw.githack.com/vvscode/js--base-course/master/05/cls/index.html#/10/1) с роутами структуры
56 |
57 | ```
58 | routes: [
59 | {
60 | name: 'index',
61 | match: '',
62 | onBeforeEnter: () => console.log('onBeforeEnter index'),
63 | onEnter: () => console.log('onEnter index'),
64 | onLeave: () => console.log('onLeave index')
65 | },
66 | {
67 | name: 'city',
68 | match: /city=(.+)/,
69 | onBeforeEnter: (city) => console.log(`onBeforeEnter city:${city}`),
70 | onEnter: (city) => console.log(`onEnter city:${city}`),
71 | onLeave: (city) => console.log(`onLeave city:${city}`)
72 | },
73 | {
74 | name: 'about',
75 | match: (text) => text === 'about',
76 | onBeforeEnter: () => console.log(`onBeforeEnter about`),
77 | onEnter: () => console.log(`onEnter about`),
78 | onLeave: () => console.log(`onLeave about`)
79 | }
80 | ]
81 | ```
82 |
--------------------------------------------------------------------------------
/10/cls/notes/01 - 07 - hooks/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Basic React element via JSX
10 |
11 |
12 |
13 |
14 |
97 |
98 |
--------------------------------------------------------------------------------
/08/cls/myFilter/tests.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | mocha.setup('bdd');
3 | const assert = chai.assert;
4 | describe('.myFilter', function() {
5 | it('is function', function() {
6 | return assert.isFunction([].myFilter);
7 | });
8 |
9 | it('needs cb as first param', function() {
10 | let ok = true;
11 | try {
12 | [].myFilter();
13 | } catch (e) {
14 | ok = false;
15 | }
16 | assert.equal(ok, false);
17 | });
18 |
19 | it('return list', function() {
20 | return assert.ok(
21 | [].myFilter(function() {
22 | return true;
23 | }) instanceof Array
24 | );
25 | });
26 |
27 | it('returns empty list for falsy cb', function() {
28 | return assert.ok(
29 | [1, 2, 3].myFilter(function() {
30 | return false;
31 | }).length === 0
32 | );
33 | });
34 | it('returns copy list for truthly cb', function() {
35 | return assert.deepEqual(
36 | [1, 2, 3].myFilter(function() {
37 | return true;
38 | }),
39 | [1, 2, 3]
40 | );
41 | });
42 | it('returns copy list for truthly cb', function() {
43 | return assert.deepEqual(
44 | [1, 2, 3].myFilter(function() {
45 | return 'some truthly param';
46 | }),
47 | [1, 2, 3]
48 | );
49 | });
50 | it('returns filtered list', function() {
51 | return assert.deepEqual(
52 | [1, 2, 3].myFilter(function(i) {
53 | return i % 2;
54 | }),
55 | [1, 3]
56 | );
57 | });
58 |
59 | it('calls passed cb', function() {
60 | const list = [1, 2, 3];
61 | const spy = sinon.spy();
62 | list.myFilter(spy);
63 | assert.equal(spy.callCount, list.length);
64 | });
65 |
66 | it('calls passed cb only for existing values', function() {
67 | const list = [1, , , 3];
68 | const spy = sinon.spy();
69 | list.myFilter(spy);
70 | assert.equal(spy.callCount, 2);
71 | });
72 |
73 | it('calls cb with params', function() {
74 | const list = [1, 2, 3];
75 | const spy = sinon.spy();
76 | list.myFilter(spy);
77 |
78 | assert.equal(spy.args.length, list.length);
79 | list.forEach(function(item, index) {
80 | return assert.deepEqual(spy.args[index], [item, index, list]);
81 | });
82 | });
83 |
84 | it('use passed thisArgs', function() {
85 | let that = undefined;
86 |
87 | const context = {name: 'fake object '};
88 | [1].myFilter(function() {
89 | that = this;
90 | }, context);
91 | assert.equal(that, context);
92 | });
93 |
94 | it('use `undefined` as thisArgs by default', function() {
95 | let that = 1;
96 | [1].myFilter(function() {
97 | that = this;
98 | });
99 | assert.isUndefined(that);
100 | });
101 |
102 | it('call cb only on initial state of list', function() {
103 | const list = [1, 2, 3];
104 | const initialLength = list.length;
105 | let counter = 0;
106 |
107 | list.myFilter(function() {
108 | if (list.length < 4) {
109 | list.push(1);
110 | }
111 | counter++;
112 | });
113 | assert.equal(counter, initialLength);
114 | });
115 | });
116 |
117 | mocha.run();
118 |
--------------------------------------------------------------------------------
/11/ht/README.md:
--------------------------------------------------------------------------------
1 | # Доработка TodoApp c использование Redux
2 |
3 | Доработать приложение добавив в него
4 |
5 | * redux (c поддержкой асинхронных операций)
6 | * firebase (в качестве базы данных и провайдера авторизации)
7 | * роутинг
8 | * библиотеку UI компонентов (bootstrap/ semantic UI)
9 |
10 | ## Базовые блоки
11 |
12 | Структурно приложение должно состоять из компонентов (см рисунок)
13 | 
14 |
15 | ### Форма фильтра (Filter Form)
16 |
17 | Позволяет задать параметры фильтрации отображаемых записей. Позволяет фильтровать по
18 |
19 | * дате (конкретные даты, или только текущий день с помощью отдельного чекбокса)
20 | * по флагу выполнения
21 | * по тексту (поиск делается в поле заголовка и в поле описания)
22 |
23 | ### Форма добавления/редактирования (Add/Edit form)
24 |
25 | Позволяет задавать значения полей при создании/редактировании записей
26 |
27 | ### Список задач (List of tasks)
28 |
29 | Позволяет отображать список задач, подходящих под фильтр. Сортировать по возрастанию/убывания через кнопки в заголовке таблицы.
30 |
31 | ### Режим календаря (Calendar View)
32 |
33 | Отображает задачи на календаре, позволяет фильтровать задачи по флагу выполнения (показывать или скрывать выполненные задачи)
34 |
35 | ** С помощью DranNDrop позволяет изменять даты для задач
36 |
37 | ## Работа с задачами
38 |
39 | Страницы для работы с задачами имеют в шапке форму добавления задач.
40 |
41 | На всех списках выполненные и невыполненные задачи отличаются либо иконкой, либо цветом блока.
42 |
43 | Невыполненные задачи можно редактировать (двойное нажатие по элементу открывает модальное окно редактирования) и удалять (с запросом подтверждения от пользователя). Выполненные задачи измененять нельзя (либо сначала нужно снять флаг выполнения).
44 |
45 | ## Страницы
46 |
47 | Приложение имеет основное меню в шапке страницы, ведущее на три основных страницы
48 |
49 | * Календарный вид
50 | * Список задач
51 | * О проекте
52 |
53 | Изменения фильтров на страницах с задачами должно отображаться на URL адрес, чтобы при обновлении или передаче ссылки состояние фильтров было восстановлено.
54 |
55 | ## Firebase
56 |
57 | Для авторизации и хранения данных использовать сервис Firebase. Работа со страницами кроме `About` доступна только после авторизации. Данные разных пользователей должны храниться раздельно (данные пользователя А недоступны пользователю B).
58 |
59 | ## Ссылки:
60 |
61 | Redux:
62 |
63 | * https://www.gitbook.com/book/rajdee/redux-in-russian
64 | * https://github.com/vvscode/js--redux-info
65 | * https://www.gitbook.com/@maxfarseer/
66 |
67 | Firebase:
68 |
69 | * https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html
70 | * https://firebase.google.com/docs/web/setup
71 | * https://www.youtube.com/watch?v=GnORwtq1_1A
72 | * https://codelabs.developers.google.com/codelabs/firebase-web-ru/index.html?index=..%2F..%2Flang-ru#0
73 | * https://firebase-info.com/category/firebase/
74 | * Репозиторий с примерами https://github.com/firebase/quickstart-js
75 |
76 | ## Процесс разработки
77 |
78 | Процесс разработки разбит на три этапа
79 |
80 | * изучение Firebase и разработка API для работы с его хранилищем
81 | * разработка приложения с хранением данных в localStorage
82 | * объединение firebase и разработанного приложения
83 |
84 | Каждый студент выполняет все три части. Часть 3 он выполняет используя код двух других студентов (часть 1 + часть 2)
85 |
--------------------------------------------------------------------------------
/.ht/05/eventBus.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | // partialy
3 | /* global EventBus, describe, it, assert, beforeEach */
4 |
5 | describe('EventBus', function() {
6 | it('is a function', function() {
7 | assert.isOk(typeof EventBus === 'function');
8 | });
9 | it('is a constructor', function() {
10 | assert.isOk(new EventBus() instanceof EventBus);
11 | });
12 | describe('methods', () => {
13 | var eb;
14 | beforeEach(() => (eb = new EventBus()));
15 |
16 | describe('.on', function() {
17 | it('a method', () => assert.equal(typeof eb.on, 'function'));
18 | });
19 | describe('.off', function() {
20 | it('a method', () => assert.equal(typeof eb.off, 'function'));
21 | });
22 | describe('.trigger', function() {
23 | it('a method', () => assert.equal(typeof eb.trigger, 'function'));
24 | });
25 | describe('.once', function() {
26 | it('a method', () => assert.equal(typeof eb.once, 'function'));
27 | });
28 |
29 | describe('logic', () => {
30 | it('calls .on handler by .trigger', () => {
31 | var a = 0;
32 | eb.on('some:event', () => (a = 1));
33 | assert.equal(a, 0);
34 | eb.trigger('some:event');
35 | assert.equal(a, 1);
36 | });
37 | it('works fine for no-handled events', () => {
38 | eb.trigger('some:event');
39 | });
40 | it('hanldes multiple events', () => {
41 | var x = 0;
42 | var y = 0;
43 | eb.on('x', () => (x = 1));
44 | eb.on('y', () => (y = 2));
45 | eb.trigger('x');
46 | eb.trigger('y');
47 | assert.equal(x, 1);
48 | assert.equal(y, 2);
49 | });
50 | it('manages multiple hanlder per one event', () => {
51 | var x = 0;
52 | var y = 0;
53 | eb.on('x', () => (x = 1));
54 | eb.on('x', () => (y = 2));
55 | eb.trigger('x');
56 | assert.equal(x, 1);
57 | assert.equal(y, 2);
58 | });
59 | it('passes params from .trigger into hanlders', () => {
60 | var x = [0];
61 | eb.on('x', (a) => x.push(a));
62 | eb.trigger('x', 2);
63 | assert.deepEqual(x, [0, 2]);
64 | });
65 | it('unsubscribes by .off call', () => {
66 | var x = 0;
67 | var _ = () => (x = 1);
68 | eb.on('x', _);
69 | eb.off('x', _);
70 | eb.trigger('x');
71 | assert.equal(x, 0);
72 | });
73 | it('unsubscribe multiple subscriptions', () => {
74 | var x = 0;
75 | var _ = () => (x = 1);
76 | eb.on('x', _);
77 | eb.on('x', _);
78 | eb.off('x', _);
79 | eb.trigger('x');
80 | assert.equal(x, 0);
81 | });
82 | it('once handles call only once', () => {
83 | var x = 0;
84 | var _ = () => x++;
85 | eb.once('x', _);
86 | eb.trigger('x');
87 | assert.equal(x, 1);
88 | eb.trigger('x');
89 | assert.equal(x, 1);
90 | });
91 | it('passes params into .once hanlder', () => {
92 | var x = [0];
93 | var _ = (y) => x.push(y);
94 | eb.once('x', _);
95 | eb.trigger('x', 4);
96 | assert.deepEqual(x, [0, 4]);
97 | });
98 | it('.off handles correctly', () => {
99 | var x = 0;
100 | var y = 0;
101 | var _ = () => x++;
102 | eb.on('x', _);
103 | eb.on('x', () => y++);
104 | eb.off('x', _);
105 | eb.trigger('x');
106 | assert.equal(y, 1);
107 | });
108 | });
109 | });
110 | });
111 |
--------------------------------------------------------------------------------
/06/ht/README.md:
--------------------------------------------------------------------------------
1 | # Сайт "Прогноз погоды"
2 |
3 | ## Общая задача
4 |
5 | Сайт состоит из трех блоков.
6 |
7 | 1. в шапке сайта находится форма с полем ввода и кнопкой "Искать" и переключатель механизма запроса (два радиобаттона `fetch`/`XHR`) и меню, ведущее на другие страницы
8 | 2. центральная часть содержит информационное описание для главной страницы. И прогноз погоды для страницы конкретного города. В случае ошибки при запросе она отображает сообщение об ошибке
9 | 3. в подвале сайта отображаются 5 последних городов, погоду в которых искал пользователь. При ошибке запрос не добавляется в списко
10 |
11 | 
12 |
13 | ## Детали
14 |
15 | * В любой момент времени взаимодействия с картой - ее состояние должно отображаться на URL-адрес, чтобы при обновлении страницы / отпавке ссылки другому человеку - страница открывалась на той же точке
16 | * При вводе текста в поле ввода и нажатие кнопки "Ввод" ( или по клику на кнопке "Искать" ) пользователь попадает на страницу с прогнозом погоды в заданном городе. При этом страницу можно добавить в закладки или отправить сообщением - при открытии ссылки должен показаться тот же город.
17 | * При изменении центра карты ( перетаскивание / зум ) должны отображаться данные по погоде для центра карты
18 | * При поиске города он появляется верхним пунктов в списке последних запросов ( нижний блок ), остальные пункты опускаются на 1 вниз. Пункты с номером больше 5 исчезают.
19 | * В любой точке на карте можно нажать 'Add to Favorites' - это добавить точку с описанием в список "Избранное". Из списка сущность можно удалить с помощью `x` возле записи. При клике на запись в списке "Избранное" происходит переход на сохраненные координаты
20 | * Функция загрузки прогноза должна быть реализована в двух вариантах - с использованием fetch и с использованием XHR. Блок с options для выбора (два пункта из которых всегда выбран только один) какую из реализаций использовать для получения следующего прогноза. Этот же переключатель влияет на реализацию всех запросов на сторонние ресурсы (определение координат пользователя, конвертация города в координаты и тп )
21 | * Для загрузки прогноза погоды использовать сайт https://darksky.net/
22 | * Для получения координат по введенным данным использовать API Google Maps
23 | * В шапку страницы добавить меню с двумя пунктами `Главная` / `О сайте`
24 | Каждый пункт меню должен открывать соответствующую страницу.
25 | "O сайте" - Отображает статическую информацию - ваше имя, фото, ссылки на соцсети и свободный текст
26 | "Главная" - при входе на страницу сайт определяет местоположение пользователя ( запросом на `https://api.userinfo.io/userinfos` или на аналогичный ресурс) и перенаправляет на страницу с соответсвующими координатами
27 | * Должны поддерживаться ссылки с указанием города ( например `/city/Minsk` )
28 |
29 | ## Настроить систему сборки, для работы с модулями / ES6 (используя gulp!!)
30 |
31 | Полезными могут оказаться следующие статьи:
32 |
33 | 1. [Setting up ES6+Babel+Gulp](http://ramkulkarni.com/blog/setting-up-es6-babel-gulp/)
34 | 2. [Getting import/export working ES6 style using Browserify + Babelify + Gulp = -5hrs of life](https://medium.com/@hey.aaron/getting-import-export-working-es6-style-using-browserify-babelify-gulp-5hrs-of-life-eca7786e44cc)
35 | 3. [Using ES6 with gulp](https://markgoodyear.com/2015/06/using-es6-with-gulp/)
36 |
37 | Уделите этому пункту внимание и время! Настроенная система сборки экономит вам время и создает удобное окружение для хорошего кода.
38 |
39 | ## Прочитать
40 |
41 | 1. [Мультивставка: insertAdjacentHTML и DocumentFragment](https://learn.javascript.ru/multi-insert)
42 | 1. [Интерфейсы. Прочь от MVC](http://javascript.ru/optimize/antimvc)
43 |
44 | ## Посмотреть
45 |
46 | 1. [Компонентный подход от Вовы](https://www.youtube.com/watch?v=sH04-Ypak_s)
47 |
--------------------------------------------------------------------------------
/.ht/diff/parallel.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('chai').assert;
2 | const sinon = require('sinon');
3 |
4 | const Parallel = require('./parallel');
5 |
6 | describe('Parallel', () => {
7 | it('is a function', () => assert.isFunction(Parallel));
8 | it('is a constructor', () => assert.instanceOf(new Parallel(), Parallel));
9 | it('has public interface', () => {
10 | let p = new Parallel();
11 | assert.isFunction(p.job);
12 | assert.isFunction(p.done);
13 | });
14 | it('.job is chainable', () => {
15 | const p = new Parallel();
16 | assert.equal(p, p.job());
17 | });
18 | it('calls done if no jobs asynchroniosly', (done) => {
19 | const cb = sinon.spy();
20 | const p = new Parallel();
21 | p.done(cb);
22 | assert.isNotOk(cb.called);
23 | setTimeout(() => {
24 | assert.isOk(cb.called);
25 | done();
26 | });
27 | });
28 | it("doesn't call jobs with no .done call", (done) => {
29 | const p = new Parallel();
30 | const cb = sinon.spy();
31 | p.job(cb);
32 | assert.isNotOk(cb.called);
33 | setTimeout(() => {
34 | assert.isNotOk(cb.called);
35 | done();
36 | }, 100);
37 | });
38 | it('calls jobs with .done call', (done) => {
39 | const p = new Parallel();
40 | const cb = sinon.spy();
41 | p.job(cb).done(() => null);
42 | setTimeout(() => {
43 | assert.isOk(cb.called);
44 | done();
45 | }, 100);
46 | });
47 | it('calls .done cb with results of jobs', function(done) {
48 | this.timeout(10000 + 500);
49 | const runner = new Parallel(2);
50 | let result = 'before/';
51 |
52 | runner
53 | .job(step0)
54 | .job(step1)
55 | .job(step2)
56 | .job(step3)
57 | .job(step4)
58 | .done(onDone);
59 |
60 | result += 'after/';
61 |
62 | function step0(done) {
63 | result += 'step0/';
64 |
65 | done('step0');
66 | }
67 |
68 | function step1(done) {
69 | result += 'step1/';
70 |
71 | setTimeout(done, 3000, 'step1');
72 | }
73 |
74 | function step2(done) {
75 | result += 'step2/';
76 |
77 | setTimeout(done, 1500, 'step2');
78 | }
79 |
80 | function step3(done) {
81 | result += 'step3/';
82 |
83 | setTimeout(done, 2000, 'step3');
84 | }
85 |
86 | function step4(done) {
87 | result += 'step4/';
88 |
89 | setTimeout(done, 500, 'step4');
90 | }
91 |
92 | let isPassed = false;
93 | function onDone(results) {
94 | assert.isArray(results);
95 | assert.deepEqual(results, ['step0', 'step1', 'step2', 'step3', 'step4']);
96 | // assert.equal(result, "before/after/step0/step1/step2/step3/step4/");
97 | isPassed = true;
98 | }
99 |
100 | setTimeout(() => done(isPassed ? null : 'not passed'), 8000);
101 | });
102 |
103 | for (let i = 1; i <= 6; i++) {
104 | let PARALLEL_LIMIT = i;
105 | it(`calls jobs in ${PARALLEL_LIMIT} parallel`, function(done) {
106 | this.timeout(PARALLEL_LIMIT * 500);
107 | const runner = new Parallel(PARALLEL_LIMIT);
108 | let currentTasks = 0;
109 | let maxNumOfParallelTasks = 0;
110 | const getTask = (delay) => (done) => {
111 | currentTasks += 1;
112 | maxNumOfParallelTasks = Math.max(maxNumOfParallelTasks, currentTasks);
113 | setTimeout(() => {
114 | maxNumOfParallelTasks = Math.max(maxNumOfParallelTasks, currentTasks);
115 | currentTasks -= 1;
116 | done(`task`);
117 | }, delay);
118 | };
119 |
120 | for (let j = 0; j <= PARALLEL_LIMIT * 5; j++) {
121 | runner.job(getTask(20));
122 | }
123 | runner.done(() => {
124 | assert.equal(maxNumOfParallelTasks, PARALLEL_LIMIT);
125 | done();
126 | });
127 | });
128 | }
129 | });
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Базовый курс JS
2 |
3 | Хорошо подумайте перед тем, как платить деньги за курс. Я об этом говорю на вводном занятии, мне не верят. Вот вам отзывы студентов: [видео](https://www.youtube.com/watch?v=5r9kr_He3q0&list=PLX3Jlot18dp7R9Tg0ccN02Pc3NTYzjcat)
4 |
5 | ## И еще отзывы студентов тут http://bit.ly/vvscode-js-truth
6 |
7 | Там же можно найти профили живых студентов
8 |
9 |
10 | Доступ к чату курса можно получить здесь http://bit.ly/codehardjs
11 |
12 |
13 | | | | |
14 | |----------------------------------------------------------------------------------- |---------------------------------------------------------------------------- |------------------------------------------------------- |
15 | | [Введение](https://github.com/vvscode/js--base-course/tree/master/00) | | Что нужно сделать ДО начала курса |
16 | | [Занятие #1](https://raw.githack.com/vvscode/js--base-course/master/01/cls/index.html) | [Задание #1](https://github.com/vvscode/js--base-course/tree/master/01/ht) | Вводное занятие и проверка подготовки к курсу |
17 | | [Занятие #2](https://raw.githack.com/vvscode/js--base-course/master/02/cls/index.html) | [Задание #2](https://github.com/vvscode/js--base-course/tree/master/02/ht) | Объекты, протипы, функции, конструкторы, наследование |
18 | | [Занятие #3](https://raw.githack.com/vvscode/js--base-course/master/03/cls/index.html) | [Задание #3](https://github.com/vvscode/js--base-course/tree/master/03/ht) | Очередь задач, асинхронность |
19 | | [Занятие #4](https://raw.githack.com/vvscode/js--base-course/master/04/cls/index.html) | [Задание #4](https://github.com/vvscode/js--base-course/tree/master/04/ht) | Интерфейсы, работа с URL |
20 | | [Занятие #5](https://raw.githack.com/vvscode/js--base-course/master/05/cls/index.html) | [Задание #5](https://github.com/vvscode/js--base-course/tree/master/05/ht) | Модульность и роутинг |
21 | | [Занятие #6](https://raw.githack.com/vvscode/js--base-course/master/06/cls/index.html) | [Задание #6](https://github.com/vvscode/js--base-course/tree/master/06/ht) | Части приложения и внешние библиотеки |
22 | | [Занятие #7](https://raw.githack.com/vvscode/js--base-course/master/07/cls/index.html) | [Задание #7](https://github.com/vvscode/js--base-course/tree/master/07/ht) | Работа с графикой |
23 | | [Занятие #8](https://raw.githack.com/vvscode/js--base-course/master/08/cls/index.html) | [Задание #8](https://github.com/vvscode/js--base-course/tree/master/08/ht) | Тестирование |
24 | ---
25 |
26 | [Список вопросов](https://raw.githack.com/vvscode/js--base-course/master/questions/index.html)
27 |
28 | ---
29 |
30 | [](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/0)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/1)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/2)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/3)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/4)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/5)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/6)[](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/7)
31 |
--------------------------------------------------------------------------------
/04/ht/README.md:
--------------------------------------------------------------------------------
1 | # Теория
2 |
3 | Прочитать материалы по следующим темам ( как минимум знать что это такое, а хотя бы пару слов зачем и как использовать ). По каждому пункту должна быть минимум 1 карточка в Anki
4 |
5 | * SOLID
6 | * KISS
7 | * DRY
8 | * YAGNI
9 | * MVC
10 | * Паттерны проектирования ( Что это? Какие есть группы? )
11 | * Антипаттерны проектирования
12 | * Модульные системы (CommonJS/ ES6 modules/ AMD)
13 | * requirejs
14 |
15 | ## Календарь задач
16 |
17 | Реализовать одностраничное приложение "Календарь задач".
18 |
19 | 
20 |
21 | ### Функционал календаря
22 |
23 | Опциональные параметры передаются в конструтор календаря
24 |
25 | * Отображение календаря
26 | * Опциональное отображение текущего месяца/года
27 | * Опциональная возможность изменения месяца кнопками "вправо/влево"
28 | * При двойном клике на ячейку календаря с датой - запросить у пользователя данные о задаче, после чего вывести запись о задаче в соответствующей ячейке. Возможность добавления записей опциональная
29 | * На каждой записи должен отображаться значок удаления записи ( удаление записей опциональное ). При клике по нему нужно запросить у пользователя подтверждение. После подтверждения удалить запись из календаря.
30 | * Календарь должен иметь возможность работать в нескольких экземплярах на странице. Независимо друг от друга.
31 | * При обновлении страницы информация о созданных заданиях должна сохраняться
32 |
33 | Календарь должен предоставлять API для программной смены месяца ( если это соответствует настройкам календаря )
34 |
35 | ## Страницы SPA ( SinglePageApplication)
36 |
37 | ### Демонстрация работы календаря
38 |
39 | Представляет полнофункциональный календарь. Со всеми возможностями
40 |
41 | ### Создание своего календаря
42 |
43 | Отображение трех блоков
44 |
45 | #### 1 - Форма настройки календаря
46 |
47 | Форма для настройки всех опциональных возможностей календаря, ввода фиксированной даты ( или отсутствие фиксации даты ), настройка класса для виджета и тп
48 |
49 | #### 2 - Блок с кодом
50 |
51 | Блок с кодом, который позволит запустить на странице календарь с выбранными настройками ( см выше ). Например
52 |
53 | ```
54 |
55 |
68 | ```
69 |
70 | #### 3 - Предпросмотр календаря
71 |
72 | Отображение календаря с текущими настройками.
73 |
74 | Любые изменения в форме 1 сразу отображаются на данных в блоках 2 и 3.
75 |
76 | Навигация между страницами происходит через меню, вверху страницы. Данные в текущей итерации хранятся в `localStorage` (важно учесть, что при нескольких календарях на странице данные для них хранятся раздельно ).
77 |
78 | Код разнести по нескольким файлам ( в соответсвии с назначением ) и интерфейсные методы/функции описать `jsdoc` комментариями.
79 |
80 | ## Тесты
81 |
82 | Приложение должно быть покрыто тестами ( unit тестами c `mocha` и интеграционными тестами c `testcafe` https://devexpress.github.io/testcafe/ ). Так же приложение должно быть задеплоено на githubpages.
83 |
84 | Задание лучше делать в отдельном репозитории. Создать отдельную ветку от ветки master, и сделать PR для оценки кода (со ссылкой на развернутую на githubpages версию )
85 |
86 | ---
87 |
88 | Добавить к конфигуратору две опции (и обновить код календаря для соответствующего функционала)
89 |
90 | * хранить данные в localStorage/firbase (изпользуя REST/fetch интерфейс к БД)
91 | * запрашивать данные через `prompt`/через модальное окно с html формой
92 |
93 | Разные пользователи должны иметь возможность хранить данные независимо. К PR прикрепить ссылку, где можно посмотреть демо работы календаря и демо конфигуратора.
94 |
--------------------------------------------------------------------------------
/02/ht/example/script.js:
--------------------------------------------------------------------------------
1 | /* eslint no-var: "off" */
2 | /* eslint no-unused-vars: "off" */
3 | /* eslint max-len: "off" */
4 |
5 | /**
6 | * Написать функцию `isDeepEqual`
7 | * которая принимает на вход двe переменных
8 | * и проверяет идентичны ли они по содержимому. Например
9 | * @param {*} objA
10 | * @param {*} objB
11 | * @return {boolean} идентичны ли параметры по содержимому
12 | */
13 | function isDeepEqual(objA, objB) {
14 | /* Ваше решение */
15 | return undefined;
16 | }
17 |
18 | /**
19 | * Функция фиксации контекста
20 | * @param {*} func Функция для которой нужно зафиксировать контекст
21 | * @param {*} context значение для this
22 | * @return {function} функция с зафиксированным контекстом
23 | */
24 | function bind(func, context) {
25 | return undefined;
26 | }
27 |
28 | /**
29 | * Реализовать метод .myBind для всех функций,
30 | * который работает так же как оригинальный .bind но не использует его внутри
31 | * (можно использовать фукнцию выше)
32 | */
33 |
34 | /**
35 | * создать объект с волшебным свойством,
36 | * чтобы при присвоении ему значения, в консоль выводилась текущая дата и значение, которое присваиваем.
37 | * А при чтении всегда выводилось число на 1 больше предыдущего
38 | * o.magicProperty = 5; // 'Sat Mar 24 2018 13:48:47 GMT+0300 (+03) -- 5'
39 | * console.log(o.magicProperty); // 6
40 | * console.log(o.magicProperty); // 7
41 | * console.log(o.magicProperty); // 8
42 | */
43 |
44 | /**
45 | * Создать конструктор с методами, так,
46 | * чтобы следующий код работал и делал соответствующие вещи
47 | * те запуск кода ниже должен делать то, что говорят методы
48 | * u.askName().askAge().showAgeInConsole().showNameInAlert();
49 | */
50 |
51 | /**
52 | * Написать фукнцию-калькулятор, которая работает следующим образом
53 | * calculate('+')(1)(2); // 3
54 | * calculate('*')(2)(3); // 6
55 | * Допустимые операции : + - * /
56 | */
57 | function calculate() {
58 | /* put your code here */
59 | }
60 |
61 | /**
62 | * Создайте конструктор-синглтон? Что такое синглтон?
63 | * new Singleton() === new Singleton
64 | */
65 | function Singleton() {
66 | throw 'undefined';
67 | }
68 |
69 | /**
70 | * Создайте функцию ForceConstructor
71 | * которая работает как конструктор независимо от того,
72 | * вызвана она с new или без
73 | * и сохраняет параметры в создаваемый объект с именами параметров
74 | */
75 | function ForceContructor(a, b, c) {
76 | throw 'undefined';
77 | }
78 |
79 | /**
80 | * Написать фукнцию сумматор, которая будет работать
81 | * var s = sum();
82 | * log(s); // 0
83 | * log(s(1)); // 1
84 | * log(s(1)(2)); //3
85 | * log(s(3)(4)(5)); // 12
86 | * Число вызовов может быть неограниченым
87 | */
88 | function sum() {
89 | throw 'undefined';
90 | }
91 |
92 | function log(x) {
93 | console.log(+x);
94 | }
95 |
96 | /**
97 | * Написать каррирующую функцию и покрыть ее тестами
98 | * Функция должна поддерживать каррирование функций с 2,3,4,5 параметрами
99 | * пример работы функции
100 | *
101 | * function target1(a,b,c,d) { return a + b + c + d }
102 | * function target2(a,b) { return a + b }
103 | * curry(target1)(1)(2)(3)(4) // 10
104 | * curry(target2)(5)(8) // 13
105 | *
106 | * Примеры тестов смотреть в файле тестов
107 | *
108 | * Читать
109 | * http://prgssr.ru/development/vvedenie-v-karrirovanie-v-javascript.html
110 | * https://github.com/MostlyAdequate/mostly-adequate-guide-ru/blob/master/ch4-ru.md
111 | * @param {*} func
112 | */
113 | function curry(func) {}
114 |
115 | /*
116 | Написать код, который для объекта созданного с помощью конструктора будет показывать,
117 | что объект является экземпляром двух классов
118 | */
119 | /* Тут ваш код */
120 | // User === PreUser; // false
121 | // u instanceof User; // true
122 | // u instanceof Array; // true
123 | // u instanceof PreUser; // true
124 |
125 | /*
126 | Создать веб страницу. Добавить на нее форму с полями
127 | - имя (строкое поле),
128 | - родной город (Выпадающий список),
129 | - Комментарий (многострочное поле), пол (radiobutton).
130 | При нажатии на кнопку - нужно собрать данные введенные в поля и вывести их в блоке под формой,
131 | после чего поля очистить.
132 | */
133 |
134 | /*
135 | Используя функцию drawCalendar из прошлого урока
136 | создать функцию drawInteractiveCalendar(el)
137 | Которая выводит календарь, в шапке которого отображается
138 | [<] месяц / год [>]
139 | При клике по кнопкам [<] / [>] нужно реализовать листание календаря
140 | Добавть на страницу index.html вызов календаря
141 | */
142 | function drawInteractiveCalendar(el) {}
143 |
--------------------------------------------------------------------------------
/00/README.md:
--------------------------------------------------------------------------------
1 | # Это вводный материал, для подготовки к первому занятию на курсе FD2 по javascript
2 |
3 | Очень советую ознакомиться со всеми материалами и выполнить все задания. До конца курса в моих группах доходят не все.
4 |
5 | ## На случай, если ты подумал(а), что это шутки - нифига https://www.youtube.com/playlist?list=PLX3Jlot18dp7R9Tg0ccN02Pc3NTYzjcat
6 |
7 | ## На занятиях понадобится
8 |
9 | - Тетрадь ( желательно формата А4)
10 | - Ручка / Карандаш
11 | - В идеале посещать занятия со своим компьютером. В классе есть рабочие машины, но гораздо удобнее работать в привычной среде, с знакомой клавиатурой/системой/редактором. Так что это не обязательно, но в ваших интересах.
12 |
13 |
14 | ## Перед первым занятием нужно прочитать
15 |
16 | - [Как правильно задавать вопросы в технических форумах](https://www.opennet.ru/docs/RUS/smart_question/) - прочитать и составить письменно чеклист по задаванию вопросов
17 | - [Как эффективно сообщать об ошибках](https://www.chiark.greenend.org.uk/~sgtatham/bugs-ru.html) - как задавать вопросы о неработающем коде или примерах, прочитать, запомнить, усвоить
18 | - [Блок-схемы алгоритмов. ГОСТ. Примеры](https://pro-prof.com/archives/1462)
19 |
20 | ---
21 | - [Введение в JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_JavaScript#Scratchpad)
22 | - [Основы JavaScript](https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics) - После прочтения найти соответствия из конструкций языка к элементам блок-схем
23 |
24 | ---
25 | - [Преимущества метода интервального запоминания](http://web.archive.org/web/20170315102949/https://habrahabr.ru/company/everydaytools/blog/322286/)
26 | - [Дерек Сиверс: «Метод интервального повторения — лучший способ изучения языков программирования»](https://habrahabr.ru/post/196448/)
27 |
28 | ---
29 | - [Git. Просто Git](http://zzet.org/git/learning/undev/coursify/2014/02/09/lection-1-git-course-undev.html)
30 | - [Скринкаст по Git](https://www.youtube.com/playlist?list=PLDyvV36pndZHkDRik6kKF6gSb0N0W995h)
31 |
32 |
33 | ## Перед первым занятием нужно сделать
34 |
35 | - Сформулировать развернутый ответ на вопросы *"Зачем мне этот курс? Зачем я сюда пришел?"*
36 | - Сформулировать развернутый ответ на вопрос *"Как я пойму, что курс был для меня полезен? По каким критерия я буду оценивать свои результаты? Какой идеальный конечный результат, на который я нацелен?"*
37 | - Зарегистрировать аккаунт на [GitHub.com](http://github.com) и максимально заполнить профиль (в идеале - имя аккаунта - это ваше имя+фамилия) + пройти до конца курс [TryGit](https://try.github.io/levels/1/challenges/1)
38 |
39 | ## Практическое задание
40 |
41 | Создать страницу:
42 | - При открытии у пользователя сначала нужно спросить его имя, а потом возраст (можно использовать функцию `prompt`).
43 | - Если пользователь не ввел имя/возраст - запросить данные повторно ( пока данные не будут заполнены ).
44 | - После ввода пользователя вывести на странице сообщение.
45 | - Если возвраст пользователя меньше 18 - `Здарова, {{ИМЯ_ПОЛЬЗОВАТЕЛЯ}}. Как твои {{ВОЗРАCТ ПОЛЬЗОВАТЕЛЯ}}?`.
46 | - Если возраст пользователя больше либо равен 18 - `Привествую, {{ИМЯ_ПОЛЬЗОВАТЕЛЯ}}. Уж {{ВОЗРАCТ ПОЛЬЗОВАТЕЛЯ}} лет прошло`
47 |
48 | Для сдачи задания на проверку нужно сделать [fork](https://help.github.com/articles/fork-a-repo/) этого репозитория. В своем форке создать отдельную ветку `00`. В этой ветке создать папку `00/ht/{{ВАШ_НИК_НА_GITHUB}}` и в этой папке разместить созданную страницу. После чего сделать [commit и push](https://readwrite.com/2013/10/02/github-for-beginners-part-2/) и создать [pull request](https://help.github.com/articles/about-pull-requests/) в этот репозиторий.
49 |
50 | ### Теория (знание ответов на вопросы проверяется на занятии!)
51 | - Что такое git?
52 | - Какие есть системы контроля версий?
53 | - как создать ветку в git?
54 | - что такое HTML?
55 | - что такое CSS?
56 | - как зовут создателя JavaScript?
57 | - в каком году был создан JavasScript?
58 | - Какая текущая версия Javacript?
59 | - Какая прошлая версия Javascript?
60 | - Какого номера версии Javascript не было?
61 | - Как называется комитет, занимающийся развитием JavaScript?
62 | - Для чего нужен файл .gitignore?
63 | - Как добавить в git пустую папку?
64 | - Что такое "линтер"?
65 | - Для чего нужен "prettier"?
66 | - Как открыть DevTools в браузере?
67 | - Как можно добавить javascript на страницу?
68 | - Сколько будет `0.2 + 0.1`?
69 | - Что такое breakpoint?
70 | - Какие методы есть у объекта `console`?
71 | - На странице два элемента с `id="awesomeId"`. Как из javascript найти второй?
72 | - Что такое falsy (ложное) значение? Сколько их?
73 | - Назовите 4 javascript фреймворка
74 | - Назовите 3 javascript библиотеки
75 | - Что такое cookies?
76 | - Что происходит между вводом в адресной строке адреса страницы и появлением страницы на экране?
77 | - Зачем нужен DNS сервер?
78 | - Что такое HTTP?
79 | - Назовите 3 программы-веб сервера
80 | - Назовите 5 программ-браузеров
81 | - Полное название Javascript?
82 | - Что такое "транспиляция" в контексте разработки на Javascript?
83 | - Как в Slack оформить многострочный код?
84 | - Как в Slack оформить однострочный код?
85 | - Что такое "императивное программирование"?
86 | - Что такое ООП?
87 |
88 |
--------------------------------------------------------------------------------
/.ht/01/script.tests.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /* eslint no-var: "off" */
4 | /* eslint no-unused-vars: "off" */
5 | /* eslint max-len: "off" */
6 |
7 | describe("fizzBuzz", function() {
8 | it("функция", function() {
9 | return assert.isOk(typeof fizzBuzz === "function");
10 | });
11 |
12 | var result =
13 | "\n1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz";
14 |
15 | var _log = window.log;
16 | var str = "";
17 | window.log = function(a) {
18 | return (str = str + a + "\n");
19 | };
20 | fizzBuzz();
21 |
22 | it("выводит правильные данные", function() {
23 | return assert.isOk(str.trim() === result.trim());
24 | });
25 | it("не использует `if`", function() {
26 | return assert.isOk(("" + fizzBuzz).indexOf("if") < 0);
27 | });
28 | it("не использует `else`", function() {
29 | return assert.isOk(("" + fizzBuzz).indexOf("else") < 0);
30 | });
31 | it("не использует `switch`", function() {
32 | return assert.isOk(("" + fizzBuzz).indexOf("switch") < 0);
33 | });
34 | it("не использует `? :`", function() {
35 | return assert.isOk(("" + fizzBuzz).indexOf("?") < 0);
36 | });
37 | });
38 |
39 | describe("isPolindrom", function() {
40 | it("функция", function() {
41 | return assert.isOk(typeof isPolindrom === "function");
42 | });
43 | it("возвращает true/false", function() {
44 | return assert.isOk(typeof isPolindrom("") === "boolean");
45 | });
46 | it("asd - не полиндром", function() {
47 | return assert.isOk(isPolindrom("asd") === false);
48 | });
49 | it("asdsa - полиндром", function() {
50 | return assert.isOk(isPolindrom("asdsa") === true);
51 | });
52 | it('"" - полиндром', function() {
53 | return assert.isOk(isPolindrom("") === true);
54 | });
55 | it("asdsb - не полиндром", function() {
56 | return assert.isOk(isPolindrom("asdsb") === false);
57 | });
58 | it("'1231' - не полиндром", function() {
59 | return assert.isOk(isPolindrom("1231") === false);
60 | });
61 | });
62 |
63 | describe("drawCalendar", function() {
64 | var el;
65 | beforeEach(function() {
66 | return (el = document.createElement("div"));
67 | });
68 |
69 | it("функция", function() {
70 | return assert.isOk(typeof drawCalendar === "function");
71 | });
72 | it("заполняет innerHTML у элемента (третий аргумент)", function() {
73 | drawCalendar(2017, 9, el);
74 | assert.isOk(el.innerHTML.trim() !== "");
75 | });
76 | it("генерирует разный html для разных месяцев", function() {
77 | drawCalendar(2017, 9, el);
78 | var html1 = el.innerHTML;
79 | drawCalendar(2017, 10, el);
80 | var html2 = el.innerHTML;
81 | assert.isOk(html1 !== html2);
82 | });
83 | it("правильно определяет число дней в месяце", function() {
84 | drawCalendar(2017, 9, el);
85 | var html = el.innerHTML;
86 | assert.isOk(html.indexOf("30") > 0);
87 | assert.isOk(html.indexOf("31") < 0);
88 |
89 | drawCalendar(2017, 2, el);
90 | var html = el.innerHTML;
91 | assert.isOk(html.indexOf("28") > 0);
92 | assert.isOk(html.indexOf("29") < 0);
93 | assert.isOk(html.indexOf("30") < 0);
94 | assert.isOk(html.indexOf("31") < 0);
95 | });
96 | /** Остальные проверки сильно зависят от разметки календаря */
97 | });
98 |
99 | describe("isDeepEqual", function() {
100 | it("фунция", function() {
101 | return assert.isOk(typeof isDeepEqual === "function");
102 | });
103 | it("возвращает true/false", function() {
104 | return assert.isOk(typeof isDeepEqual("", "") === "boolean");
105 | });
106 | it("распознает одинаковые строки", function() {
107 | return assert.isOk(isDeepEqual("мама", "мама") === true);
108 | });
109 | it("распознает разные строки", function() {
110 | return assert.isOk(isDeepEqual("мама", "папа") === false);
111 | });
112 |
113 | it("распознаем разные массивы", function() {
114 | return assert.isOk(isDeepEqual([1, 4, 2], [1, 2, 4]) === false);
115 | });
116 | it("распознает одинаковые массивы", function() {
117 | return assert.isOk(isDeepEqual([1, 2, 4, 3], [1, 2, 4, 3]) === true);
118 | });
119 | it("распознает массивы разной длинны", function() {
120 | return assert.isOk(isDeepEqual([1, 2, 5], [1, 2, 5, 7]) === false);
121 | });
122 |
123 | var a = { prop1: 1, list: [1, 2, 3], o: { x: 2 } };
124 | var b = { list: [1, 2, 3], o: { x: 2 } };
125 | it("распознает разные объекты", function() {
126 | return assert.isOk(isDeepEqual(a, b) === false);
127 | });
128 |
129 | it("распознает одинаковые объекты", function() {
130 | b.prop1 = 1;
131 | return assert.isOk(isDeepEqual(a, b) === true);
132 | });
133 |
134 | it("распознает разные объекты", function() {
135 | var a = { a: 1, b: 3, c: 2 };
136 | var b = { a: 1, b: 4, c: 2 };
137 | return assert.isOk(isDeepEqual(a, b) === false);
138 | });
139 |
140 | it("распознает вложенные объекты", function() {
141 | var a = { a: 1, b: { x: 5 }, c: 2 };
142 | var b = { a: 1, b: { x: 5 }, c: 2 };
143 | return assert.isOk(isDeepEqual(a, b) === true);
144 | });
145 |
146 | it("распознает числа", function() {
147 | var a = 1;
148 | var b = 1.0;
149 | return assert.isOk(isDeepEqual(a, b) === true);
150 | });
151 |
152 | it("распознает разные числа", function() {
153 | let a = 1;
154 | let b = 2;
155 | return assert.isOk(isDeepEqual(a, b) === false);
156 | });
157 | });
158 |
--------------------------------------------------------------------------------
/02/ht/README.md:
--------------------------------------------------------------------------------
1 | ## Домашнее задание
2 |
3 | ### Прочитать\* (с выполнением задач) разделы из учебника [Learn.Javascript.Ru](http://learn.javascript.ru/):
4 |
5 | * [Автоматические тесты при помощи chai и mocha](https://learn.javascript.ru/testing)
6 | * [Отладка в браузере Chrome](https://learn.javascript.ru/debugging-chrome)
7 | * [Методы объектов и контекст вызова](https://learn.javascript.ru/objects-more)
8 | * [setTimeout и setInterval](https://learn.javascript.ru/settimeout-setinterval)
9 | * [Документ, события, интерфейсы](https://learn.javascript.ru/ui)
10 |
11 | ### Найти ответы на вопросы (это то, что будет спрашиваться на занятии):
12 |
13 | * Что такое контекст вызова функции? Чем определяется?
14 | * Как изменить `this` внутри функции? (5 способов)
15 | * чем различаются `.call` / `.apply` / `.bind`
16 | * Что такое сигнатура функции?
17 | * Чем характеризуется функция?
18 | * Что такое прототип?
19 | * Как работает конструктор? Что происходит при вызове со словом `new` ?
20 | * Как происходит чтение свойств из объекта?
21 | * Как происходит запись свойств в объект?
22 | * Как проверить на принадлежность классу?
23 | * Как работает `instanceof` ?
24 | * 4е принципа ООП
25 | * Виды полиморфизма. И их объяснение
26 | * Событийный цикл в javascript
27 | * Что такое фаза захвата / capturing ?
28 | * Что такое фаза всплытия / bubbling ?
29 | * Как подписаться на событие документа / html элемента?
30 | * Что такое `Функция высшего порядка`?
31 | * Что такое синхронный / асинхронный код?
32 | * Что такое `каррирование` ?
33 | * Что такое паттерн `цепочка` ? Как реализовать?
34 | * В чем разница объявления методов в конструкторе и на `.prototype` ?
35 | * Что такое 'полифилл'?
36 |
37 | ### Решить задачи (подробнее см [файл с тестами](https://github.com/vvscode/js--base-course/blob/master/.ht/02/script.tests.js))
38 |
39 | * `isDeepEqual` (добавлены тесты)
40 | * написать ФВП (функцию высшего порядка) `bind`
41 | * написать методы `.myBind` (именно с таким названием)
42 | * создать объект с волшебным свойством, чтобы при присвоении ему значения, в консоль выводилась текущая дата и значение, которое присваиваем. А при чтении всегда выводилось число на 1 больше предыдущего
43 |
44 | ```javascript
45 | o.magicProperty = 5; // 'Sat Mar 24 2018 13:48:47 GMT+0300 (+03) -- 5'
46 | console.log(o.magicProperty); // 6
47 | console.log(o.magicProperty); // 7
48 | console.log(o.magicProperty); // 8
49 | ```
50 |
51 | * создать конструктор для работы с цепочками вызовов
52 | * написать функцию калькулятор
53 | * написать синглтон
54 | * написать конструктор, который всегда конструктор
55 |
56 | ```javascript
57 | var u = User();
58 | u instanceof User; // true
59 | ```
60 |
61 | * написать сумматор
62 | * написать и покрыть тестами каррирующую функцию `curry` ( преобразующую функцию - из функции многих аргументов, получить множество функций одного аргумента)
63 |
64 | ```javascript
65 | function sum2(x, y) {
66 | return x + y;
67 | }
68 | function sum4(a, b, c, d) {
69 | return a + b + c + d;
70 | }
71 |
72 | curry(sum2)(1)(2); // 3
73 | curry(sum4)(2)(3)(4)(5); // 14
74 | ```
75 |
76 | * создать цепочку наследования
77 |
78 | ```javascript
79 | var u = new User();
80 | var u2 = new User();
81 | assert.isOk(u instanceof User);
82 | assert.isOk(u instanceof Array);
83 | assert.isOk(u instanceof PreUser);
84 | ```
85 |
86 | * создать форму и ее обработчик. На форме поля ввода - Имя пользователя( строка ), возраст (выпадающий список), пол - radio-button, есть ли водительские права - чекбокс, о себе - многострочное поле. Все поля обязательные. При отправке формы, если все заполнено - под формой вывести информацию собранную от пользователя.
87 | * создать генератор листаемого календаря и покрыть его тестами. В шапку календаря из прошлго ДЗ добавить кнопки для листания вправо/влево, которые позволяют изменыть отображаемый месяц. Тесты должны проверять весь функционал
88 | * создать функцию, которая не может работать как конструктор (работать с `new`, и покрыть ее тестами
89 |
90 | ---
91 |
92 | * Написать реализацию метода `.myCall`, который будет работать аналогично системному `.call` и покрыть реализацию тестами
93 | * Написать реализацию функций [debounce](http://underscorejs.ru/#debounce) и [throttle](http://underscorejs.ru/#throttle) и покрыть реализации тестами ( Если ваше имя начинается с гласной - `debounce`, иначе - `throttle`. А лучше - обе ). Функции должны с сигнатурой `debounce(fun, delay)` / `throttle(fun, delay)`
94 | * К генератору листаемого календаря добавить функционал: под календарем добавить блок. При клике на ячейку даты ( но не на пустую ячейку календаря ) в блоке должна добавляться запись о том, по какой ячейке кликнули. Можно добавить запрос описания даты от пользователя ( с помощью функции `prompt` и выводить это описание там же). История дат и список, по которым пользоатель кликал, должны сохраняться между перезагрузками страницы. Для сохранения использовать [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Интерфейс работы с данными (чтение/запись) лучше сделать асинхронным
95 | * Создать синхронную функцию `sleep(seconds)` так, чтобы работал код
96 |
97 | ```javascript
98 | console.log(new Date()); // Sun Oct 08 2017 10:44:34 GMT+0300 (+03)
99 | sleep(9);
100 | console.log(new Date()); // Sun Oct 08 2017 10:44:43 GMT+0300 (+03)
101 | ```
102 |
103 | * Написать функцию `getCounter` и покрыть ее тестами, так, чтобы работал следующий код
104 |
105 | ```javascript
106 | var c = getCounter(5);
107 | c
108 | .log() // 5
109 | .add(4)
110 | .log() // 9
111 | .add(3)
112 | .log() // 12
113 | .reset()
114 | .log() // 0
115 | .add(8)
116 | .log(); // 8
117 | ```
118 |
119 | ## Видео
120 |
121 | * [https://www.youtube.com/watch?v=8cV4ZvHXQL4](https://www.youtube.com/watch?v=8cV4ZvHXQL4)
122 | * [https://learn.javascript.ru/screencast/gulp](https://learn.javascript.ru/screencast/gulp)
123 |
--------------------------------------------------------------------------------
/10/cls/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Js Base Course - Занятие 10
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
30 |
31 |
32 |
33 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/questions/script.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | const questions0 = `Что такое git?
4 | Какие есть системы контроля версий?
5 | как создать ветку в git?
6 | что такое HTML?
7 | что такое CSS?
8 | как зовут создателя JavaScript?
9 | в каком году был создан JavasScript?
10 | Какая текущая версия Javacript?
11 | Какая прошлая версия Javascript?
12 | Какого номера версии Javascript не было?
13 | Как называется комитет, занимающийся развитием JavaScript?
14 | Для чего нужен файл .gitignore?
15 | Как добавить в git пустую папку?
16 | Что такое "линтер"?
17 | Для чего нужен "prettier"?
18 | Как открыть DevTools в браузере?
19 | Как можно добавить javascript на страницу?
20 | Сколько будет 0.2 + 0.1?
21 | Что такое breakpoint?
22 | Какие методы есть у объекта console?
23 | На странице два элемента с id="awesomeId". Как из javascript найти второй?
24 | Что такое falsy (ложное) значение? Сколько их?
25 | Назовите 4 javascript фреймворка
26 | Назовите 3 javascript библиотеки
27 | Что такое cookies?
28 | Что происходит между вводом в адресной строке адреса страницы и появлением страницы на экране?
29 | Зачем нужен DNS сервер?
30 | Что такое HTTP?
31 | Назовите 3 программы-веб сервера
32 | Назовите 5 программ-браузеров
33 | Полное название Javascript?
34 | Что такое "транспиляция" в контексте разработки на Javascript?
35 | Как в Slack оформить многострочный код?
36 | Как в Slack оформить однострочный код?
37 | Что такое "императивное программирование"?
38 | Что такое ООП?`;
39 |
40 | const questions1 = `
41 | Что такое переменная?
42 | как объявить переменную? как инициализировать переменную?
43 | виды циклов ( 3 вида ) ?
44 | сколько и какие типы данных в javascript?
45 | Как узнать тип переменной?
46 | что такое область видимости?
47 | каким образом можно реализовать условное выполнение кода ?
48 | условные операторы в javascript - какие?
49 | что такое тернарный оператор?
50 | Как обойтись без условных операторов если нужно сделать условное выполнение кода?
51 | что такое функция?
52 | какими характеристиками можно описать функцию?
53 | Как можно создать функцию? 3 способа.
54 | Что такое объект? Как создать объект? ( 3 способа )
55 | Что такое передача по ссылке / передача по значению?
56 | Что такое минификация и зачем она нужна?
57 | Как можно добавить javascript код в html страницу? 2 способа
58 | Что такое массив?
59 | Как создать массив? ( 3 способа )
60 | Как запросить данные у пользователя?
61 | Что такое замыкание?
62 | Как узнать сколько параметров принимает функция?
63 | Как узнать есть ли у объекта свойство x ?
64 | Как сделать ревес строки?
65 | Как удалить предпоследний элемент в массиве?
66 | Как заменить в строке "papa roach" все буквы a на A ?
67 | Сколькими способами ( с примерами кода ) можно найти на странице div с id someId ?
68 | Как устроен событийный цикл в js?
69 | Что такое API? Примеры?
70 | Как в js реализовать многопоточность?
71 | Как в js реализовать наследование одного "класса" от другого?
72 | Сколькими способами можно проитерироваться по всем полям объекта?
73 | Что такое callback ? Зачем ?
74 | Почему 1 + '2' ? и 1 - '2' ?
75 | Как и когда работает преобразование типов?
76 | Что такое HTTP ?
77 | Какие есть методы HTTP запросов? Для чего каждый?
78 | Что такое REST ? RPC ?
79 | Что такое "линтер" (linter) ? Зачем они нужны? Какие линтеры есть для javascript?
80 | Что такое "jsdoc" ? Найдите его в своем домашнем задании. Зачем он нужен? Объясните использовнные теги.
81 | Что такое пакетный менеджер?
82 | Какие пакетные менеджеры есть для js?
83 | Что делают системы сборки?
84 | Какие системы сборки есть для js?`;
85 |
86 | const questions2 = `Как изменить "this" внутри функции? (5 способов)
87 | чем различаются ".call" / ".apply" / ".bind"
88 | Что такое контекст вызова функции? Чем определяется?
89 | Что такое сигнатура функции?
90 | Чем характеризуется функция?
91 | Что такое прототип?
92 | Как работает конструктор? Что происходит при вызове со словом "new" ?
93 | Как происходит чтение свойств из объекта?
94 | Как происходит запись свойств в объект?
95 | Как проверить на принадлежность классу?
96 | Как работает "instanceof" ?
97 | 4е принципа ООП
98 | виды полиморфизма. И их объяснение
99 | событийный цикл в javascript
100 | что такое фаза захвата / capturing ?
101 | что такое фаза всплытия / bubbling ?
102 | как подписаться на событие документа / html элемента?
103 | что такое "Функция высшего порядка"?
104 | что такое синхронный / асинхронный код?
105 | что такое "каррирование" ?
106 | в чем разница объявления методов в конструкторе и на .prototype" ?
107 | что такое 'полифилл'?`;
108 |
109 | const questions3 = `Что такое "стрелочная" ("arrow function") функция? Чем она отличается от обычной?
110 | Что такое Promise? Какой стандарт отписывает поведение Promise? Основные пункты стандарта?
111 | Чем куки (cookie) отличаются от localStorage ?
112 | Что такое CORS?
113 | Что такое и какие есть коды ответов HTTP?
114 | Что такое jsonp-запрос?
115 | Как код, написанный на ES6 (ES2015-2017) превратить в код, который поддерживается IE10?
116 | Как реализовать простейший модуль на js?
117 | Что такое и зачем нужен паттерн модуль? Какие модули существуют в JS?
118 | Как реализовать подписку на клик по кнопке, которая отработает только один раз? ( с примером кода )
119 | Какие события не "всплывают" ?
120 | Что такое делегирование?
121 | Преимущества и особенности работы с делегированием?
122 | Какие вспомогательные методы есть для работы с промисами?
123 | в чем разница между следующими кусками кода?
promise.then(onSuccess, onError);
promise.then(onSuccess).catch(onError);
124 | в чем разница между следующими кусками кода?
139 | function log(a) { console.log(a); }
140 | /*
141 | Напишите программу, которая выводит на экран числа от 1 до 100.
142 | При этом вместо чисел, кратных трем, программа должна выводить слово «Fizz»,
143 | а вместо чисел, кратных пяти — слово «Buzz».
144 | Если число кратно и 3, и 5, то программа должна выводить слово «FizzBuzz»
145 | */
146 | log(1);
147 | log(2);
148 | log('Fizz');
149 | log(4);
150 | log('Buzz');
151 |
221 | test stub (заглушка), используется для получения данных из внешней зависимости, подменяя её.
222 |
223 | test spy (тестовый шпион), используется для тестов взаимодействия, основной функцией является запись
224 | данных и вызовов, поступающих из тестируемого объекта для последующей проверки
225 |
226 | mock object (мок-объект), очень похож на тестовый шпион, однако не записывает последовательность вызовов
227 | с переданными параметрами для последующей проверки