@digital-blueprint/esign-app
Version:
[GitHub Repository](https://github.com/digital-blueprint/esign-app) | [npmjs package](https://www.npmjs.com/package/@digital-blueprint/esign-app) | [Unpkg CDN](https://unpkg.com/browse/@digital-blueprint/esign-app/) | [Esign Bundle](https://gitlab.tugraz.
498 lines (447 loc) • 15.3 kB
JavaScript
import {html, css} from 'lit';
import {createInstance} from './i18n.js';
import {ScopedElementsMixin, IconButton, Icon, LangMixin} from '@dbp-toolkit/common';
import {TabulatorTable} from '@dbp-toolkit/tabulator-table';
import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
import {TooltipElement} from '@dbp-toolkit/tooltip';
export class CustomTabulatorTable extends TabulatorTable {
static get scopedElements() {
return {
'dbp-esign-download-button': DownloadButton,
'dbp-esign-filename-label': FilenameLabel,
'dbp-esign-reupload-button': ReUploadButton,
'dbp-esign-remove-failed-file-button': RemoveFailedFileButton,
'dbp-esign-preview-button': PreviewButton,
'dbp-esign-delete-button': DeleteButton,
'dbp-esign-annotations-button': AnnotationsButton,
'dbp-esign-positioning-switch': PositioningSwitch,
};
}
static get styles() {
return [
TabulatorTable.styles,
// block needed for ResizeObserver
css`
:host {
display: block;
}
`,
];
}
_handleResize() {
// XXX: Work around tabulator table losing elements when un-collapsing
if (this.tabulatorTable && this.tabulatorTable.initialized) {
this.tabulatorTable.redraw(true);
}
}
connectedCallback() {
super.connectedCallback();
this._resizeObserver = new ResizeObserver(this._handleResize.bind(this));
this._resizeObserver.observe(this);
}
disconnectedCallback() {
this._resizeObserver.unobserve(this);
this._resizeObserver.disconnect();
super.disconnectedCallback();
}
}
export class FilenameLabel extends LangMixin(ScopedElementsMixin(DBPLitElement), createInstance) {
constructor() {
super();
this.file = null;
this.isDownloaded = false;
this.isPlacementMissing = false;
}
static get properties() {
return {
...super.properties,
file: {type: Object, attribute: false},
isDownloaded: {type: Boolean, reflect: true},
isPlacementMissing: {type: Boolean, reflect: true},
};
}
static get scopedElements() {
return {
'dbp-icon': Icon,
'dbp-tooltip': TooltipElement,
};
}
static get styles() {
return css`
:host {
display: flex;
align-items: center;
max-width: 100%;
}
.filename {
overflow: hidden;
text-overflow: ellipsis;
}
dbp-icon {
font-size: 24px;
margin-left: 20px;
top: -0.1em;
}
dbp-tooltip {
font-size: 24px;
margin-bottom: 4px;
margin-left: 10px;
}
`;
}
render() {
let i18n = this._i18n;
return html`
<div class="filename">${this.file ? this.file.name : ``}</div>
${this.isPlacementMissing
? html`
<dbp-tooltip
text-content="${i18n.t('label-manual-positioning-missing')}"
icon-name="warning-high"
role="tooltip"
aria-label="${i18n.t('label-manual-positioning-missing')}"></dbp-tooltip>
`
: ''}
${this.isDownloaded
? html`
<dbp-icon
name="download-complete"
title="${i18n.t('download-file-completed')}"
aria-label="${i18n.t('download-file-completed')}"></dbp-icon>
`
: ``}
`;
}
}
export class DownloadButton extends LangMixin(ScopedElementsMixin(DBPLitElement), createInstance) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
render() {
return html`
<dbp-icon-button
icon-name="download"
class="download-button"
aria-label="${this._i18n.t('download-file-button-title')}"
title="${this._i18n.t('download-file-button-title')}"></dbp-icon-button>
`;
}
}
export class ReUploadButton extends LangMixin(ScopedElementsMixin(DBPLitElement), createInstance) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
render() {
return html`
<dbp-icon-button
icon-name="reload"
class="re-upload-button"
aria-label="${this._i18n.t('re-upload-file-button-title')}"
title="${this._i18n.t('re-upload-file-button-title')}"></dbp-icon-button>
`;
}
}
export class RemoveFailedFileButton extends LangMixin(
ScopedElementsMixin(DBPLitElement),
createInstance,
) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
render() {
return html`
<dbp-icon-button
icon-name="trash"
class="delete-button"
aria-label="${this._i18n.t('remove-failed-file-button-title')}"
title="${this._i18n.t('remove-failed-file-button-title')}"></dbp-icon-button>
`;
}
}
export class PreviewButton extends LangMixin(ScopedElementsMixin(DBPLitElement), createInstance) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
render() {
return html`
<dbp-icon-button
icon-name="keyword-research"
class="preview-button"
aria-label="${this._i18n.t('preview-file-button-title')}"
title="${this._i18n.t('preview-file-button-title')}"></dbp-icon-button>
`;
}
}
export class AnnotationsButton extends LangMixin(
ScopedElementsMixin(DBPLitElement),
createInstance,
) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
static get properties() {
return {
annotations: {type: Array},
};
}
static get styles() {
return css`
.annotation-wrapper {
display: inline-grid;
grid-template-columns: 27px 23px;
grid-template-rows: 23px 27px;
width: 50px;
height: 50px;
position: relative;
}
.annotation-button {
font-size: 24px;
grid-area: 1 / 1 / 3 / 3;
place-self: center;
}
.annotation-plus {
position: absolute;
font-size: 19px;
top: 21%;
left: 40%;
font-weight: bold;
pointer-events: none;
}
.annotation-count {
grid-column: 2 / 3;
grid-row: 1 / 2;
justify-self: start;
align-self: end;
background: var(--dbp-primary);
color: var(--dbp-background);
border: 1px solid var(--dbp-background);
border-radius: 100%;
display: block;
width: 21px;
height: 21px;
text-align: center;
line-height: 21px;
font-size: 14px;
font-weight: bold;
z-index: 3;
pointer-events: none;
}
`;
}
constructor() {
super();
this.annotations = [];
}
render() {
return html`
<span class="annotation-wrapper">
<dbp-icon-button
icon-name="bubble"
class="annotation-button"
aria-label="${this._i18n.t('annotation-button-title')}"
title="${this._i18n.t('annotation-button-title')}"></dbp-icon-button>
${this.annotations.length < 1
? html`
<span class="annotation-plus">+</span>
`
: html`
<span
class="annotation-count"
title="${this._i18n.t('annotations-count-text', {
annotationCount: this.annotations.length,
})}">
${this.annotations.length}
</span>
`}
</span>
`;
}
}
export class DeleteButton extends LangMixin(ScopedElementsMixin(DBPLitElement), createInstance) {
static get scopedElements() {
return {
'dbp-icon-button': IconButton,
};
}
render() {
return html`
<dbp-icon-button
icon-name="trash"
class="delete-button"
aria-label="${this._i18n.t('remove-queued-file-button-title')}"
title="${this._i18n.t('remove-queued-file-button-title')}"></dbp-icon-button>
`;
}
}
export class PositioningSwitch extends LangMixin(
ScopedElementsMixin(DBPLitElement),
createInstance,
) {
static get styles() {
return css`
.toggle-wrapper {
--toggle-width: 80px;
--toggle-height: 34px;
--icon-width: 35px;
--icon-height: 28px;
--transition-time: 0.3s;
--gap: 3px;
--checkmark-color: var(--dbp-muted);
--checkmark-color-need-positioning: var(--dbp-danger);
--dbp-border-radius: 4px;
overflow: hidden;
position: relative;
display: flex;
align-items: center;
}
.toggle {
position: relative;
display: inline-block;
padding: 0 8px;
}
.label-text {
line-height: var(--toggle-height);
}
/* the switch */
label.toggle-item {
width: var(--toggle-width);
background: var(--dbp-muted);
color: var(--dbp-background);
height: var(--toggle-height);
display: block;
border-radius: var(--dbp-border-radius);
border: 1px solid var(--dbp-muted);
position: relative;
transition: all var(--transition-time) ease;
cursor: pointer;
margin: 0;
}
label.toggle-item.on {
background-color: var(--dbp-info);
border: 1px solid var(--dbp-info);
}
.label-off,
.label-on {
font-weight: bold;
position: absolute;
transition: opacity 0.1s ease;
transition-delay: 0.3s;
opacity: 1;
height: var(--toggle-height);
line-height: var(--toggle-height);
}
.label-off {
/*left: calc(100% - var(--icon-size) - var(--gap));*/
right: 6px;
}
.label-on {
/*right: calc(100% - var(--icon-size) - var(--gap));*/
left: 6px;
}
input {
height: 40px;
left: 0;
opacity: 0;
position: absolute;
top: 0;
width: 40px;
margin: 0;
padding: 0;
}
/* keyboard focus visibility */
.toggle .input-checkbox:focus-visible + .toggle-item {
box-shadow: 0px 0px 3px 1px var(--dbp-primary);
}
/* the button */
.toggle .check {
border-radius: var(--dbp-border-radius);
width: var(--icon-width);
height: var(--icon-height);
position: absolute;
background: var(--dbp-background);
transition: 0.4s ease;
/*top: calc(var(--gap) + 1px);*/
top: var(--gap);
bottom: var(--gap);
left: var(--gap);
}
.need-positioning label.toggle-item {
border-color: var(--checkmark-color-need-positioning);
background-color: var(--checkmark-color-need-positioning);
color: var(--dbp-background);
}
.hidden {
display: none;
}
.sr-only {
position: absolute ;
clip: rect(1px, 1px, 1px, 1px);
overflow: hidden;
height: 1px;
width: 1px;
word-wrap: normal;
}
/* animation */
.input-checkbox:checked + label .check {
/*left: calc(100% - var(--icon-width) - var(--gap) - 1px);*/
left: calc(100% - var(--icon-width) - var(--gap));
}
`;
}
constructor() {
super();
this.needPositioning = false;
this.checked = false;
}
static get properties() {
return {
needPositioning: {type: Boolean, attribute: 'need-positioning'},
checked: {type: Boolean, reflect: true},
};
}
_handleToggle(event) {
this.checked = event.target.checked;
this.dispatchEvent(
new CustomEvent('toggle-change', {
detail: {
checked: this.checked,
},
bubbles: true,
}),
);
}
render() {
return html`
<div class="toggle-wrapper">
<div class="toggle ${this.needPositioning ? 'need-positioning' : ''}">
<input
id="toggle-input"
class="input-checkbox"
type="checkbox"
role="switch"
.checked="${this.checked}"
@change="${this._handleToggle}" />
<label class="toggle-item ${this.checked ? 'on' : 'off'}" for="toggle-input">
<span class="label-on" ?aria-hidden="${!this.checked}">
${this._i18n.t('toggle-switch-label-text-on')}
</span>
<span class="label-off" ?aria-hidden="${this.checked}">
${this._i18n.t('toggle-switch-label-text-off')}
</span>
<div class="check"></div>
</label>
</div>
</div>
`;
}
}