diff --git a/frontend/components/slider/slider.js b/frontend/components/slider/slider.js deleted file mode 100644 index 8c0533d..0000000 --- a/frontend/components/slider/slider.js +++ /dev/null @@ -1,27 +0,0 @@ -/* global $ */ -import convertRemToPixels from '../../scripts/convertRemToPixels'; - -class Slider { - constructor(element) { - this.$element = $(element); - this.$parent = this.$element.parent(); - this.$view = this.$parent.find('.js-slider__view'); - this.$line = this.$parent.find('.js-slider__line'); - this.sliderChange.call(this); - this.$element.on('input.slider', this.sliderChange.bind(this)); - } - sliderChange() { - const { $element } = this; - const width = $element.width() - convertRemToPixels(1.25); - const value = $element.val(); - const min = this.$element.prop('min'); - const max = this.$element.prop('max'); - const newLeft = ((width / (max - min)) * (value - min)) - convertRemToPixels(0.625); - this.$view.text(value).css({ left: newLeft }); - const newWidth = ((width / (max - min)) * (value - min)) + convertRemToPixels(0.625); - this.$line.width(newWidth); - } -} - -let sliders = []; -$('.js-slider__input').each((index, element) => sliders.push(new Slider(element))); diff --git a/frontend/components/slider/slider.pug b/frontend/components/slider/slider.pug index af116bf..c2e91a3 100644 --- a/frontend/components/slider/slider.pug +++ b/frontend/components/slider/slider.pug @@ -5,7 +5,7 @@ mixin slider(options) - options.value = options.value || 0 - options.mix = options.mix || '' - div(class = "slider slider_color_" + options.color + " " + options.mix) + div(class = "slider js-slider slider_color_" + options.color + " " + options.mix) if (options.view) .slider__view.js-slider__view #{options.value} if (options.line) diff --git a/frontend/components/slider/slider.ts b/frontend/components/slider/slider.ts new file mode 100644 index 0000000..da43968 --- /dev/null +++ b/frontend/components/slider/slider.ts @@ -0,0 +1,31 @@ + +import convertRemToPixels from '../../scripts/convertRemToPixels'; + +class Slider { + $block: JQuery; + $slider: JQuery; + $view: JQuery; + $line: JQuery; + constructor(element) { + this.$block = $(element); + this.$slider = this.$block.find('.js-slider__input'); + this.$view = this.$block.find('.js-slider__view'); + this.$line = this.$block.find('.js-slider__line'); + this.sliderChange.call(this); + this.$slider.on('input.slider', this.sliderChange.bind(this)); + } + sliderChange(): void { + const { $slider } = this; + const width: number = $slider.width() - convertRemToPixels(1.25); + const value: number = Number($slider.val()); + const min: number = Number(this.$slider.prop('min')); + const max: number = Number(this.$slider.prop('max')); + const newLeft: number = ((width / (max - min)) * (value - min)) - convertRemToPixels(0.625); + this.$view.text(value).css({ left: newLeft }); + const newWidth: number = ((width / (max - min)) * (value - min)) + convertRemToPixels(0.625); + this.$line.width(newWidth); + } +} + +let sliders: Slider[] = []; +$('.js-slider').each((index, element) => { sliders.push(new Slider(element)); }); diff --git a/frontend/components/standart-button/standart-button.js b/frontend/components/standart-button/standart-button.ts similarity index 51% rename from frontend/components/standart-button/standart-button.js rename to frontend/components/standart-button/standart-button.ts index 9d729a5..c359054 100644 --- a/frontend/components/standart-button/standart-button.js +++ b/frontend/components/standart-button/standart-button.ts @@ -1,17 +1,19 @@ -/* global $ */ + import convertRemToPixels from '../../scripts/convertRemToPixels'; class Button { + $element: JQuery; + size: number; constructor(element) { this.$element = $(element).on('click.standart-button', this.rippleEffect.bind(this)); this.size = convertRemToPixels(2); } - rippleEffect(event) { - const $div = $('
').attr('id', 'button__ripple'); - $div.css({ top: `${event.offsetY - this.size}px`, left: `${event.offsetX - this.size}px` }); + rippleEffect({ offsetX, offsetY }): void { + const $div: JQuery = $('
').attr('id', 'button__ripple'); + $div.css({ top: `${offsetY - this.size}px`, left: `${offsetX - this.size}px` }); this.$element.append($div); setTimeout(() => $div.remove(), 550); } } let buttons = []; -$('.js-standart-button').each((index, element) => buttons.push(new Button(element))); +$('.js-standart-button').each((index, element) => { buttons.push(new Button(element)); }); diff --git a/frontend/index.ts b/frontend/index.ts index 6b1fee5..78a769b 100644 --- a/frontend/index.ts +++ b/frontend/index.ts @@ -1,7 +1,8 @@ import './index.styl'; import './favicons/favicons'; import './components/slider/slider'; -import Controller from './mvc/controller/Controller.ts'; +import './components/standart-button/standart-button'; +import Controller from './mvc/controller/Controller'; import Model from './mvc/model/Model'; import View from './mvc/view/View'; diff --git a/frontend/mvc/controller/Controller.ts b/frontend/mvc/controller/Controller.ts index 9a61f91..9742f42 100644 --- a/frontend/mvc/controller/Controller.ts +++ b/frontend/mvc/controller/Controller.ts @@ -1,5 +1,6 @@ -import IModel from '../model/IModel'; -import IView from '../view/IView'; +import { IModel } from '../model/IModel'; +import { IView } from '../view/IView'; + class Controller { model: IModel; @@ -15,34 +16,34 @@ class Controller { this.setRunning(false); } setSubscription():void { - this.model.matrixChanged.attach((sender, obj) => { - if (obj.resized) { this.view.initTable(obj.matrix); } - else { this.view.changeTable(obj.matrix); } + this.model.matrixChanged.attach((sender, { resized , matrix }) => { + if (resized) { this.view.initTable(matrix); } + else { this.view.changeTable(matrix); } }); this.view.tableCellChanged.attach((sender, { row, cell }) => { this.model.toggleCell(row, cell); }); - this.view.startEvent.attach(() => { + this.view.started.attach(() => { this.setRunning(true); this.anim(); }); - this.view.pauseEvent.attach(() => { + this.view.paused.attach(() => { this.setRunning(false); }); - this.view.clearEvent.attach(() => { + this.view.cleared.attach(() => { this.model.clearMatrix(); this.setRunning(false); }); - this.view.speedChanged.attach((sender, options) => { - this.fps = options.value; + this.view.speedChanged.attach((sender, value) => { + this.fps = value; }); - this.view.widthChanged.attach((sender, options) => { + this.view.widthChanged.attach((sender, value) => { this.setRunning(false); - this.model.setWidthMatrix(options.value); + this.model.setWidthMatrix(value); }); - this.view.heightChanged.attach((sender, options) => { + this.view.heightChanged.attach((sender, value) => { this.setRunning(false); - this.model.setHeightMatrix(options.value); + this.model.setHeightMatrix(value); }); } setRunning(value: boolean): void { diff --git a/frontend/mvc/model/IModel.ts b/frontend/mvc/model/IModel.ts index 3024706..d3ceb81 100644 --- a/frontend/mvc/model/IModel.ts +++ b/frontend/mvc/model/IModel.ts @@ -1,8 +1,13 @@ import IEventSender from '../utils/IEventSender'; +type matrixChangedMessage = { + matrix: boolean[][]; + resized?: boolean; +}; + interface IModel { matrix: boolean[][]; - matrixChanged: IEventSender; + matrixChanged: IEventSender; setWidthMatrix(newValue: number): void; setHeightMatrix(newValue: number): void; clearMatrix(): void; @@ -11,4 +16,4 @@ interface IModel { toggleCell(row: number, column: number): void; } -export default IModel; +export { IModel, matrixChangedMessage }; diff --git a/frontend/mvc/model/Model.ts b/frontend/mvc/model/Model.ts index bebd095..4433dcb 100644 --- a/frontend/mvc/model/Model.ts +++ b/frontend/mvc/model/Model.ts @@ -1,19 +1,19 @@ -import Event from '../utils/EventSender'; -import IModel from './IModel'; +import EventSender from '../utils/EventSender'; +import { IModel, matrixChangedMessage } from './IModel'; import '../../scripts/arrayFrom-polyfill'; class Model implements IModel{ matrix: boolean[][]; rows: number; columns: number; - listOldMatrix: boolean[][][]; - matrixChanged: Event; + stateHistory: boolean[][][]; + matrixChanged: EventSender; constructor(rows: number = 10, columns: number = 10) { this.initMatrix(rows, columns); this.rows = rows; this.columns = columns; - this.listOldMatrix = []; - this.matrixChanged = new Event(this); + this.stateHistory = []; + this.matrixChanged = new EventSender(this); } initMatrix(rows: number, columns: number): void { this.matrix = Array.from(Array(rows), () => Array.from(Array(columns), () => false)); @@ -29,7 +29,7 @@ class Model implements IModel{ return row.slice(0, newWidth); }); this.columns = newWidth; - this.listOldMatrix = []; + this.stateHistory = []; this.matrixChanged.notify({ matrix: this.matrix, resized: true }); } setHeightMatrix(newHeight: number): void { @@ -38,12 +38,12 @@ class Model implements IModel{ return this.getNewRow(this.columns); }); this.rows = newHeight; - this.listOldMatrix = []; + this.stateHistory = []; this.matrixChanged.notify({ matrix: this.matrix, resized: true }); } clearMatrix(): void { this.initMatrix(this.rows, this.columns); - this.listOldMatrix = []; + this.stateHistory = []; this.matrixChanged.notify({ matrix: this.matrix }); } calculateMatrix(): void { @@ -53,15 +53,15 @@ class Model implements IModel{ this.matrixChanged.notify({ matrix: this.matrix }); } isRepeatMatrix(): boolean { - const result: boolean = this.listOldMatrix.some((matrix: boolean[][]) => + const result: boolean = this.stateHistory.some((matrix: boolean[][]) => matrix.every((row: boolean[], i: number) => row.every((cell: boolean, j: number) => (cell === this.matrix[i][j]), ), ), ); - if (result) { this.listOldMatrix = []; } - else { this.listOldMatrix.push(this.matrix); } + if (result) { this.stateHistory = []; } + else { this.stateHistory.push(this.matrix); } return result; } calculateCell(row: number, column: number): boolean { diff --git a/frontend/mvc/utils/EventSender.ts b/frontend/mvc/utils/EventSender.ts index 260a8db..a701ea8 100644 --- a/frontend/mvc/utils/EventSender.ts +++ b/frontend/mvc/utils/EventSender.ts @@ -1,16 +1,16 @@ import IEventSender from './IEventSender'; -class EventSender implements IEventSender { +class EventSender implements IEventSender { sender: object; - listeners: Array<(a, b) => void>; + listeners: Array<(a: object, b: T) => void>; constructor(sender: object) { this.sender = sender; this.listeners = []; } - attach(listener: (a, b) => void): void { + attach(listener: (a: object, b: T) => void): void { this.listeners.push(listener); } - notify(args: object): void { + notify(args: T): void { this.listeners.forEach((listener) => { listener(this.sender, args); }); diff --git a/frontend/mvc/utils/IEventSender.ts b/frontend/mvc/utils/IEventSender.ts index 41127cf..088a716 100644 --- a/frontend/mvc/utils/IEventSender.ts +++ b/frontend/mvc/utils/IEventSender.ts @@ -1,5 +1,5 @@ -interface IEventSender { - attach(listener: (a, b) => void): void; - notify(args: object): void; +interface IEventSender { + attach(listener: (a: object, b: T) => void): void; + notify(args: T): void; } export default IEventSender; diff --git a/frontend/mvc/view/IView.ts b/frontend/mvc/view/IView.ts index c37cb64..fd8964b 100644 --- a/frontend/mvc/view/IView.ts +++ b/frontend/mvc/view/IView.ts @@ -1,16 +1,22 @@ import IEventSender from '../utils/IEventSender'; +type tableCellAddress = { + row: number; + cell:number; +}; + + interface IView { - tableCellChanged: IEventSender; - startEvent: IEventSender; - pauseEvent: IEventSender; - clearEvent: IEventSender; - widthChanged: IEventSender; - heightChanged: IEventSender; - speedChanged: IEventSender; + tableCellChanged: IEventSender; + started: IEventSender; + paused: IEventSender; + cleared: IEventSender; + widthChanged: IEventSender; + heightChanged: IEventSender; + speedChanged: IEventSender; setStatus(running: boolean): void; initTable(matrix: boolean[][]): void; changeTable(matrix: boolean[][]): void; } -export default IView; +export { IView, tableCellAddress }; diff --git a/frontend/mvc/view/View.ts b/frontend/mvc/view/View.ts index 12e39eb..16d7061 100644 --- a/frontend/mvc/view/View.ts +++ b/frontend/mvc/view/View.ts @@ -1,5 +1,5 @@ import EventSender from '../utils/EventSender'; -import IView from './IView'; +import { IView, tableCellAddress } from './IView'; const CLASS_CEIL = 'game__ceil'; const CLASS_CEIL_LIVE = 'game__ceil_live'; @@ -15,13 +15,13 @@ class View implements IView{ $sliderHeight: JQuery; $status: JQuery; - tableCellChanged: EventSender; - startEvent: EventSender; - pauseEvent: EventSender; - clearEvent: EventSender; - widthChanged: EventSender; - heightChanged: EventSender; - speedChanged: EventSender; + tableCellChanged: EventSender; + started: EventSender; + paused: EventSender; + cleared: EventSender; + widthChanged: EventSender; + heightChanged: EventSender; + speedChanged: EventSender; constructor() { this.initDOMElements(); this.initEvents(); @@ -39,13 +39,13 @@ class View implements IView{ this.$status = this.$controls.find('.js-game__status'); } initEvents(): void { - this.tableCellChanged = new EventSender(this); - this.startEvent = new EventSender(this); - this.pauseEvent = new EventSender(this); - this.clearEvent = new EventSender(this); - this.widthChanged = new EventSender(this); - this.heightChanged = new EventSender(this); - this.speedChanged = new EventSender(this); + this.tableCellChanged = new EventSender(this); + this.started = new EventSender(this); + this.paused = new EventSender(this); + this.cleared = new EventSender(this); + this.widthChanged = new EventSender(this); + this.heightChanged = new EventSender(this); + this.speedChanged = new EventSender(this); } initHandlers(): void { this.$table.on('click.view', 'td', ({ target }) => { @@ -54,25 +54,25 @@ class View implements IView{ this.tableCellChanged.notify({ row, cell }); }); this.$buttonStart.on('click.view', () => { - this.startEvent.notify({}); + this.started.notify(null); }); this.$buttonPause.on('click.view', () => { - this.pauseEvent.notify({}); + this.paused.notify(null); }); this.$buttonClear.on('click.view', () => { - this.clearEvent.notify({}); + this.cleared.notify(null); }); this.$sliderSpeed.on('change.view', ({ target }) => { const value: number = Number($(target).val()); - this.speedChanged.notify({ value }); + this.speedChanged.notify(value); }); this.$sliderWidth.on('change.view', ({ target }) => { const value: number = Number($(target).val()); - this.widthChanged.notify({ value }); + this.widthChanged.notify(value); }); this.$sliderHeight.on('change.view', ({ target }) => { const value: number = Number($(target).val()); - this.heightChanged.notify({ value }); + this.heightChanged.notify(value); }); } setButtons(running: boolean): void { diff --git a/frontend/scripts/convertRemToPixels.js b/frontend/scripts/convertRemToPixels.js deleted file mode 100644 index c3d9325..0000000 --- a/frontend/scripts/convertRemToPixels.js +++ /dev/null @@ -1,4 +0,0 @@ -const convertRemToPixels = function convertRemToPixels(rem) { - return rem * parseFloat(getComputedStyle(document.documentElement).fontSize); -}; -export default convertRemToPixels; diff --git a/frontend/scripts/convertRemToPixels.ts b/frontend/scripts/convertRemToPixels.ts new file mode 100644 index 0000000..d1c641c --- /dev/null +++ b/frontend/scripts/convertRemToPixels.ts @@ -0,0 +1,3 @@ +const convertRemToPixels = (rem: number): number => + rem * parseFloat(getComputedStyle(document.documentElement).fontSize); +export default convertRemToPixels;