Converting HTML Element Builds to JSO style builder with inheritances
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
103
src/HTMLBuilder.ts
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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",
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import {
|
||||
CustomButtonElement,
|
||||
CustomDivElement,
|
||||
CustomImgElement,
|
||||
CustomSpanElement
|
||||
} from "./CustomHTMLElement";
|
||||
import {ELEMENT_ButtonContainer} from "./const";
|
||||
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
|
||||
|
||||
@@ -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() : () => {},
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import {CustomDivElement} from "./CustomHTMLElement";
|
||||
|
||||
export default function createChatSettingsSeparator() {
|
||||
return new CustomDivElement('twitch-note-settings-separator');
|
||||
}
|
||||
@@ -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 { 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(() => {
|
||||
},
|
||||
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 title = new CustomSpanElement('twitch-note-title', username);
|
||||
const content = new CustomDivElement('twitch-note-content', NoteStorage.getNote(username));
|
||||
content.addAttribute('contentEditable', 'true');
|
||||
const containerElement = new HTMLBuilder(container);
|
||||
|
||||
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);
|
||||
document.body.appendChild(containerElement.getElement());
|
||||
NoteContainers.addContainer(username, containerElement);
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
14
src/types.ts
14
src/types.ts
@@ -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,
|
||||
}
|
||||
Reference in New Issue
Block a user