add observer to formula and table
This commit is contained in:
parent
3870d7dfd0
commit
c74c0490c1
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 `
|
||||
<div class="info">fx</div>
|
||||
<div class="input" contenteditable spellcheck="false"></div>
|
||||
<div id="formula-input" class="input" contenteditable spellcheck="false"></div>
|
||||
`;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 `
|
||||
<input type="text" class="input" value="Новая таблица">
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
28
src/core/Emitter.ts
Normal file
28
src/core/Emitter.ts
Normal file
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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('');
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user