diff --git a/src/components/excel/Excel.ts b/src/components/excel/Excel.ts
index e7761f8..8772e79 100644
--- a/src/components/excel/Excel.ts
+++ b/src/components/excel/Excel.ts
@@ -1,4 +1,6 @@
import { $, Dom } from '../../core/dom';
+import { Emitter } from '../../core/Emitter';
+import { ExcelComponent } from '../../core/ExcelComponent';
interface ExcelOptionsType {
components: any[]
@@ -7,10 +9,12 @@ interface ExcelOptionsType {
export class Excel {
$el: HTMLElement | Dom;
components: any[];
+ emitter: Emitter;
constructor(selector: string, options: ExcelOptionsType) {
this.$el = $(selector);
this.components = options.components;
+ this.emitter = new Emitter();
console.log(`Created new Excel class in ${selector} with options: ${options}`);
}
@@ -18,9 +22,13 @@ export class Excel {
getRoot() {
const $root = $.create('div', 'excel');
+ const componentOptions = {
+ emitter: this.emitter,
+ };
+
this.components = this.components.map(Component => {
const $el = $.create('div', Component.className);
- const component: any = new Component($el);
+ const component: ExcelComponent = new Component($el, componentOptions);
$el.html(component.toHTML());
$root.append($el.$el);
@@ -35,4 +43,8 @@ export class Excel {
this.$el.append(this.getRoot());
this.components.forEach(component => component.init());
}
+
+ destroy() {
+ this.components.forEach(component => component.destroy());
+ }
}
diff --git a/src/components/formula/Formula.ts b/src/components/formula/Formula.ts
index eb224a7..b542119 100644
--- a/src/components/formula/Formula.ts
+++ b/src/components/formula/Formula.ts
@@ -1,28 +1,51 @@
-import { DomClass } from '../../core/dom';
+import { Dom, DomClass } from '../../core/dom';
import { ExcelComponent } from '../../core/ExcelComponent';
export class Formula extends ExcelComponent {
static className = 'excel__formula';
- constructor($root: DomClass) {
+ private formulaInput: Dom;
+
+ constructor($root: DomClass, options: any) {
super($root, {
- listeners: ['input', 'click'],
+ listeners: ['input', 'keydown'],
name: 'Formula',
+ ...options,
});
}
toHTML(): string {
return `
fx
-
+
`;
}
- onInput(event: Event) {
- console.log('Formula on input listeners', event);
+ init() {
+ super.init();
+
+ this.formulaInput = this.$root.find('#formula-input');
+
+ this.$on('table:input', text => {
+ this.formulaInput.text = text;
+ });
+ this.$on('table:select-cell', text => {
+ this.formulaInput.text = text;
+ });
}
- onClick() {
+ onInput(event: Event) {
+ const text = (event.target as HTMLElement).textContent.trim();
+ this.$emit('formula:input', text);
+ }
+ onKeydown(event: KeyboardEvent) {
+ const preventedKeys = ['Enter', 'Tab'];
+
+ if (preventedKeys.includes(event.key)) event.preventDefault();
+
+ if (event.key === 'Enter') {
+ this.$emit('formula:enter-press');
+ }
}
}
diff --git a/src/components/header/Header.ts b/src/components/header/Header.ts
index e420c30..8632005 100644
--- a/src/components/header/Header.ts
+++ b/src/components/header/Header.ts
@@ -1,8 +1,16 @@
+import { DomClass } from '../../core/dom';
import { ExcelComponent } from '../../core/ExcelComponent';
export class Header extends ExcelComponent {
static className = 'excel__header';
+ constructor($root: DomClass, options: any) {
+ super($root, {
+ name: 'Header',
+ ...options,
+ });
+ }
+
toHTML(): string {
return `
diff --git a/src/components/table/Table.ts b/src/components/table/Table.ts
index 6e68463..9a434c0 100644
--- a/src/components/table/Table.ts
+++ b/src/components/table/Table.ts
@@ -1,3 +1,4 @@
+import { DomClass } from '../../core/dom';
import { ExcelComponent } from '../../core/ExcelComponent';
import { selectHandler } from './handlers/table.select.handler';
import { TableSelection } from './TableSelection';
@@ -9,10 +10,11 @@ export class Table extends ExcelComponent {
private selection: TableSelection;
- constructor($root: any) {
+ constructor($root: DomClass, options: any) {
super($root, {
name: 'Table',
- listeners: ['mousedown', 'keydown'],
+ listeners: ['mousedown', 'keydown', 'input'],
+ ...options,
});
}
@@ -29,14 +31,33 @@ export class Table extends ExcelComponent {
const $cell = this.$root.find('[data-id="0:0"]');
this.selection.select($cell);
+
+ this.$emit('table:select-cell', $cell.text);
+
+ this.$on('formula:input', (data) => {
+ this.selection.current.text = data;
+ });
+
+ this.$on('formula:enter-press', () => {
+ this.selection.current.focus();
+ });
+ }
+
+ emitSelectCallback() {
+ this.$emit('table:select-cell', this.selection.current.text);
}
onMousedown(event: MouseEvent) {
- selectHandler(event, this.selection);
+ selectHandler(event, this.selection, this.emitSelectCallback.bind(this));
resizeHandler(this.$root, event);
}
onKeydown(event: KeyboardEvent) {
- selectHandler(event, this.selection);
+ selectHandler(event, this.selection, this.emitSelectCallback.bind(this));
+ }
+
+ onInput(event: InputEvent) {
+ const inputText = (event.target as HTMLElement).textContent.trim();
+ this.$emit('table:input', inputText);
}
}
diff --git a/src/components/table/handlers/table.select.handler.ts b/src/components/table/handlers/table.select.handler.ts
index 6bdeb71..c54d99b 100644
--- a/src/components/table/handlers/table.select.handler.ts
+++ b/src/components/table/handlers/table.select.handler.ts
@@ -2,7 +2,7 @@ import { $ } from '../../../core/dom';
import { getParamsFromCellId, isCell } from '../table.functions';
import { TableSelection } from '../TableSelection';
-export function selectHandler(event: MouseEvent | KeyboardEvent, selection: TableSelection) {
+export function selectHandler(event: MouseEvent | KeyboardEvent, selection: TableSelection, callback?: () => void) {
switch (event.type) {
case 'mousedown': {
onMouseDownHandler();
@@ -15,6 +15,8 @@ export function selectHandler(event: MouseEvent | KeyboardEvent, selection: Tabl
default: break;
}
+ callback();
+
function onMouseDownHandler() {
if (isCell(event)) {
if (event.shiftKey) selection.selectGroup($(event.target as HTMLElement));
diff --git a/src/components/toolbar/Toolbar.ts b/src/components/toolbar/Toolbar.ts
index a60f7c4..f4350d2 100644
--- a/src/components/toolbar/Toolbar.ts
+++ b/src/components/toolbar/Toolbar.ts
@@ -1,13 +1,14 @@
-import { Dom } from '../../core/dom';
+import { DomClass } from '../../core/dom';
import { ExcelComponent } from '../../core/ExcelComponent';
export class Toolbar extends ExcelComponent {
static className = 'excel__toolbar';
- constructor($root: Dom) {
+ constructor($root: DomClass, options: any) {
super($root, {
name: 'Toolbar',
listeners: ['click'],
+ ...options,
});
}
diff --git a/src/core/Emitter.ts b/src/core/Emitter.ts
new file mode 100644
index 0000000..e38338f
--- /dev/null
+++ b/src/core/Emitter.ts
@@ -0,0 +1,28 @@
+export class Emitter {
+ private listeners: {
+ [k: string]: Array<(args?: any) => any>
+ };
+
+ constructor() {
+ this.listeners = {};
+ }
+
+ emit(eventName: string, ...args: any[]) {
+ if (!Array.isArray(this.listeners[eventName])) return false;
+
+ this.listeners[eventName].forEach(listener => {
+ listener(args);
+ });
+
+ return true;
+ }
+
+ subscribe(eventName: string, callback: (args?: any) => any) {
+ this.listeners[eventName] = this.listeners[eventName] || [];
+ this.listeners[eventName].push(callback);
+
+ return () => {
+ this.listeners[eventName] = this.listeners[eventName].filter(listener => listener !== callback);
+ };
+ }
+}
diff --git a/src/core/ExcelComponent.ts b/src/core/ExcelComponent.ts
index bf56c46..c47552e 100644
--- a/src/core/ExcelComponent.ts
+++ b/src/core/ExcelComponent.ts
@@ -1,4 +1,5 @@
import { DomListener } from './DomListener';
+import { Emitter } from './Emitter';
interface ExcelComponentClass {
toHTML: () => string;
@@ -8,15 +9,19 @@ interface ExcelComponentClass {
type OptionsType = {
listeners?: string[];
name: string;
+ emitter?: Emitter;
};
export class ExcelComponent extends DomListener implements ExcelComponentClass {
name: string;
+ emitter: Emitter;
+ private unsubscribers: ((args?: any) => any)[];
constructor($root: any, options: OptionsType) {
super($root, options?.listeners);
this.name = options?.name;
-
+ this.emitter = options?.emitter;
+ this.unsubscribers = [];
this.prepare();
}
@@ -28,11 +33,21 @@ export class ExcelComponent extends DomListener implements ExcelComponentClass {
return '';
}
+ $emit(event: string, ...args: any): void {
+ this.emitter.emit(event, ...args);
+ }
+
+ $on(event: string, callback: (args: any) => any) {
+ const unsub = this.emitter.subscribe(event, callback);
+ this.unsubscribers.push(unsub);
+ }
+
init() {
this.initDOMListeners();
}
destroy() {
this.removeDOMListeners();
+ this.unsubscribers.forEach(unsub => unsub());
}
}
diff --git a/src/core/dom.ts b/src/core/dom.ts
index 845e202..e046d1d 100644
--- a/src/core/dom.ts
+++ b/src/core/dom.ts
@@ -24,6 +24,14 @@ export class Dom implements DomClass {
return this.$el.outerHTML.trim();
}
+ set text(text: string) {
+ this.$el.textContent = text;
+ }
+
+ get text() {
+ return this.$el.textContent;
+ }
+
clear() {
this.html('');