From 5db61da32b0460fb0f2e8c9946f23ce95d616999 Mon Sep 17 00:00:00 2001 From: shmyga Date: Mon, 7 Sep 2026 18:09:49 +0300 Subject: [PATCH] refactor(static): split schedule and weather to modules --- static/src/app/base/storage.ts | 41 ++++++++++++ .../{schedule.ts => schedule/component.ts} | 64 ++----------------- static/src/app/schedule/index.ts | 32 ++++++++++ static/src/app/schedule/model.ts | 5 ++ .../app/{weather.ts => weather/component.ts} | 61 +----------------- static/src/app/weather/index.ts | 29 +++++++++ static/src/app/weather/model.ts | 9 +++ 7 files changed, 124 insertions(+), 117 deletions(-) create mode 100644 static/src/app/base/storage.ts rename static/src/app/{schedule.ts => schedule/component.ts} (57%) create mode 100644 static/src/app/schedule/index.ts create mode 100644 static/src/app/schedule/model.ts rename static/src/app/{weather.ts => weather/component.ts} (52%) create mode 100644 static/src/app/weather/index.ts create mode 100644 static/src/app/weather/model.ts diff --git a/static/src/app/base/storage.ts b/static/src/app/base/storage.ts new file mode 100644 index 0000000..bcc9581 --- /dev/null +++ b/static/src/app/base/storage.ts @@ -0,0 +1,41 @@ +export class DataStorage { + constructor(private storageKey: string) {} + + private readValues(): T[] { + const objects = JSON.parse(window.localStorage.getItem(this.storageKey) || "[]"); + if (!Array.isArray(objects)) { + return Object.values(objects); + } + return objects; + } + + private writeValues(values: T[]) { + window.localStorage.setItem(this.storageKey, JSON.stringify(values)); + } + + getAll(): T[] { + return this.readValues(); + } + + add(value: T) { + const values = this.readValues(); + for (const v of values) { + if (v.id == value.id) { + return; + } + } + values.push(value); + this.writeValues(values); + } + + remove(id: string) { + const values = this.readValues(); + for (let i = 0; i < values.length; i++) { + if (values[i].id == id) { + values.splice(i, 1); + this.writeValues(values); + return; + } + } + } +} diff --git a/static/src/app/schedule.ts b/static/src/app/schedule/component.ts similarity index 57% rename from static/src/app/schedule.ts rename to static/src/app/schedule/component.ts index 926addf..769d20e 100644 --- a/static/src/app/schedule.ts +++ b/static/src/app/schedule/component.ts @@ -1,50 +1,6 @@ -export interface Channel { - id: string; - name: string; - provider: string; -} +import { Channel } from "./model"; -export class ScheduleChannelStorage { - private storageKey: string = "schedule:channels"; - - getAll(): Channel[] { - const objects = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - return Object.values(objects); - } - - add(object: Channel) { - const objects = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - objects[object.id] = object; - window.localStorage.setItem(this.storageKey, JSON.stringify(objects)); - } - - remove(id: string) { - const objects = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - delete objects[id]; - window.localStorage.setItem(this.storageKey, JSON.stringify(objects)); - } -} - -export class ScheduleChannelManager { - loadChannels(selector: string) { - const channels = window.scheduleChannelStorage.getAll(); - const container = document.querySelector(selector); - if (container) { - container.innerHTML = ""; - for (const channel of channels) { - const element = new ScheduleChannelElement(); - element.setAttribute("channel", JSON.stringify(channel)); - element.setAttribute("removable", ""); - container.appendChild(element); - } - const groupElement = new ScheduleChannelGroupElement(); - groupElement.setAttribute("channels", JSON.stringify(channels)); - container.append(groupElement); - } - } -} - -class ScheduleChannelElement extends HTMLElement { +export class ScheduleChannelElement extends HTMLElement { static observedAttributes = ["channel", "removable"]; channel: Channel | null = null; @@ -100,9 +56,7 @@ class ScheduleChannelElement extends HTMLElement { } } -customElements.define("schedule-channel", ScheduleChannelElement); - -class ScheduleChannelGroupElement extends HTMLElement { +export class ScheduleChannelGroupElement extends HTMLElement { static observedAttributes = ["channels"]; channels: Channel[] | null = null; @@ -124,14 +78,6 @@ class ScheduleChannelGroupElement extends HTMLElement { this.classList = "list-group-item list-group-item-action"; } } + +customElements.define("schedule-channel", ScheduleChannelElement); customElements.define("schedule-channel-group", ScheduleChannelGroupElement); - -declare global { - interface Window { - scheduleChannelStorage: ScheduleChannelStorage; - scheduleChannelManager: ScheduleChannelManager; - } -} - -window.scheduleChannelStorage = new ScheduleChannelStorage(); -window.scheduleChannelManager = new ScheduleChannelManager(); diff --git a/static/src/app/schedule/index.ts b/static/src/app/schedule/index.ts new file mode 100644 index 0000000..801ba18 --- /dev/null +++ b/static/src/app/schedule/index.ts @@ -0,0 +1,32 @@ +import { DataStorage } from "../base/storage"; +import { ScheduleChannelElement, ScheduleChannelGroupElement } from "./component"; +import { Channel } from "./model"; + +export class ScheduleChannelManager { + loadChannels(selector: string) { + const channels = window.scheduleChannelStorage.getAll(); + const container = document.querySelector(selector); + if (container) { + container.innerHTML = ""; + for (const channel of channels) { + const element = new ScheduleChannelElement(); + element.setAttribute("channel", JSON.stringify(channel)); + element.setAttribute("removable", ""); + container.appendChild(element); + } + const groupElement = new ScheduleChannelGroupElement(); + groupElement.setAttribute("channels", JSON.stringify(channels)); + container.append(groupElement); + } + } +} + +declare global { + interface Window { + scheduleChannelStorage: DataStorage; + scheduleChannelManager: ScheduleChannelManager; + } +} + +window.scheduleChannelStorage = new DataStorage("schedule:channels"); +window.scheduleChannelManager = new ScheduleChannelManager(); diff --git a/static/src/app/schedule/model.ts b/static/src/app/schedule/model.ts new file mode 100644 index 0000000..b902b96 --- /dev/null +++ b/static/src/app/schedule/model.ts @@ -0,0 +1,5 @@ +export interface Channel { + id: string; + name: string; + provider: string; +} diff --git a/static/src/app/weather.ts b/static/src/app/weather/component.ts similarity index 52% rename from static/src/app/weather.ts rename to static/src/app/weather/component.ts index c527b4e..491aedf 100644 --- a/static/src/app/weather.ts +++ b/static/src/app/weather/component.ts @@ -1,51 +1,6 @@ -export interface Location { - id: string; - name: string; - provider: string; - country_code: string; - country?: string; - district?: string; - subdistrict?: string; -} +import { Location } from "./model"; -export class WeatherLocationStorage { - private storageKey: string = "weather:locations"; - - getAll(): Location[] { - const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - return Object.values(locations); - } - - add(location: Location) { - const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - locations[location.id] = location; - window.localStorage.setItem(this.storageKey, JSON.stringify(locations)); - } - - remove(id: string) { - const locations = JSON.parse(window.localStorage.getItem(this.storageKey) || "{}"); - delete locations[id]; - window.localStorage.setItem(this.storageKey, JSON.stringify(locations)); - } -} - -export class WeatherLocationManager { - loadLocations(selector: string) { - const locations = window.weatherLocationStorage.getAll(); - const container = document.querySelector(selector); - if (container) { - container.innerHTML = ""; - for (const location of locations) { - const element = new WeatherLocationElement(); - element.setAttribute("location", JSON.stringify(location)); - element.setAttribute("removable", ""); - container.appendChild(element); - } - } - } -} - -class WeatherLocationElement extends HTMLElement { +export class WeatherLocationElement extends HTMLElement { static observedAttributes = ["location", "removable"]; location: Location | null = null; @@ -75,7 +30,7 @@ class WeatherLocationElement extends HTMLElement { `; - this.classList = 'list-group-item list-group-item-action'; + this.classList = "list-group-item list-group-item-action"; this.addEventListener("click", this.handleClick); if (this.hasAttribute("removable")) { this.querySelector("[data-remove]")?.addEventListener("click", this.handleRemoveClick); @@ -106,13 +61,3 @@ class WeatherLocationElement extends HTMLElement { } customElements.define("weather-location", WeatherLocationElement); - -declare global { - interface Window { - weatherLocationStorage: WeatherLocationStorage; - weatherLocationManager: WeatherLocationManager; - } -} - -window.weatherLocationStorage = new WeatherLocationStorage(); -window.weatherLocationManager = new WeatherLocationManager(); diff --git a/static/src/app/weather/index.ts b/static/src/app/weather/index.ts new file mode 100644 index 0000000..5ff05e8 --- /dev/null +++ b/static/src/app/weather/index.ts @@ -0,0 +1,29 @@ +import { DataStorage } from "../base/storage"; +import { WeatherLocationElement } from "./component"; +import { Location } from "./model"; + +export class WeatherLocationManager { + loadLocations(selector: string) { + const locations = window.weatherLocationStorage.getAll(); + const container = document.querySelector(selector); + if (container) { + container.innerHTML = ""; + for (const location of locations) { + const element = new WeatherLocationElement(); + element.setAttribute("location", JSON.stringify(location)); + element.setAttribute("removable", ""); + container.appendChild(element); + } + } + } +} + +declare global { + interface Window { + weatherLocationStorage: DataStorage; + weatherLocationManager: WeatherLocationManager; + } +} + +window.weatherLocationStorage = new DataStorage("weather:locations"); +window.weatherLocationManager = new WeatherLocationManager(); diff --git a/static/src/app/weather/model.ts b/static/src/app/weather/model.ts new file mode 100644 index 0000000..e785919 --- /dev/null +++ b/static/src/app/weather/model.ts @@ -0,0 +1,9 @@ +export interface Location { + id: string; + name: string; + provider: string; + country_code: string; + country?: string; + district?: string; + subdistrict?: string; +}