@eclipse-glsp/client
Version:
A sprotty-based client for GLSP
127 lines (110 loc) • 4.86 kB
text/typescript
/********************************************************************************
* Copyright (c) 2020-2023 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { ValidationStatus, codiconCSSString } from '@eclipse-glsp/sprotty';
export interface IValidationDecorator {
decorateValidationResult(status: ValidationStatus): void;
isValidatedOk(): boolean;
invalidate(): void;
dispose(): void;
}
export namespace IValidationDecorator {
export const NO_DECORATION: IValidationDecorator = {
// eslint-disable-next-line @typescript-eslint/no-empty-function
decorateValidationResult(_status: ValidationStatus) {},
isValidatedOk(): boolean {
return false;
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
invalidate() {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
dispose() {}
};
}
export class ValidationDecorator implements IValidationDecorator {
warningClasses = ['warning'];
warningIconClasses = codiconCSSString('warning');
errorClasses = ['error'];
errorIconClasses = codiconCSSString('error');
isValidated = false;
hasValidationError = false;
protected decorationDiv?: HTMLDivElement;
constructor(protected containerElement: HTMLElement) {}
decorateValidationResult(status: ValidationStatus): void {
if (ValidationStatus.isError(status)) {
this.hasValidationError = true;
this.decorateError(status.message ? status.message : 'Error');
} else if (ValidationStatus.isWarning(status)) {
this.hasValidationError = false;
this.decorateWarning(status.message ? status.message : 'Warning');
} else {
this.hasValidationError = false;
this.dispose();
}
this.isValidated = true;
}
protected decorateError(message: string): void {
this.switchCssClasses(this.containerElement, this.errorClasses);
const div = this.createDecorationDiv();
this.switchCssClasses(div, this.errorClasses);
div.innerHTML = `<span class="${this.errorIconClasses}"></span> ${message}`;
this.adjustPosition();
}
protected decorateWarning(message: string): void {
this.switchCssClasses(this.containerElement, this.warningClasses);
const div = this.createDecorationDiv();
this.switchCssClasses(div, this.warningClasses);
div.innerHTML = `<span class="${this.warningIconClasses}"></span> ${message}`;
this.adjustPosition();
}
protected switchCssClasses(element: HTMLElement, cssClasses: string[]): void {
element.classList.remove(...this.errorClasses, ...this.warningClasses);
element.classList.add(...cssClasses);
}
protected createDecorationDiv(): HTMLDivElement {
if (!this.decorationDiv) {
this.containerElement.classList.add('validation');
this.decorationDiv = document.createElement('div');
this.decorationDiv.style.width = `${this.decorationContainerWidth()}px`;
this.decorationDiv.classList.add('validation-decorator');
this.containerElement.appendChild(this.decorationDiv);
}
return this.decorationDiv;
}
protected decorationContainerWidth(): number {
return this.containerElement.clientWidth - 5;
}
protected adjustPosition(): void {
if (this.decorationDiv) {
const height = this.decorationDiv.clientHeight + 2;
this.decorationDiv.style.top = `-${height}px`;
}
}
isValidatedOk(): boolean {
return this.isValidated && !this.hasValidationError;
}
invalidate(): void {
this.isValidated = false;
}
dispose(): void {
this.hasValidationError = false;
this.isValidated = false;
if (this.decorationDiv && this.containerElement && this.containerElement.contains(this.decorationDiv)) {
this.containerElement.removeChild(this.decorationDiv);
this.switchCssClasses(this.containerElement, []);
this.decorationDiv = undefined;
}
}
}