Converting HTML Element Builds to JSO style builder with inheritances

This commit is contained in:
2022-09-15 23:49:33 +03:00
parent b33bf7fece
commit 12fc946c9b
12 changed files with 344 additions and 138 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
node_modules
.idea
.vscode
twitchNotes*.zip

File diff suppressed because one or more lines are too long

103
src/HTMLBuilder.ts Normal file
View File

@@ -0,0 +1,103 @@
import {HTMLBuilderBlock} from "./types";
export default class HTMLBuilder {
element: HTMLElement;
constructor(data: HTMLBuilderBlock) {
this.element = document.createElement(data.element);
this.setId(data.id ?? data.element + '-custom-element-' + Math.floor(Math.random() * 1000000));
if (data.class) this.setClasses(data.class);
if (data.attributes) this.setAttributes(data.attributes);
if (data.style) this.setStyles(data.style);
if (data.mouseClickEvent) this.setMouseClickListener(data.mouseClickEvent);
if (data.mouseMoveEvent) this.setMouseClickListener(data.mouseMoveEvent);
if (data.mouseDownEvent) this.setMouseClickListener(data.mouseDownEvent);
if (data.mouseUpEvent) this.setMouseClickListener(data.mouseUpEvent);
if (data.keyUpEvent) this.setKeyUpListener(data.keyUpEvent);
if (data.content) this.setContent(data.content);
}
setId(id: string) {
this.element.id = id;
}
setClasses(classes: string | string[]) {
if (typeof classes === 'string') {
this.addClass(classes);
} else {
for(let className of classes) {
this.addClass(className);
}
}
}
addClass(className: string) {
this.element.classList.add(className);
}
setAttributes(attributes: {[key: string]: string}) {
for(let key in attributes) {
if (!attributes[key]) continue;
this.addAttribute(key, attributes[key]);
}
}
addAttribute(key: string, value: string) {
this.element.setAttribute(key, value);
}
setStyles(style: Partial<CSSStyleDeclaration>) {
for (const key in style) {
this.addStyle(key, style[key] || '');
}
}
addStyle(key: string, value: string) {
this.element.style.setProperty(key, value);
}
setMouseClickListener(cb: Function) {
this.element.addEventListener('click', () => cb());
}
setContent(content: (HTMLBuilderBlock|string)[]) {
for (let block of content) {
this.addContent(block);
}
}
addContent(content: HTMLBuilderBlock|string) {
if (typeof content === 'string') {
this.element.innerHTML += content;
} else {
const el = new HTMLBuilder(content);
this.element.appendChild(el.element)
}
}
setMouseMoveListener(cb: Function) {
this.element.addEventListener('mousemove', () => cb());
}
setMouseDownListener(cb: Function) {
this.element.addEventListener('mousedown', () => cb());
}
setMouseUpListener(cb: Function) {
this.element.addEventListener('mouseup', () => cb());
}
setKeyUpListener(cb: Function) {
this.element.addEventListener('keyup', () => cb(this.element.innerHTML));
}
getElement() {
return this.element;
}
remove() {
this.element.remove();
}
}

View File

@@ -32,7 +32,7 @@ export default class Mouse {
if (NoteContainers.activeContainer) {
const dx = Mouse.mousePosition.x - Mouse.lastMousePosition.x;
const dy = Mouse.mousePosition.y - Mouse.lastMousePosition.y;
NoteContainers.containers[NoteContainers.activeContainer].setStyle({
NoteContainers.containers[NoteContainers.activeContainer].setStyles({
top: parseInt(NoteContainers.containers[NoteContainers.activeContainer].getElement().style.top) + dy + "px",
left: parseInt(NoteContainers.containers[NoteContainers.activeContainer].getElement().style.left) + dx + "px",
});

View File

@@ -1,11 +1,11 @@
import {CustomHTMLElement} from "./CustomHTMLElement";
import HTMLBuilder from "./HTMLBuilder";
const containers: {[key: string]: CustomHTMLElement} = {};
const containers: {[key: string]: HTMLBuilder} = {};
export default {
activeContainer: '',
containers,
addContainer(username: string, container: CustomHTMLElement) {
addContainer(username: string, container: HTMLBuilder) {
if (this.containers[username]) return;
this.containers[username] = container;
},

View File

@@ -1,12 +1,7 @@
import {
CustomButtonElement,
CustomDivElement,
CustomImgElement,
CustomSpanElement
} from "./CustomHTMLElement";
import { ELEMENT_ButtonContainer } from "./const";
import toggleSettingsList from "./toggleSettingsList";
import openTwitchNote from "./openTwitchNote";
import HTMLBuilder from "./HTMLBuilder";
export default class TwitchNote {
@@ -60,26 +55,41 @@ export default class TwitchNote {
return;
}
const container1 = new CustomDivElement();
container1.setStyle({marginLeft: "0.5rem !important"});
const container2 = new CustomDivElement();
container1.setStyle({display: "inline-flex !important"});
const settingsButton = new CustomButtonElement('twitch-notes-settings-button', 'Notes');
settingsButton.setClickListener(() => {
toggleSettingsList();
const btn = new HTMLBuilder({
element: 'div',
style: {
marginLeft: "0.5rem !important"
},
content: [
{
element: 'div',
style: {
display: "inline-flex !important"
},
content: [
{
element: 'button',
class: [
'twitch-notes-settings-button',
'twitch-notes-settings-button__outline'
],
content: [
'Notes'
],
mouseClickEvent: () => toggleSettingsList(),
}
]
}
]
});
container2.appendCustomChild(settingsButton);
container1.appendCustomChild(container2);
if (buttonContainer.lastChild) {
buttonContainer.lastChild.insertBefore(
container1.getElement(),
btn.getElement(),
buttonContainer.lastChild.lastChild
);
} else {
buttonContainer.appendChild(container1.getElement());
buttonContainer.appendChild(btn.getElement());
}
}
@@ -96,15 +106,27 @@ export default class TwitchNote {
if (username) {
let noteButton = usernameContainer.querySelector(".twitch-note");
if (!noteButton) {
const twitchNote = new CustomSpanElement('twitch-note');
twitchNote.setStyle({cursor: 'pointer'});
twitchNote.setClickListener(() => {
openTwitchNote(username);
const twitchNote = new HTMLBuilder({
element: 'span',
class: 'twitch-note',
style: {
cursor: 'pointer',
},
mouseClickEvent: () => openTwitchNote(username),
content: [
{
element: 'img',
style: {
height: '18px',
paddingRight: '4px'
},
attributes: {
src: 'https://cdn.rdarius.lt/icons/32-id-card.png'
}
}
]
});
const img = new CustomImgElement();
img.setStyle({height: '18px', paddingRight: '4px'});
img.addAttribute('src', 'https://cdn.rdarius.lt/icons/32-id-card.png');
twitchNote.appendCustomChild(img);
usernameContainer.insertBefore(
twitchNote.getElement(),
usernameContainer.firstChild

View File

@@ -1,13 +1,31 @@
import {CustomButtonElement, CustomDivElement} from "./CustomHTMLElement";
import {HTMLBuilderBlock} from "./types";
export default function createChatSettingsLine(text: string) {
const element = new CustomDivElement('twitch-notes-settings-option-line');
const button = new CustomButtonElement('twitch-notes-settings-option-line-button');
const buttonContainer = new CustomDivElement('twitch-notes-settings-option-line-button-container');
const buttonContainerContent = new CustomDivElement('twitch-notes-settings-option-line-button-container-content', text);
export default function createChatSettingsLine(text: string, cb?: Function): HTMLBuilderBlock {
buttonContainer.appendCustomChild(buttonContainerContent);
button.appendCustomChild(buttonContainer);
element.appendCustomChild(button);
return element;
return {
element: 'div',
class: 'twitch-notes-settings-option-line',
content: [
{
element: 'button',
class: 'twitch-notes-settings-option-line-button',
content: [
{
element: 'div',
class: 'twitch-notes-settings-option-line-button-container',
content: [
{
element: 'div',
class: 'twitch-notes-settings-option-line-button-container-content',
content: [
text
]
}
]
}
]
}
],
mouseClickEvent: () => cb ? cb() : () => {},
};
}

View File

@@ -1,5 +0,0 @@
import {CustomDivElement} from "./CustomHTMLElement";
export default function createChatSettingsSeparator() {
return new CustomDivElement('twitch-note-settings-separator');
}

View File

@@ -1,43 +1,67 @@
import NoteContainers from "./NoteContainers";
import {CustomDivElement, CustomSpanElement} from "./CustomHTMLElement";
import Mouse from "./Mouse";
import NoteStorage from "./NoteStorage";
import { getCloseButtonSVG } from "./HTMLTemplates";
import {HTMLBuilderBlock} from "./types";
import HTMLBuilder from "./HTMLBuilder";
export default function openTwitchNote(username: string) {
if (NoteContainers.containers[username]) return;
const container = new CustomDivElement('twitch-note-container');
container.setStyle({
let noteContent = NoteStorage.getNote(username);
const container: HTMLBuilderBlock = {
element: 'div',
class: 'twitch-note-container',
style: {
left: Mouse.mousePosition.x + 'px',
top: Mouse.mousePosition.y + 10 + 'px'
});
const header = new CustomDivElement('twitch-note-header');
header.setMouseDownListener(() => {
},
content: [
{
element: 'div',
class: 'twitch-note-header',
mouseDownEvent: () => {
NoteContainers.activeContainer = username;
Mouse.isMouseDown = true;
});
const closeButton = new CustomSpanElement('twitch-note-close-button', getCloseButtonSVG());
closeButton.setClickListener(() => {
NoteContainers.removeContainer(username);
});
const title = new CustomSpanElement('twitch-note-title', username);
const content = new CustomDivElement('twitch-note-content', NoteStorage.getNote(username));
content.addAttribute('contentEditable', 'true');
const saveButton = new CustomDivElement('twitch-note-save-button', 'SAVE');
saveButton.setClickListener(() => {
NoteStorage.saveNote(username, content.getElement().innerHTML);
NoteContainers.removeContainer(username);
});
header.appendCustomChild(closeButton);
header.appendCustomChild(title);
container.appendCustomChild(header);
container.appendCustomChild(content);
container.appendCustomChild(saveButton);
document.body.appendChild(container.getElement());
NoteContainers.addContainer(username, container);
},
content: [
{
element: 'span',
class: 'twitch-note-close-button',
content: [getCloseButtonSVG()],
mouseClickEvent: () => NoteContainers.removeContainer(username),
},
{
element: 'span',
class: 'twitch-note-title',
content: [username],
}
]
},
{
element: 'div',
class: 'twitch-note-content',
content: [NoteStorage.getNote(username)],
attributes: {
contentEditable: 'true'
},
keyUpEvent: (newContent: string) => {
noteContent = newContent;
}
},
{
element: 'div',
class: 'twitch-note-save-button',
content: ['SAVE'],
mouseClickEvent: () => {
NoteStorage.saveNote(username, noteContent);
NoteContainers.removeContainer(username);
}
}
]
};
const containerElement = new HTMLBuilder(container);
document.body.appendChild(containerElement.getElement());
NoteContainers.addContainer(username, containerElement);
}

View File

@@ -76,7 +76,7 @@
.twitch-notes-settings-button {
z-index: var(--z-index-default) !important;
position: relative !important;
background-color: transparent;
background-color: var(--color-background-button-primary-default);
color: var(--color-text-button-primary);
text-decoration: none;
cursor: pointer;
@@ -90,11 +90,15 @@
white-space: nowrap;
user-select: none;
font-weight: var(--font-weight-semibold);
border: 2px solid var(--color-text-button-primary);
border-radius: var(--border-radius-medium);
font-size: var(--button-text-default);
height: var(--button-size-default);
padding: 0 var(--button-padding-x);
&__outline {
background: transparent;
border: 2px solid var(--color-text-button-primary);
}
}
.twitch-notes-settings-container {

View File

@@ -1,68 +1,92 @@
import {CustomButtonElement, CustomDivElement, CustomPElement} from "./CustomHTMLElement";
import NoteStorage from "./NoteStorage";
import {
getCloseButtonSVG
} from "./HTMLTemplates";
import { getCloseButtonSVG } from "./HTMLTemplates";
import openAllNoteListWindow from "./openAllNoteListWindow";
import openClearDataWindow from "./openClearDataWindow";
import openImportNotesWindow from "./openImprtNotesWindow";
import createChatSettingsLine from "./chatSettingsLine";
import createChatSettingsSeparator from "./chatSettingsSeparator";
import { HTMLBuilderBlock } from "./types";
import HTMLBuilder from "./HTMLBuilder";
export default function toggleSettingsList() {
const settingsWindow = document.querySelector('.twitch-notes-settings-container') as HTMLElement;
if (!settingsWindow) {
const settingsContainer = new CustomDivElement('twitch-notes-settings-container');
const settingsBalloon = new CustomDivElement('twitch-notes-settings-balloon');
const settingsPopover = new CustomDivElement('twitch-notes-settings-popover');
const settingsHeader = new CustomDivElement('twitch-notes-settings-header');
const settingsHeaderLeftElement = new CustomDivElement('twitch-notes-settings-header-left-element');
const settingsHeaderCenterElement = new CustomDivElement('twitch-notes-settings-header-center-element');
const settingsHeaderCenterElementContent = new CustomPElement('twitch-notes-settings-header-center-element-content','Twitch Notes Settings');
const settingsHeaderRightElement = new CustomDivElement('twitch-notes-settings-header-right-element');
const settingsCloseButton = new CustomButtonElement('twitch-notes-settings-close-button', getCloseButtonSVG());
const settingsScrollableArea = new CustomDivElement('twitch-notes-settings-scrollable-area');
const settingsContent = new CustomDivElement('twitch-notes-settings-content');
const exportNotes = createChatSettingsLine('Export Notes');
const importNotes = createChatSettingsLine('Import Notes');
const clearData = createChatSettingsLine('Clear Data');
const openAllNotes = createChatSettingsLine('View All Notes');
settingsContainer.appendCustomChild(settingsBalloon);
settingsBalloon.appendCustomChild(settingsPopover);
settingsPopover.appendCustomChild(settingsHeader);
settingsHeader.appendCustomChild(settingsHeaderLeftElement);
settingsHeader.appendCustomChild(settingsHeaderCenterElement);
settingsHeaderCenterElement.appendCustomChild(settingsHeaderCenterElementContent);
settingsHeader.appendCustomChild(settingsHeaderRightElement);
settingsHeaderRightElement.appendCustomChild(settingsCloseButton);
settingsPopover.appendCustomChild(settingsScrollableArea);
settingsScrollableArea.appendCustomChild(settingsContent);
settingsContent.appendCustomChild(exportNotes);
settingsContent.appendCustomChild(importNotes);
settingsContent.appendCustomChild(clearData);
settingsContent.appendCustomChild(createChatSettingsSeparator());
settingsContent.appendCustomChild(openAllNotes);
settingsCloseButton.setClickListener(() => toggleSettingsList());
exportNotes.setClickListener(() => {
const settingsContainer: HTMLBuilderBlock = {
element: 'div',
class: 'twitch-notes-settings-container',
content: [{
element: 'div',
class: 'twitch-notes-settings-balloon',
content: [{
element: 'div',
class: 'twitch-notes-settings-popover',
content: [
{
element: 'div',
class: 'twitch-notes-settings-header',
content: [
{
element: 'div',
class: 'twitch-notes-settings-header-left-element',
},
{
element: 'div',
class: 'twitch-notes-settings-header-center-element',
content: [{
element: 'p',
class: 'twitch-notes-settings-header-center-element-content',
content: ['Twitch Notes Settings']
}]
},
{
element: 'div',
class: 'twitch-notes-settings-header-right-element',
content: [{
element: 'button',
class: 'twitch-notes-settings-close-button',
content: [getCloseButtonSVG()],
mouseClickEvent: () => toggleSettingsList(),
}]
}
]
},
{
element: 'div',
class: 'twitch-notes-settings-scrollable-area',
content: [{
element: 'div',
class: 'twitch-notes-settings-content',
content: [
createChatSettingsLine('Export Notes', () => {
NoteStorage.exportNotes();
toggleSettingsList();
});
importNotes.setClickListener(() => {
}),
createChatSettingsLine('Import Notes',() => {
openImportNotesWindow();
toggleSettingsList();
});
clearData.setClickListener(() => {
}),
createChatSettingsLine('Clear Data',() => {
openClearDataWindow();
toggleSettingsList();
});
openAllNotes.setClickListener(() => {
}),
{
element: 'div',
class: 'twitch-note-settings-separator',
},
createChatSettingsLine('View All Notes',() => {
openAllNoteListWindow();
toggleSettingsList();
});
}),
]
}]
}
]
}]
}]
};
document.body.appendChild(settingsContainer.getElement());
const settingsContainerElement = new HTMLBuilder(settingsContainer);
document.body.appendChild(settingsContainerElement.getElement());
return;
} else {
settingsWindow.remove();

View File

@@ -8,3 +8,17 @@ export type CustomHTMLElementConstructor = {
body?: string | HTMLElement,
customBody?: CustomHTMLElement,
}
export type HTMLBuilderBlock = {
element: 'div' | 'span' | 'button' | 'a' | 'p' | 'strong' | 'em' | 'input' | 'img',
id?: string,
class?: string | string[],
style?: Partial<CSSStyleDeclaration>,
attributes?: {[key: string]: string},
content?: (HTMLBuilderBlock | string)[],
mouseClickEvent?: Function,
mouseMoveEvent?: Function,
mouseDownEvent?: Function,
mouseUpEvent?: Function,
keyUpEvent?: Function,
}