forked from MapComplete/MapComplete
Refactoring fullscreenhandling
This commit is contained in:
parent
e1a4c75391
commit
00f610c589
23 changed files with 346 additions and 245 deletions
|
@ -1,22 +1,25 @@
|
|||
import {UIElement} from "../UIElement";
|
||||
|
||||
export default class LazyElement extends UIElement {
|
||||
export default class LazyElement<T extends UIElement> extends UIElement {
|
||||
|
||||
|
||||
private _content: UIElement = undefined;
|
||||
public Activate: (onElement?: (element: T) => void) => void;
|
||||
private _content: T = undefined;
|
||||
private readonly _loadingContent: string;
|
||||
|
||||
public Activate: () => void;
|
||||
private _loadingContent: string;
|
||||
|
||||
constructor(content: (() => UIElement), loadingContent = "Rendering...") {
|
||||
constructor(content: (() => T), loadingContent = "Rendering...") {
|
||||
super();
|
||||
this._loadingContent = loadingContent;
|
||||
this.dumbMode = false;
|
||||
const self = this;
|
||||
this.Activate = () => {
|
||||
this.Activate = (onElement?: (element: T) => void) => {
|
||||
console.log("ACTIVATED")
|
||||
if (this._content === undefined) {
|
||||
self._content = content();
|
||||
}
|
||||
if (onElement) {
|
||||
onElement(self._content)
|
||||
}
|
||||
self.Update();
|
||||
}
|
||||
}
|
||||
|
@ -27,5 +30,7 @@ export default class LazyElement extends UIElement {
|
|||
}
|
||||
return this._content.InnerRender();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import {UIElement} from "../UIElement";
|
||||
import Svg from "../../Svg";
|
||||
import State from "../../State";
|
||||
import Combine from "./Combine";
|
||||
import Ornament from "./Ornament";
|
||||
|
||||
|
@ -8,63 +7,150 @@ import Ornament from "./Ornament";
|
|||
* Wraps some contents into a panel that scrolls the content _under_ the title
|
||||
*/
|
||||
export default class ScrollableFullScreen extends UIElement {
|
||||
private static _isInited = false;
|
||||
private title: UIElement;
|
||||
private content: UIElement;
|
||||
private _component: UIElement;
|
||||
private elementsToRestore: Set<HTMLElement> = new Set<HTMLElement>();
|
||||
|
||||
constructor(title: UIElement, content: UIElement, onClose: (() => void)) {
|
||||
super();
|
||||
this.content = content;
|
||||
this.title = title;
|
||||
if (!ScrollableFullScreen._isInited) {
|
||||
ScrollableFullScreen._isInited = ScrollableFullScreen.PreparePatchesForFullscreen();
|
||||
}
|
||||
if (onClose === undefined) {
|
||||
console.error("ScrollableFullScreen initialized without onClose!")
|
||||
}
|
||||
this.dumbMode = false;
|
||||
const returnToTheMap = Svg.back_svg().onClick(() => {
|
||||
console.log("Clicked back!");
|
||||
this.RestoreLeaflet();
|
||||
if (onClose() !== undefined) {
|
||||
console.error("WARNING: onClose is not defined")
|
||||
onClose();
|
||||
}
|
||||
}).SetClass("block sm:hidden mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5")
|
||||
const returnToTheMap =
|
||||
new Combine([
|
||||
Svg.back_svg().SetClass("block sm:hidden"),
|
||||
Svg.close_svg().SetClass("hidden sm:block")
|
||||
])
|
||||
.onClick(() => {
|
||||
console.log("Clicked back!");
|
||||
ScrollableFullScreen.RestoreLeaflet();
|
||||
if (onClose !== undefined) {
|
||||
onClose();
|
||||
} else {
|
||||
console.error("WARNING: onClose is not defined")
|
||||
}
|
||||
}).SetClass("mb-2 bg-blue-50 rounded-full w-12 h-12 p-1.5")
|
||||
|
||||
title.SetClass("block w-full")
|
||||
title.SetClass("block w-full text-2xl font-bold p-2 pl-4")
|
||||
const ornament = new Combine([new Ornament().SetStyle("height:5em;")])
|
||||
.SetClass("block sm:hidden h-5")
|
||||
|
||||
|
||||
this._component =
|
||||
new Combine([
|
||||
new Combine([
|
||||
new Combine([returnToTheMap, title])
|
||||
.AddClass("border-b-2 border-black shadow sm:shadow-none bg-white p-2 pb-0 sm:p-0 flex overflow-x-hidden flex-shrink-0 max-h-20vh"),
|
||||
new Combine(["<span>", content, "</span>", ornament])
|
||||
.SetClass("block p-2 sm:pt-4 w-full h-screen landscape:h-screen sm:h-full sm:w-full overflow-y-auto overflow-x-hidden"),
|
||||
// We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide
|
||||
]).SetClass("block flex flex-col relative bg-white")
|
||||
]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen sm:max-h-65vh sm:w-auto");
|
||||
new Combine([
|
||||
new Combine([returnToTheMap, title])
|
||||
.SetClass("border-b-2 border-black shadow sm:shadow-none bg-white p-2 pb-0 sm:p-0 flex overflow-x-hidden flex-shrink-0 max-h-20vh"),
|
||||
new Combine(["<span>", content, "</span>", ornament])
|
||||
.SetClass("block p-2 sm:pt-4 w-full h-screen landscape:h-screen sm:h-full sm:w-full overflow-y-auto overflow-x-hidden"),
|
||||
// We add an ornament which takes around 5em. This is in order to make sure the Web UI doesn't hide
|
||||
]).SetClass("block flex flex-col relative bg-white")
|
||||
]).SetClass("fixed top-0 left-0 right-0 h-screen w-screen sm:max-h-65vh sm:w-auto sm:relative");
|
||||
|
||||
}
|
||||
|
||||
private static HideClutter(htmlElement: HTMLElement) {
|
||||
const whiteList = new Set<Element>();
|
||||
do {
|
||||
if(htmlElement === null){
|
||||
break;
|
||||
}
|
||||
if (htmlElement.classList.contains("clutter")) {
|
||||
// Don't hide the parent element
|
||||
whiteList.add(htmlElement)
|
||||
}
|
||||
htmlElement = htmlElement.parentElement;
|
||||
} while (htmlElement != null)
|
||||
|
||||
const clutter = document.getElementsByClassName("clutter");
|
||||
for (let i = 0; i < clutter.length; ++i) {
|
||||
if (whiteList.has(clutter[i])) {
|
||||
continue;
|
||||
}
|
||||
const classlist = clutter[i].classList;
|
||||
if (classlist.contains("clutter-hidden")) {
|
||||
continue;
|
||||
}
|
||||
classlist.add("clutter-hidden");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the 'clutter' class (which merely acts as a tag) onto some elements, e.g. the leaflet attributions
|
||||
* @constructor
|
||||
*/
|
||||
private static PreparePatchesForFullscreen(): boolean {
|
||||
const toHide = document.getElementsByClassName("leaflet-control-container");
|
||||
for (let i = 0; i < toHide.length; ++i) {
|
||||
toHide[i].classList.add("clutter");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static PatchLeaflet(htmlElement) {
|
||||
if(htmlElement === null){
|
||||
return;
|
||||
}
|
||||
do {
|
||||
// A leaflet workaround: in order for fullscreen to work, we need to get the parent element which does a transform3d and remove/read the transform
|
||||
if (htmlElement.style.transform !== "") {
|
||||
if (!htmlElement.classList.contains("no-transform")) {
|
||||
htmlElement.classList.add("no-transform");
|
||||
htmlElement.classList.add("scrollable-fullscreen-no-transform")
|
||||
}
|
||||
}
|
||||
htmlElement = htmlElement.parentElement;
|
||||
} while (htmlElement != null)
|
||||
|
||||
}
|
||||
|
||||
private static RestoreLeaflet() {
|
||||
console.log("Restoring")
|
||||
const noTransf = document.getElementsByClassName("scrollable-fullscreen-no-transform");
|
||||
for (let i = 0; i < noTransf.length; ++i) {
|
||||
noTransf[i].classList.remove("no-transform");
|
||||
noTransf[i].classList.remove("scrollable-fullscreen-no-transform");
|
||||
}
|
||||
let clutter = document.getElementsByClassName("clutter-hidden");
|
||||
|
||||
do {
|
||||
for (let i = 0; i < clutter.length; ++i) {
|
||||
clutter[i].classList.remove("clutter-hidden");
|
||||
}
|
||||
clutter = document.getElementsByClassName("clutter-hidden");
|
||||
} while (clutter.length > 0)
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
return this._component.Render();
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
|
||||
do {
|
||||
// A leaflet workaround: in order for fullscreen to work, we need to get the parent element which does a transform3d and remove/read the transform
|
||||
if (htmlElement.style.transform !== "") {
|
||||
this.elementsToRestore.add(htmlElement);
|
||||
htmlElement.classList.add("no-transform")
|
||||
}
|
||||
htmlElement = htmlElement.parentElement;
|
||||
} while (htmlElement != null)
|
||||
|
||||
super.InnerUpdate(htmlElement);
|
||||
Update() {
|
||||
console.log("Updating the scrollableFullScreen")
|
||||
super.Update();
|
||||
this._component.Update();
|
||||
}
|
||||
|
||||
private RestoreLeaflet() {
|
||||
this.elementsToRestore.forEach(
|
||||
el => el.classList.remove("no-transform")
|
||||
);
|
||||
public PrepFullscreen(htmlElement = undefined) {
|
||||
htmlElement = htmlElement ?? document.getElementById(this.id);
|
||||
ScrollableFullScreen.PatchLeaflet(htmlElement);
|
||||
ScrollableFullScreen.HideClutter(htmlElement);
|
||||
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
this.PrepFullscreen(htmlElement)
|
||||
super.InnerUpdate(htmlElement);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,9 +24,9 @@ export class SubtleButton extends UIElement{
|
|||
} else {
|
||||
img = imageUrl;
|
||||
}
|
||||
img.AddClass("block flex items-center justify-center h-11 w-11 flex-shrink0")
|
||||
img.SetClass("block flex items-center justify-center h-11 w-11 flex-shrink0")
|
||||
this.image = new Combine([img])
|
||||
.AddClass("flex-shrink-0");
|
||||
.SetClass("flex-shrink-0");
|
||||
|
||||
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ export class SubtleButton extends UIElement{
|
|||
return new Combine([
|
||||
this.image,
|
||||
this.message,
|
||||
]).AddClass("block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200")
|
||||
]).SetClass("block flex p-3 my-2 bg-blue-100 rounded-lg hover:shadow-xl hover:bg-blue-200")
|
||||
.Render();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,22 +7,22 @@ export default class IndexText extends Combine {
|
|||
constructor() {
|
||||
super([
|
||||
new FixedUiElement(`<img class="w-12 h-12 sm:h-24 sm:w-24" src="./assets/svg/logo.svg" alt="MapComplete Logo">`)
|
||||
.AddClass("flex-none m-3"),
|
||||
.SetClass("flex-none m-3"),
|
||||
|
||||
new Combine([
|
||||
Translations.t.index.title
|
||||
.AddClass("text-2xl tracking-tight font-extrabold text-gray-900 sm:text-5xl md:text-6xl block text-gray-800 xl:inline"),
|
||||
.SetClass("text-2xl tracking-tight font-extrabold text-gray-900 sm:text-5xl md:text-6xl block text-gray-800 xl:inline"),
|
||||
|
||||
Translations.t.index.intro.AddClass(
|
||||
Translations.t.index.intro.SetClass(
|
||||
"mt-3 text-base font-semibold text-gray-500 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0"),
|
||||
|
||||
Translations.t.index.pickTheme.AddClass("mt-3 text-base text-green-600 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0")
|
||||
Translations.t.index.pickTheme.SetClass("mt-3 text-base text-green-600 sm:mt-5 sm:text-lg sm:max-w-xl sm:mx-auto md:mt-5 md:text-xl lg:mx-0")
|
||||
|
||||
]).AddClass("flex flex-col sm:text-center lg:text-left m-1 mt-2 md:m-2 md:mt-4")
|
||||
]).SetClass("flex flex-col sm:text-center lg:text-left m-1 mt-2 md:m-2 md:mt-4")
|
||||
]);
|
||||
|
||||
|
||||
this.AddClass("flex flex-row");
|
||||
this.SetClass("flex flex-row");
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ export default class SearchAndGo extends UIElement {
|
|||
);
|
||||
|
||||
private _foundEntries = new UIEventSource([]);
|
||||
private _goButton = Svg.search_ui().AddClass('w-8 h-8 full-rounded border-black float-right');
|
||||
private _goButton = Svg.search_ui().SetClass('w-8 h-8 full-rounded border-black float-right');
|
||||
|
||||
constructor() {
|
||||
super(undefined);
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
import {UIElement} from "./UIElement";
|
||||
import State from "../State";
|
||||
import Combine from "./Base/Combine";
|
||||
|
||||
/**
|
||||
* Handles the full screen popup on mobile
|
||||
*/
|
||||
export default class FullScreenMessageBox extends UIElement {
|
||||
|
||||
private _content: UIElement;
|
||||
|
||||
constructor() {
|
||||
super(State.state.fullScreenMessage);
|
||||
this.HideOnEmpty(true);
|
||||
}
|
||||
|
||||
|
||||
InnerRender(): string {
|
||||
if (State.state.fullScreenMessage.data === undefined) {
|
||||
return "";
|
||||
}
|
||||
this._content = State.state.fullScreenMessage.data.content;
|
||||
return new Combine([this._content])
|
||||
.SetClass("block max-h-screen h-screen overflow-x-hidden overflow-y-auto bg-white p-0").Render();
|
||||
}
|
||||
|
||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||
super.InnerUpdate(htmlElement);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -9,29 +9,41 @@ import State from "../../State";
|
|||
import TagRenderingConfig from "../../Customizations/JSON/TagRenderingConfig";
|
||||
import ScrollableFullScreen from "../Base/ScrollableFullScreen";
|
||||
|
||||
export default class FeatureInfoBox extends UIElement {
|
||||
private _component: UIElement;
|
||||
|
||||
public title: UIElement ;
|
||||
export default class FeatureInfoBox extends ScrollableFullScreen {
|
||||
|
||||
constructor(
|
||||
tags: UIEventSource<any>,
|
||||
layerConfig: LayerConfig,
|
||||
onClose: () => {}
|
||||
onClose: () => void
|
||||
) {
|
||||
super();
|
||||
super(
|
||||
FeatureInfoBox.GenerateTitleBar(tags, layerConfig),
|
||||
FeatureInfoBox.GenerateContent(tags, layerConfig),
|
||||
onClose
|
||||
);
|
||||
if (layerConfig === undefined) {
|
||||
throw "Undefined layerconfig"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static GenerateTitleBar( tags: UIEventSource<any>,
|
||||
layerConfig: LayerConfig): UIElement{
|
||||
const title = new TagRenderingAnswer(tags, layerConfig.title ?? new TagRenderingConfig("POI", undefined))
|
||||
.AddClass("text-2xl break-words font-bold p-2");
|
||||
this.title = title;
|
||||
.SetClass("text-2xl break-words font-bold p-2");
|
||||
const titleIcons = new Combine(
|
||||
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)
|
||||
.AddClass("block w-8 h-8 align-baseline box-content p-0.5")))
|
||||
.AddClass("flex flex-row flex-wrap pt-1 items-center mr-2");
|
||||
.SetClass("block w-8 h-8 align-baseline box-content p-0.5")))
|
||||
.SetClass("flex flex-row flex-wrap pt-1 items-center mr-2");
|
||||
|
||||
return new Combine([
|
||||
new Combine([title, titleIcons]).SetClass("flex flex-grow justify-between")
|
||||
])
|
||||
}
|
||||
|
||||
private static GenerateContent(tags: UIEventSource<any>,
|
||||
layerConfig: LayerConfig): UIElement{
|
||||
|
||||
|
||||
|
||||
let questionBox: UIElement = undefined;
|
||||
if (State.state.featureSwitchUserbadge.data) {
|
||||
|
@ -53,20 +65,12 @@ export default class FeatureInfoBox extends UIElement {
|
|||
}
|
||||
const tail = new Combine([]).SetClass("only-on-mobile");
|
||||
|
||||
const content = new Combine([
|
||||
return new Combine([
|
||||
...renderings,
|
||||
tail.SetClass("featureinfobox-tail")
|
||||
]
|
||||
)
|
||||
const titleBar = new Combine([
|
||||
new Combine([title, titleIcons]).SetClass("flex flex-grow justify-between")
|
||||
])
|
||||
|
||||
this._component = new ScrollableFullScreen(titleBar, content, onClose)
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
return this._component.Render();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class TagRenderingAnswer extends UIElement {
|
|||
if (configuration === undefined) {
|
||||
throw "Trying to generate a tagRenderingAnswer without configuration..."
|
||||
}
|
||||
this.AddClass("flex items-center flex-row text-lg")
|
||||
this.SetClass("flex items-center flex-row text-lg")
|
||||
}
|
||||
|
||||
InnerRender(): string {
|
||||
|
|
|
@ -88,7 +88,7 @@ export default class TagRenderingQuestion extends UIElement {
|
|||
return tags.asHumanString(true, true);
|
||||
}
|
||||
)
|
||||
).AddClass("block")
|
||||
).SetClass("block")
|
||||
}
|
||||
|
||||
private GenerateInputElement(): InputElement<TagsFilter> {
|
||||
|
|
|
@ -44,10 +44,10 @@ export default class ShowDataLayer {
|
|||
|
||||
let geoLayer = self.CreateGeojsonLayer(feats)
|
||||
if (layoutToUse.clustering.minNeededElements <= features.data.length) {
|
||||
const cl = window["L"]; // This is a dirty workaround, the clustering plugin binds to the L of the window, not of the namespace or something
|
||||
const cluster = cl.markerClusterGroup({ disableClusteringAtZoom: layoutToUse.clustering.maxZoom });
|
||||
cluster.addLayer(geoLayer);
|
||||
geoLayer = cluster;
|
||||
const cl = window["L"]; // This is a dirty workaround, the clustering plugin binds to the L of the window, not of the namespace or something
|
||||
const cluster = cl.markerClusterGroup({disableClusteringAtZoom: layoutToUse.clustering.maxZoom});
|
||||
cluster.addLayer(geoLayer);
|
||||
geoLayer = cluster;
|
||||
}
|
||||
|
||||
if (oldGeoLayer) {
|
||||
|
@ -60,22 +60,22 @@ export default class ShowDataLayer {
|
|||
features.addCallbackAndRun(() => update());
|
||||
leafletMap.addCallback(() => update());
|
||||
State.state.selectedElement.addCallback(feature => {
|
||||
if(feature === undefined){
|
||||
if (feature === undefined) {
|
||||
return;
|
||||
}
|
||||
const id = feature.properties.id+feature.geometry.type+feature._matching_layer_id;
|
||||
const id = feature.properties.id + feature.geometry.type + feature._matching_layer_id;
|
||||
const action = self._onSelectedTrigger[id];
|
||||
if(action){
|
||||
if (action) {
|
||||
action();
|
||||
}
|
||||
});
|
||||
Hash.hash.addCallbackAndRun(id => {
|
||||
// This is a bit of an edge case: if the hash becomes an id to search, we have to show the corresponding popup
|
||||
if(State.state.selectedElement !== undefined){
|
||||
if (State.state.selectedElement !== undefined) {
|
||||
return; // Something is already selected, we don't have to apply this fix
|
||||
}
|
||||
const action = self._onSelectedTrigger[id];
|
||||
if(action){
|
||||
if (action) {
|
||||
action();
|
||||
}
|
||||
})
|
||||
|
@ -126,41 +126,48 @@ export default class ShowDataLayer {
|
|||
|
||||
|
||||
const tags = State.state.allElements.getEventSourceFor(feature);
|
||||
const uiElement: LazyElement = new LazyElement(() => new FeatureInfoBox(tags, layer, () => popup.closePopup()),
|
||||
const uiElement: LazyElement<FeatureInfoBox> = new LazyElement(() => new FeatureInfoBox(tags, layer, () => {
|
||||
console.log("Closing the popup!")
|
||||
State.state.selectedElement.setData(undefined);
|
||||
popup.remove();
|
||||
|
||||
}),
|
||||
"<div style='height: 90vh'>Rendering</div>");
|
||||
popup.setContent(uiElement.Render());
|
||||
popup.on('remove', () => {
|
||||
if(!popup.isOpen()){
|
||||
if (!popup.isOpen()) {
|
||||
return;
|
||||
}
|
||||
State.state.selectedElement.setData(undefined);
|
||||
State.state.selectedElement.setData(undefined);
|
||||
});
|
||||
leafletLayer.bindPopup(popup);
|
||||
// We first render the UIelement (which'll still need an update later on...)
|
||||
// But at least it'll be visible already
|
||||
|
||||
|
||||
leafletLayer.on("click", (e) => {
|
||||
leafletLayer.on("click", () => {
|
||||
// We set the element as selected...
|
||||
uiElement.Activate();
|
||||
|
||||
uiElement.Activate(e => e.PrepFullscreen());
|
||||
State.state.selectedElement.setData(feature);
|
||||
});
|
||||
|
||||
const id = feature.properties.id+feature.geometry.type+feature._matching_layer_id;
|
||||
|
||||
const id = feature.properties.id + feature.geometry.type + feature._matching_layer_id;
|
||||
this._onSelectedTrigger[id]
|
||||
= () => {
|
||||
if(popup.isOpen()){
|
||||
= () => {
|
||||
if (popup.isOpen()) {
|
||||
return;
|
||||
}
|
||||
leafletLayer.openPopup();
|
||||
uiElement.Activate();
|
||||
uiElement.Activate(e => e.PrepFullscreen());
|
||||
State.state.selectedElement.setData(feature);
|
||||
}
|
||||
this._onSelectedTrigger[feature.properties.id.replace("/","_")] = this._onSelectedTrigger[id];
|
||||
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data) {
|
||||
this._onSelectedTrigger[feature.properties.id.replace("/", "_")] = this._onSelectedTrigger[id];
|
||||
if (feature.properties.id.replace(/\//g, "_") === Hash.hash.data && State.state.selectedElement.data === undefined) {
|
||||
// This element is in the URL, so this is a share link
|
||||
// We open the relevant popup straight away
|
||||
uiElement.Activate();
|
||||
console.log("Opening the popup due to sharelink")
|
||||
uiElement.Activate(e => e.PrepFullscreen());
|
||||
popup.setContent(uiElement.Render());
|
||||
|
||||
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
|
||||
|
|
|
@ -149,16 +149,12 @@ export abstract class UIElement extends UIEventSource<string> {
|
|||
return this.InnerRender() === "";
|
||||
}
|
||||
|
||||
public SetClass(clss: string): UIElement {
|
||||
return this.AddClass(clss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the relevant classes, space seperated
|
||||
* @param clss
|
||||
* @constructor
|
||||
*/
|
||||
public AddClass(clss: string) {
|
||||
public SetClass(clss: string) {
|
||||
this.dumbMode = false;
|
||||
const all = clss.split(" ");
|
||||
let recordedChange = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue