static: format code
This commit is contained in:
parent
e42ad3f659
commit
1cb227305c
|
@ -0,0 +1,3 @@
|
||||||
|
# Ignore artifacts:
|
||||||
|
dist
|
||||||
|
coverage
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -449,6 +449,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
|
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
|
||||||
},
|
},
|
||||||
|
"prettier": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-yYerpkvseM4iKD/BXLYUkQV5aKt4tQPqaGW6EsZjzyu0r7sVZZNPJW4Y8MyKmicp6t42XUPcBVA+H6sB3gqndw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"randombytes": {
|
"randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-typescript": "^6.1.0",
|
"@rollup/plugin-typescript": "^6.1.0",
|
||||||
|
"prettier": "2.2.0",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-minify-html-literals": "^1.2.5",
|
"rollup-plugin-minify-html-literals": "^1.2.5",
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'DIN 1451 Std';
|
font-family: "DIN 1451 Std";
|
||||||
src: url('fonts/DINEngschriftStd.woff2') format('woff2'),
|
src: url("fonts/DINEngschriftStd.woff2") format("woff2"),
|
||||||
url('fonts/DINEngschriftStd.woff') format('woff');
|
url("fonts/DINEngschriftStd.woff") format("woff");
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: .5em;
|
margin-right: 0.5em;
|
||||||
color: var(--pf-global--Color--light-200);
|
color: var(--pf-global--Color--light-200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,11 @@
|
||||||
|
|
||||||
.pb-brand > img {
|
.pb-brand > img {
|
||||||
max-height: 68px;
|
max-height: 68px;
|
||||||
margin-right: .5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pf-c-background-image::before {
|
.pf-c-background-image::before {
|
||||||
background-image: url('./flow_background.jpg');
|
background-image: url("./flow_background.jpg");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,8 @@ select[multiple] {
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector-available, .selector-chosen {
|
.selector-available,
|
||||||
|
.selector-chosen {
|
||||||
width: auto;
|
width: auto;
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -114,7 +115,8 @@ select[multiple] {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector-add, .selector-remove {
|
.selector-add,
|
||||||
|
.selector-remove {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background-size: 20px auto;
|
background-size: 20px auto;
|
||||||
|
@ -128,7 +130,8 @@ select[multiple] {
|
||||||
background-position: 0 -80px;
|
background-position: 0 -80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.selector-chooseall, a.selector-clearall {
|
a.selector-chooseall,
|
||||||
|
a.selector-clearall {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +148,8 @@ a.selector-chooseall, a.selector-clearall {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stacked .selector-available, .stacked .selector-chosen {
|
.stacked .selector-available,
|
||||||
|
.stacked .selector-chosen {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +165,8 @@ a.selector-chooseall, a.selector-clearall {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stacked .selector-add, .stacked .selector-remove {
|
.stacked .selector-add,
|
||||||
|
.stacked .selector-remove {
|
||||||
background-size: 20px auto;
|
background-size: 20px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +186,8 @@ a.selector-chooseall, a.selector-clearall {
|
||||||
background-position: 0 -20px;
|
background-position: 0 -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-tooltip, .selector .help-icon {
|
.help-tooltip,
|
||||||
|
.selector .help-icon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +218,8 @@ form .form-row p.datetime {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector-add, .selector-remove {
|
.selector-add,
|
||||||
|
.selector-remove {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -222,11 +229,13 @@ form .form-row p.datetime {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active.selector-add, .active.selector-remove {
|
.active.selector-add,
|
||||||
|
.active.selector-remove {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active.selector-add:hover, .active.selector-remove:hover {
|
.active.selector-add:hover,
|
||||||
|
.active.selector-remove:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +243,8 @@ form .form-row p.datetime {
|
||||||
background: url(../admin/img/selector-icons.svg) 0 -96px no-repeat;
|
background: url(../admin/img/selector-icons.svg) 0 -96px no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.active.selector-add:focus, .active.selector-add:hover {
|
.active.selector-add:focus,
|
||||||
|
.active.selector-add:hover {
|
||||||
background-position: 0 -112px;
|
background-position: 0 -112px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
import resolve from 'rollup-plugin-node-resolve';
|
import resolve from "rollup-plugin-node-resolve";
|
||||||
import commonjs from 'rollup-plugin-commonjs';
|
import commonjs from "rollup-plugin-commonjs";
|
||||||
import minifyHTML from 'rollup-plugin-minify-html-literals';
|
import minifyHTML from "rollup-plugin-minify-html-literals";
|
||||||
import { terser } from 'rollup-plugin-terser';
|
import { terser } from "rollup-plugin-terser";
|
||||||
import sourcemaps from 'rollup-plugin-sourcemaps';
|
import sourcemaps from "rollup-plugin-sourcemaps";
|
||||||
import typescript from '@rollup/plugin-typescript';
|
import typescript from "@rollup/plugin-typescript";
|
||||||
import cssimport from "rollup-plugin-cssimport";
|
import cssimport from "rollup-plugin-cssimport";
|
||||||
|
|
||||||
export default [{
|
export default [
|
||||||
input: './src/main.ts',
|
{
|
||||||
|
input: "./src/main.ts",
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
format: 'es',
|
format: "es",
|
||||||
dir: 'dist',
|
dir: "dist",
|
||||||
sourcemap: true
|
sourcemap: true,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
cssimport(),
|
cssimport(),
|
||||||
typescript(),
|
typescript(),
|
||||||
resolve({browser: true}),
|
resolve({ browser: true }),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
sourcemaps(),
|
sourcemaps(),
|
||||||
minifyHTML(),
|
minifyHTML(),
|
||||||
terser(),
|
terser(),
|
||||||
],
|
],
|
||||||
}];
|
},
|
||||||
|
];
|
||||||
|
|
|
@ -9,10 +9,11 @@ const PROGRESS_CLASSES = ["pf-m-progress", "pf-m-in-progress"];
|
||||||
|
|
||||||
@customElement("pb-action-button")
|
@customElement("pb-action-button")
|
||||||
export class ActionButton extends LitElement {
|
export class ActionButton extends LitElement {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.querySelector("button")?.addEventListener('click', e => this.callAction());
|
this.querySelector("button")?.addEventListener("click", (e) =>
|
||||||
|
this.callAction()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
|
@ -41,33 +42,39 @@ export class ActionButton extends LitElement {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setLoading();
|
this.setLoading();
|
||||||
const csrftoken = getCookie('passbook_csrf');
|
const csrftoken = getCookie("passbook_csrf");
|
||||||
const request = new Request(
|
const request = new Request(this.url, {
|
||||||
this.url,
|
headers: { "X-CSRFToken": csrftoken! },
|
||||||
{ headers: { 'X-CSRFToken': csrftoken! } }
|
});
|
||||||
);
|
|
||||||
fetch(request, {
|
fetch(request, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
mode: 'same-origin',
|
mode: "same-origin",
|
||||||
}).then(r => r.json()).then(r => {
|
})
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((r) => {
|
||||||
this.setDone(SUCCESS_CLASS);
|
this.setDone(SUCCESS_CLASS);
|
||||||
}).catch(() => {
|
})
|
||||||
|
.catch(() => {
|
||||||
this.setDone(ERROR_CLASS);
|
this.setDone(ERROR_CLASS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`<button class="pf-c-button pf-m-primary">
|
return html`<button class="pf-c-button pf-m-primary">
|
||||||
${this.isRunning ? html`
|
${this.isRunning
|
||||||
<span class="pf-c-button__progress">
|
? html` <span class="pf-c-button__progress">
|
||||||
<span class="pf-c-spinner pf-m-md" role="progressbar" aria-valuetext="Loading...">
|
<span
|
||||||
|
class="pf-c-spinner pf-m-md"
|
||||||
|
role="progressbar"
|
||||||
|
aria-valuetext="Loading..."
|
||||||
|
>
|
||||||
<span class="pf-c-spinner__clipper"></span>
|
<span class="pf-c-spinner__clipper"></span>
|
||||||
<span class="pf-c-spinner__lead-ball"></span>
|
<span class="pf-c-spinner__lead-ball"></span>
|
||||||
<span class="pf-c-spinner__tail-ball"></span>
|
<span class="pf-c-spinner__tail-ball"></span>
|
||||||
</span>
|
</span>
|
||||||
</span>` : ""}
|
</span>`
|
||||||
|
: ""}
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>`;
|
</button>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ interface TickValue {
|
||||||
|
|
||||||
@customElement("pb-admin-logins-chart")
|
@customElement("pb-admin-logins-chart")
|
||||||
export class AdminLoginsChart extends LitElement {
|
export class AdminLoginsChart extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
url: string = "";
|
url: string = "";
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ export class AdminLoginsChart extends LitElement {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener("resize", () => {
|
||||||
if (this.chart) {
|
if (this.chart) {
|
||||||
this.chart.resize();
|
this.chart.resize();
|
||||||
}
|
}
|
||||||
|
@ -40,56 +39,74 @@ export class AdminLoginsChart extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
fetch(this.url).then(r => r.json()).catch(e => console.error(e)).then(r => {
|
fetch(this.url)
|
||||||
let ctx = (<HTMLCanvasElement>this.shadowRoot?.querySelector("canvas")).getContext('2d')!;
|
.then((r) => r.json())
|
||||||
|
.catch((e) => console.error(e))
|
||||||
|
.then((r) => {
|
||||||
|
let ctx = (<HTMLCanvasElement>(
|
||||||
|
this.shadowRoot?.querySelector("canvas")
|
||||||
|
)).getContext("2d")!;
|
||||||
this.chart = new Chart(ctx, {
|
this.chart = new Chart(ctx, {
|
||||||
type: 'bar',
|
type: "bar",
|
||||||
data: {
|
data: {
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: 'Failed Logins',
|
label: "Failed Logins",
|
||||||
backgroundColor: "rgba(201, 25, 11, .5)",
|
backgroundColor: "rgba(201, 25, 11, .5)",
|
||||||
spanGaps: true,
|
spanGaps: true,
|
||||||
data: r.logins_failed_per_1h,
|
data: r.logins_failed_per_1h,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Successful Logins',
|
label: "Successful Logins",
|
||||||
backgroundColor: "rgba(189, 229, 184, .5)",
|
backgroundColor: "rgba(189, 229, 184, .5)",
|
||||||
spanGaps: true,
|
spanGaps: true,
|
||||||
data: r.logins_per_1h,
|
data: r.logins_per_1h,
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
spanGaps: true,
|
spanGaps: true,
|
||||||
scales: {
|
scales: {
|
||||||
xAxes: [{
|
xAxes: [
|
||||||
|
{
|
||||||
stacked: true,
|
stacked: true,
|
||||||
gridLines: {
|
gridLines: {
|
||||||
color: "rgba(0, 0, 0, 0)",
|
color: "rgba(0, 0, 0, 0)",
|
||||||
},
|
},
|
||||||
type: 'time',
|
type: "time",
|
||||||
offset: true,
|
offset: true,
|
||||||
ticks: {
|
ticks: {
|
||||||
callback: function (value, index: number, values) {
|
callback: function (
|
||||||
const valueStamp = <TickValue>(<unknown>values[index]);
|
value,
|
||||||
const delta = (Date.now() - valueStamp.value);
|
index: number,
|
||||||
const ago = Math.round(delta / 1000 / 3600);
|
values
|
||||||
|
) {
|
||||||
|
const valueStamp = <TickValue>(
|
||||||
|
(<unknown>values[index])
|
||||||
|
);
|
||||||
|
const delta =
|
||||||
|
Date.now() - valueStamp.value;
|
||||||
|
const ago = Math.round(
|
||||||
|
delta / 1000 / 3600
|
||||||
|
);
|
||||||
return `${ago} Hours ago`;
|
return `${ago} Hours ago`;
|
||||||
},
|
},
|
||||||
autoSkip: true,
|
autoSkip: true,
|
||||||
maxTicksLimit: 8
|
maxTicksLimit: 8,
|
||||||
}
|
},
|
||||||
}],
|
},
|
||||||
yAxes: [{
|
],
|
||||||
|
yAxes: [
|
||||||
|
{
|
||||||
stacked: true,
|
stacked: true,
|
||||||
gridLines: {
|
gridLines: {
|
||||||
color: "rgba(0, 0, 0, 0)",
|
color: "rgba(0, 0, 0, 0)",
|
||||||
}
|
},
|
||||||
}]
|
},
|
||||||
}
|
],
|
||||||
}
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -97,5 +114,4 @@ export class AdminLoginsChart extends LitElement {
|
||||||
render() {
|
render() {
|
||||||
return html`<canvas></canvas>`;
|
return html`<canvas></canvas>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ interface RegexAnchor {
|
||||||
|
|
||||||
@customElement("pb-admin-sidebar")
|
@customElement("pb-admin-sidebar")
|
||||||
export class AdminSideBar extends LitElement {
|
export class AdminSideBar extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
activePath: string;
|
activePath: string;
|
||||||
|
|
||||||
|
@ -16,11 +15,13 @@ export class AdminSideBar extends LitElement {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.activePath = window.location.hash.slice(1, Infinity);
|
this.activePath = window.location.hash.slice(1, Infinity);
|
||||||
window.addEventListener("hashchange", e => {
|
window.addEventListener("hashchange", (e) => {
|
||||||
this.activePath = window.location.hash.slice(1, Infinity);
|
this.activePath = window.location.hash.slice(1, Infinity);
|
||||||
});
|
});
|
||||||
this.querySelectorAll<HTMLAnchorElement>(".pf-c-nav__link").forEach(a => {
|
this.querySelectorAll<HTMLAnchorElement>(".pf-c-nav__link").forEach(
|
||||||
let rawValue = a.attributes.getNamedItem("pb-url-prefix")?.value;
|
(a) => {
|
||||||
|
let rawValue = a.attributes.getNamedItem("pb-url-prefix")
|
||||||
|
?.value;
|
||||||
if (!rawValue) {
|
if (!rawValue) {
|
||||||
const parsedURL = new URL(a.href);
|
const parsedURL = new URL(a.href);
|
||||||
if (parsedURL.hash === "") {
|
if (parsedURL.hash === "") {
|
||||||
|
@ -30,19 +31,19 @@ export class AdminSideBar extends LitElement {
|
||||||
rawValue = `^${parsedURL.hash.slice(1, Infinity)}$`;
|
rawValue = `^${parsedURL.hash.slice(1, Infinity)}$`;
|
||||||
}
|
}
|
||||||
const regexp = RegExp(rawValue);
|
const regexp = RegExp(rawValue);
|
||||||
this.paths.push({anchor: a, match: regexp});
|
this.paths.push({ anchor: a, match: regexp });
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
this.paths.forEach(path => {
|
this.paths.forEach((path) => {
|
||||||
if (path.match.exec(this.activePath)) {
|
if (path.match.exec(this.activePath)) {
|
||||||
path.anchor.classList.add("pf-m-current");
|
path.anchor.classList.add("pf-m-current");
|
||||||
} else {
|
} else {
|
||||||
path.anchor.classList.remove("pf-m-current");
|
path.anchor.classList.remove("pf-m-current");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return html`<slot></slot>`;
|
return html`<slot></slot>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import "codemirror/mode/python/python.js";
|
||||||
|
|
||||||
@customElement("pb-codemirror")
|
@customElement("pb-codemirror")
|
||||||
export class CodeMirrorTextarea extends LitElement {
|
export class CodeMirrorTextarea extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
readOnly: boolean = false;
|
readOnly: boolean = false;
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ export class CodeMirrorTextarea extends LitElement {
|
||||||
}
|
}
|
||||||
this.editor = CodeMirror.fromTextArea(textarea, {
|
this.editor = CodeMirror.fromTextArea(textarea, {
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
theme: 'monokai',
|
theme: "monokai",
|
||||||
lineNumbers: false,
|
lineNumbers: false,
|
||||||
readOnly: this.readOnly,
|
readOnly: this.readOnly,
|
||||||
autoRefresh: true,
|
autoRefresh: true,
|
||||||
|
@ -38,5 +37,4 @@ export class CodeMirrorTextarea extends LitElement {
|
||||||
this.editor?.save();
|
this.editor?.save();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,11 @@ import { customElement, html, LitElement } from "lit-element";
|
||||||
|
|
||||||
@customElement("pb-dropdown")
|
@customElement("pb-dropdown")
|
||||||
export class DropdownButton extends LitElement {
|
export class DropdownButton extends LitElement {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super();
|
||||||
const menu = <HTMLElement>this.querySelector('.pf-c-dropdown__menu')!;
|
const menu = <HTMLElement>this.querySelector(".pf-c-dropdown__menu")!;
|
||||||
this.querySelectorAll("button").forEach(btn => {
|
this.querySelectorAll("button").forEach((btn) => {
|
||||||
btn.addEventListener("click", e => {
|
btn.addEventListener("click", (e) => {
|
||||||
menu.hidden = !menu.hidden;
|
menu.hidden = !menu.hidden;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -16,5 +15,4 @@ export class DropdownButton extends LitElement {
|
||||||
render() {
|
render() {
|
||||||
return html`<slot></slot>`;
|
return html`<slot></slot>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import { LitElement, html, customElement, property } from 'lit-element';
|
import { LitElement, html, customElement, property } from "lit-element";
|
||||||
|
|
||||||
interface ComparisonHash {
|
interface ComparisonHash {
|
||||||
[key: string]: (a: any, b: any) => boolean
|
[key: string]: (a: any, b: any) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("fetch-fill-slot")
|
@customElement("fetch-fill-slot")
|
||||||
export class FetchFillSlot extends LitElement {
|
export class FetchFillSlot extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
url: string = "";
|
url: string = "";
|
||||||
|
|
||||||
|
@ -18,14 +17,30 @@ export class FetchFillSlot extends LitElement {
|
||||||
|
|
||||||
comparison(slotName: string) {
|
comparison(slotName: string) {
|
||||||
let comparisonOperatorsHash = <ComparisonHash>{
|
let comparisonOperatorsHash = <ComparisonHash>{
|
||||||
'<': function (a: any, b: any) { return a < b; },
|
"<": function (a: any, b: any) {
|
||||||
'>': function (a: any, b: any) { return a > b; },
|
return a < b;
|
||||||
'>=': function (a: any, b: any) { return a >= b; },
|
},
|
||||||
'<=': function (a: any, b: any) { return a <= b; },
|
">": function (a: any, b: any) {
|
||||||
'==': function (a: any, b: any) { return a == b; },
|
return a > b;
|
||||||
'!=': function (a: any, b: any) { return a != b; },
|
},
|
||||||
'===': function (a: any, b: any) { return a === b; },
|
">=": function (a: any, b: any) {
|
||||||
'!==': function (a: any, b: any) { return a !== b; },
|
return a >= b;
|
||||||
|
},
|
||||||
|
"<=": function (a: any, b: any) {
|
||||||
|
return a <= b;
|
||||||
|
},
|
||||||
|
"==": function (a: any, b: any) {
|
||||||
|
return a == b;
|
||||||
|
},
|
||||||
|
"!=": function (a: any, b: any) {
|
||||||
|
return a != b;
|
||||||
|
},
|
||||||
|
"===": function (a: any, b: any) {
|
||||||
|
return a === b;
|
||||||
|
},
|
||||||
|
"!==": function (a: any, b: any) {
|
||||||
|
return a !== b;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const tokens = slotName.split(" ");
|
const tokens = slotName.split(" ");
|
||||||
if (tokens.length < 3) {
|
if (tokens.length < 3) {
|
||||||
|
@ -45,13 +60,16 @@ export class FetchFillSlot extends LitElement {
|
||||||
}
|
}
|
||||||
const comp = tokens[1];
|
const comp = tokens[1];
|
||||||
if (!(comp in comparisonOperatorsHash)) {
|
if (!(comp in comparisonOperatorsHash)) {
|
||||||
throw new Error("Invalid comparison")
|
throw new Error("Invalid comparison");
|
||||||
}
|
}
|
||||||
return comparisonOperatorsHash[comp](a, b);
|
return comparisonOperatorsHash[comp](a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
fetch(this.url).then(r => r.json()).then(r => r[this.key]).then(r => this.value = r);
|
fetch(this.url)
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((r) => r[this.key])
|
||||||
|
.then((r) => (this.value = r));
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -59,13 +77,13 @@ export class FetchFillSlot extends LitElement {
|
||||||
return html`<slot></slot>`;
|
return html`<slot></slot>`;
|
||||||
}
|
}
|
||||||
let selectedSlot = "";
|
let selectedSlot = "";
|
||||||
this.querySelectorAll("[slot]").forEach(slot => {
|
this.querySelectorAll("[slot]").forEach((slot) => {
|
||||||
const comp = slot.getAttribute("slot")!;
|
const comp = slot.getAttribute("slot")!;
|
||||||
if (this.comparison(comp)) {
|
if (this.comparison(comp)) {
|
||||||
selectedSlot = comp;
|
selectedSlot = comp;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.querySelectorAll("[data-value]").forEach(dv => {
|
this.querySelectorAll("[data-value]").forEach((dv) => {
|
||||||
dv.textContent = this.value;
|
dv.textContent = this.value;
|
||||||
});
|
});
|
||||||
return html`<slot name=${selectedSlot}></slot>`;
|
return html`<slot name=${selectedSlot}></slot>`;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { LitElement, html, customElement, property } from 'lit-element';
|
import { LitElement, html, customElement, property } from "lit-element";
|
||||||
|
|
||||||
const LEVEL_ICON_MAP: { [key: string]: string } = {
|
const LEVEL_ICON_MAP: { [key: string]: string } = {
|
||||||
"error": "fas fa-exclamation-circle",
|
error: "fas fa-exclamation-circle",
|
||||||
"warning": "fas fa-exclamation-triangle",
|
warning: "fas fa-exclamation-triangle",
|
||||||
"success": "fas fa-check-circle",
|
success: "fas fa-check-circle",
|
||||||
"info": "fas fa-info",
|
info: "fas fa-info",
|
||||||
};
|
};
|
||||||
|
|
||||||
let ID = function (prefix: string) {
|
let ID = function (prefix: string) {
|
||||||
|
@ -23,7 +23,6 @@ interface Message {
|
||||||
|
|
||||||
@customElement("pb-messages")
|
@customElement("pb-messages")
|
||||||
export class Messages extends LitElement {
|
export class Messages extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
url: string = "";
|
url: string = "";
|
||||||
|
|
||||||
|
@ -39,8 +38,13 @@ export class Messages extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMessages() {
|
fetchMessages() {
|
||||||
return fetch(this.url).then(r => r.json()).then(r => this.messages = r).then((r) => {
|
return fetch(this.url)
|
||||||
const container = <HTMLElement>this.querySelector(".pf-c-alert-group")!;
|
.then((r) => r.json())
|
||||||
|
.then((r) => (this.messages = r))
|
||||||
|
.then((r) => {
|
||||||
|
const container = <HTMLElement>(
|
||||||
|
this.querySelector(".pf-c-alert-group")!
|
||||||
|
);
|
||||||
r.forEach((message: Message) => {
|
r.forEach((message: Message) => {
|
||||||
const messageElement = this.renderMessage(message);
|
const messageElement = this.renderMessage(message);
|
||||||
container.appendChild(messageElement);
|
container.appendChild(messageElement);
|
||||||
|
@ -52,7 +56,9 @@ export class Messages extends LitElement {
|
||||||
const id = ID("pb-message");
|
const id = ID("pb-message");
|
||||||
const el = document.createElement("template");
|
const el = document.createElement("template");
|
||||||
el.innerHTML = `<li id=${id} class="pf-c-alert-group__item">
|
el.innerHTML = `<li id=${id} class="pf-c-alert-group__item">
|
||||||
<div class="pf-c-alert pf-m-${message.level_tag} ${message.level_tag === 'error' ? 'pf-m-danger': ''}">
|
<div class="pf-c-alert pf-m-${message.level_tag} ${
|
||||||
|
message.level_tag === "error" ? "pf-m-danger" : ""
|
||||||
|
}">
|
||||||
<div class="pf-c-alert__icon">
|
<div class="pf-c-alert__icon">
|
||||||
<i class="${LEVEL_ICON_MAP[message.level_tag]}"></i>
|
<i class="${LEVEL_ICON_MAP[message.level_tag]}"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { convertToSlug } from "../utils";
|
||||||
|
|
||||||
@customElement("pb-modal-button")
|
@customElement("pb-modal-button")
|
||||||
export class ModalButton extends LitElement {
|
export class ModalButton extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
href: string = "";
|
href: string = "";
|
||||||
|
|
||||||
|
@ -18,12 +17,12 @@ export class ModalButton extends LitElement {
|
||||||
open: boolean = false;
|
open: boolean = false;
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [ModalBoxStyle, BullseyeStyle, BackdropStyle]
|
return [ModalBoxStyle, BullseyeStyle, BackdropStyle];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
window.addEventListener("keyup", e => {
|
window.addEventListener("keyup", (e) => {
|
||||||
if (e.code === "Escape") {
|
if (e.code === "Escape") {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
}
|
}
|
||||||
|
@ -33,62 +32,83 @@ export class ModalButton extends LitElement {
|
||||||
setContent(content: string) {
|
setContent(content: string) {
|
||||||
this.querySelector("[slot=modal]")!.innerHTML = content;
|
this.querySelector("[slot=modal]")!.innerHTML = content;
|
||||||
// Ensure links close the modal
|
// Ensure links close the modal
|
||||||
this.querySelectorAll<HTMLAnchorElement>("[slot=modal] a").forEach(a => {
|
this.querySelectorAll<HTMLAnchorElement>("[slot=modal] a").forEach(
|
||||||
|
(a) => {
|
||||||
// Make click on a close the modal
|
// Make click on a close the modal
|
||||||
a.addEventListener("click", e => {
|
a.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.open = false;
|
this.open = false;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
// Make name field update slug field
|
// Make name field update slug field
|
||||||
this.querySelectorAll<HTMLInputElement>("input[name=name]").forEach((input) => {
|
this.querySelectorAll<HTMLInputElement>("input[name=name]").forEach(
|
||||||
|
(input) => {
|
||||||
input.addEventListener("input", (e) => {
|
input.addEventListener("input", (e) => {
|
||||||
const form = input.closest("form");
|
const form = input.closest("form");
|
||||||
if (form === null) {
|
if (form === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const slugField = form.querySelector<HTMLInputElement>("input[name=slug]");
|
const slugField = form.querySelector<HTMLInputElement>(
|
||||||
|
"input[name=slug]"
|
||||||
|
);
|
||||||
if (!slugField) {
|
if (!slugField) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
slugField.value = convertToSlug(input.value);
|
slugField.value = convertToSlug(input.value);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
// Ensure forms sends in AJAX
|
// Ensure forms sends in AJAX
|
||||||
this.querySelectorAll<HTMLFormElement>("[slot=modal] form").forEach(form => {
|
this.querySelectorAll<HTMLFormElement>("[slot=modal] form").forEach(
|
||||||
form.addEventListener('submit', (e) => {
|
(form) => {
|
||||||
|
form.addEventListener("submit", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let formData = new FormData(form);
|
let formData = new FormData(form);
|
||||||
fetch((form.action === window.location.toString()) ? this.href : form.action, {
|
fetch(
|
||||||
|
form.action === window.location.toString()
|
||||||
|
? this.href
|
||||||
|
: form.action,
|
||||||
|
{
|
||||||
method: form.method,
|
method: form.method,
|
||||||
body: formData,
|
body: formData,
|
||||||
}).then((response) => {
|
}
|
||||||
|
)
|
||||||
|
.then((response) => {
|
||||||
return response.text();
|
return response.text();
|
||||||
}).then(data => {
|
})
|
||||||
|
.then((data) => {
|
||||||
if (data.indexOf("csrfmiddlewaretoken") !== -1) {
|
if (data.indexOf("csrfmiddlewaretoken") !== -1) {
|
||||||
this.setContent(data);
|
this.setContent(data);
|
||||||
} else {
|
} else {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.dispatchEvent(new CustomEvent('hashchange', { bubbles: true }));
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("hashchange", {
|
||||||
|
bubbles: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
updateMessages();
|
updateMessages();
|
||||||
}
|
}
|
||||||
}).catch((e) => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick(e: MouseEvent) {
|
onClick(e: MouseEvent) {
|
||||||
const request = new Request(
|
const request = new Request(this.href);
|
||||||
this.href,
|
|
||||||
);
|
|
||||||
fetch(request, {
|
fetch(request, {
|
||||||
mode: 'same-origin',
|
mode: "same-origin",
|
||||||
}).then(r => r.text()).then((t) => {
|
})
|
||||||
|
.then((r) => r.text())
|
||||||
|
.then((t) => {
|
||||||
this.setContent(t);
|
this.setContent(t);
|
||||||
this.open = true;
|
this.open = true;
|
||||||
}).catch(e => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -96,21 +116,32 @@ export class ModalButton extends LitElement {
|
||||||
renderModal() {
|
renderModal() {
|
||||||
return html`<div class="pf-c-backdrop">
|
return html`<div class="pf-c-backdrop">
|
||||||
<div class="pf-l-bullseye">
|
<div class="pf-l-bullseye">
|
||||||
<div class="pf-c-modal-box pf-m-md" role="dialog" aria-modal="true" aria-labelledby="modal-md-title" aria-describedby="modal-md-description">
|
<div
|
||||||
<button @click=${() => this.open = false} class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
|
class="pf-c-modal-box pf-m-md"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby="modal-md-title"
|
||||||
|
aria-describedby="modal-md-description"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
@click=${() => (this.open = false)}
|
||||||
|
class="pf-c-button pf-m-plain"
|
||||||
|
type="button"
|
||||||
|
aria-label="Close dialog"
|
||||||
|
>
|
||||||
<i class="fas fa-times" aria-hidden="true"></i>
|
<i class="fas fa-times" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
<slot name="modal">
|
<slot name="modal"> </slot>
|
||||||
</slot>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html` <slot
|
||||||
<slot name="trigger" @click=${(e: any) => this.onClick(e)}></slot>
|
name="trigger"
|
||||||
|
@click=${(e: any) => this.onClick(e)}
|
||||||
|
></slot>
|
||||||
${this.open ? this.renderModal() : ""}`;
|
${this.open ? this.renderModal() : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
import { LitElement, html, customElement } from 'lit-element';
|
import { LitElement, html, customElement } from "lit-element";
|
||||||
|
|
||||||
@customElement("pb-tabs")
|
@customElement("pb-tabs")
|
||||||
export class Tabs extends LitElement {
|
export class Tabs extends LitElement {
|
||||||
|
|
||||||
_currentPage? = "";
|
_currentPage? = "";
|
||||||
_firstPage? = "";
|
_firstPage? = "";
|
||||||
|
|
||||||
get currentPage() {
|
get currentPage() {
|
||||||
return this._currentPage
|
return this._currentPage;
|
||||||
}
|
}
|
||||||
|
|
||||||
set currentPage(value) {
|
set currentPage(value) {
|
||||||
try {
|
try {
|
||||||
// Show active tab page
|
// Show active tab page
|
||||||
this.querySelector(`.pf-c-tab-content[tab-name='${value}']`)?.removeAttribute("hidden");
|
this.querySelector(
|
||||||
|
`.pf-c-tab-content[tab-name='${value}']`
|
||||||
|
)?.removeAttribute("hidden");
|
||||||
// Update active status on buttons
|
// Update active status on buttons
|
||||||
this.querySelector(`.pf-c-tabs__item[tab-name='${value}']`)?.classList.add("pf-m-current");
|
this.querySelector(
|
||||||
|
`.pf-c-tabs__item[tab-name='${value}']`
|
||||||
|
)?.classList.add("pf-m-current");
|
||||||
// Hide other tab pages
|
// Hide other tab pages
|
||||||
this.querySelectorAll(`.pf-c-tab-content:not([tab-name='${value}'])`).forEach((el) => {
|
this.querySelectorAll(
|
||||||
|
`.pf-c-tab-content:not([tab-name='${value}'])`
|
||||||
|
).forEach((el) => {
|
||||||
el.setAttribute("hidden", "");
|
el.setAttribute("hidden", "");
|
||||||
});
|
});
|
||||||
// Update active status on other buttons
|
// Update active status on other buttons
|
||||||
this.querySelectorAll(`.pf-c-tabs__item:not([tab-name='${value}'])`).forEach((el) => {
|
this.querySelectorAll(
|
||||||
|
`.pf-c-tabs__item:not([tab-name='${value}'])`
|
||||||
|
).forEach((el) => {
|
||||||
el.classList.remove("pf-m-current");
|
el.classList.remove("pf-m-current");
|
||||||
});
|
});
|
||||||
// Update window hash
|
// Update window hash
|
||||||
|
@ -37,7 +44,9 @@ export class Tabs extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this._firstPage = this.querySelector(".pf-c-tab-content")?.getAttribute("tab-name")!;
|
this._firstPage = this.querySelector(".pf-c-tab-content")?.getAttribute(
|
||||||
|
"tab-name"
|
||||||
|
)!;
|
||||||
if (window.location.hash) {
|
if (window.location.hash) {
|
||||||
this.currentPage = window.location.hash;
|
this.currentPage = window.location.hash;
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,8 +56,7 @@ export class Tabs extends LitElement {
|
||||||
button.addEventListener("click", (e) => {
|
button.addEventListener("click", (e) => {
|
||||||
let tabPage = button.parentElement?.getAttribute("tab-name")!;
|
let tabPage = button.parentElement?.getAttribute("tab-name")!;
|
||||||
this.currentPage = tabPage;
|
this.currentPage = tabPage;
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ document.querySelectorAll("input[type=search]").forEach((si) => {
|
||||||
document.querySelectorAll("[data-pb-fetch-fill]").forEach((el) => {
|
document.querySelectorAll("[data-pb-fetch-fill]").forEach((el) => {
|
||||||
const url = el.dataset.pbFetchFill;
|
const url = el.dataset.pbFetchFill;
|
||||||
const key = el.dataset.pbFetchKey;
|
const key = el.dataset.pbFetchKey;
|
||||||
fetch(url).then(r => r.json()).then(r => {
|
fetch(url)
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((r) => {
|
||||||
el.textContent = r[key];
|
el.textContent = r[key];
|
||||||
el.value = r[key];
|
el.value = r[key];
|
||||||
});
|
});
|
||||||
|
@ -21,13 +23,13 @@ document.querySelectorAll("[data-pb-fetch-fill]").forEach((el) => {
|
||||||
document.querySelectorAll("[data-target='modal']").forEach((m) => {
|
document.querySelectorAll("[data-target='modal']").forEach((m) => {
|
||||||
m.addEventListener("click", (e) => {
|
m.addEventListener("click", (e) => {
|
||||||
const parentContainer = e.target.closest('[data-target="modal"]');
|
const parentContainer = e.target.closest('[data-target="modal"]');
|
||||||
const modalId = parentContainer.attributes['data-modal'].value;
|
const modalId = parentContainer.attributes["data-modal"].value;
|
||||||
document.querySelector(`#${modalId}`).removeAttribute("hidden");
|
document.querySelector(`#${modalId}`).removeAttribute("hidden");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
document.querySelectorAll(".pf-c-modal-box [data-modal-close]").forEach((b) => {
|
document.querySelectorAll(".pf-c-modal-box [data-modal-close]").forEach((b) => {
|
||||||
b.addEventListener("click", (e) => {
|
b.addEventListener("click", (e) => {
|
||||||
const parentContainer = e.target.closest('.pf-c-backdrop');
|
const parentContainer = e.target.closest(".pf-c-backdrop");
|
||||||
parentContainer.setAttribute("hidden", true);
|
parentContainer.setAttribute("hidden", true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -35,13 +37,17 @@ document.querySelectorAll(".pf-c-modal-box [data-modal-close]").forEach((b) => {
|
||||||
// Make Checkbox label click trigger checkbox toggle
|
// Make Checkbox label click trigger checkbox toggle
|
||||||
document.querySelectorAll(".pf-c-check__label").forEach((checkLabel) => {
|
document.querySelectorAll(".pf-c-check__label").forEach((checkLabel) => {
|
||||||
checkLabel.addEventListener("click", (e) => {
|
checkLabel.addEventListener("click", (e) => {
|
||||||
const checkbox = e.target.parentElement.querySelector("input[type=checkbox]");
|
const checkbox = e.target.parentElement.querySelector(
|
||||||
|
"input[type=checkbox]"
|
||||||
|
);
|
||||||
checkbox.checked = !checkbox.checked;
|
checkbox.checked = !checkbox.checked;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hamburger Menu
|
// Hamburger Menu
|
||||||
document.querySelectorAll(".pf-c-page__header-brand-toggle>button").forEach((toggle) => {
|
document
|
||||||
|
.querySelectorAll(".pf-c-page__header-brand-toggle>button")
|
||||||
|
.forEach((toggle) => {
|
||||||
toggle.addEventListener("click", (e) => {
|
toggle.addEventListener("click", (e) => {
|
||||||
const sidebar = document.querySelector(".pf-c-page__sidebar");
|
const sidebar = document.querySelector(".pf-c-page__sidebar");
|
||||||
if (sidebar.classList.contains("pf-m-expanded")) {
|
if (sidebar.classList.contains("pf-m-expanded")) {
|
||||||
|
@ -54,12 +60,14 @@ document.querySelectorAll(".pf-c-page__header-brand-toggle>button").forEach((tog
|
||||||
sidebar.style.zIndex = 200;
|
sidebar.style.zIndex = 200;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Collapsable Menus in Sidebar
|
// Collapsable Menus in Sidebar
|
||||||
document.querySelectorAll(".pf-m-expandable>.pf-c-nav__link").forEach((menu) => {
|
document
|
||||||
|
.querySelectorAll(".pf-m-expandable>.pf-c-nav__link")
|
||||||
|
.forEach((menu) => {
|
||||||
menu.addEventListener("click", (e) => {
|
menu.addEventListener("click", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
menu.parentElement.classList.toggle("pf-m-expanded");
|
menu.parentElement.classList.toggle("pf-m-expanded");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import "./legacy.js";
|
import "./legacy.js";
|
||||||
|
|
||||||
import './elements/ActionButton';
|
import "./elements/ActionButton";
|
||||||
import './elements/AdminSidebar';
|
import "./elements/AdminSidebar";
|
||||||
import './elements/CodeMirror';
|
import "./elements/CodeMirror";
|
||||||
import './elements/Dropdown';
|
import "./elements/Dropdown";
|
||||||
import './elements/FetchFillSlot';
|
import "./elements/FetchFillSlot";
|
||||||
import './elements/Messages';
|
import "./elements/Messages";
|
||||||
import './elements/ModalButton';
|
import "./elements/ModalButton";
|
||||||
import './elements/Tabs';
|
import "./elements/Tabs";
|
||||||
import './pages/AdminSiteShell';
|
import "./pages/AdminSiteShell";
|
||||||
import './pages/FlowShellCard';
|
import "./pages/FlowShellCard";
|
||||||
import "./elements/AdminLoginsChart";
|
import "./elements/AdminLoginsChart";
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
import { css, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
import {
|
||||||
|
css,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit-element";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
|
import BullseyeStyle from "@patternfly/patternfly/layouts/Bullseye/bullseye.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -6,7 +13,6 @@ import SpinnerStyle from "@patternfly/patternfly/components/Spinner/spinner.css"
|
||||||
|
|
||||||
@customElement("pb-admin-shell")
|
@customElement("pb-admin-shell")
|
||||||
export class AdminSiteShell extends LitElement {
|
export class AdminSiteShell extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
set defaultUrl(value: string) {
|
set defaultUrl(value: string) {
|
||||||
if (window.location.hash === "" && value !== undefined) {
|
if (window.location.hash === "" && value !== undefined) {
|
||||||
|
@ -18,7 +24,8 @@ export class AdminSiteShell extends LitElement {
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [css`
|
return [
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +36,10 @@ export class AdminSiteShell extends LitElement {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
`, BullseyeStyle, SpinnerStyle];
|
`,
|
||||||
|
BullseyeStyle,
|
||||||
|
SpinnerStyle,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -41,14 +51,19 @@ export class AdminSiteShell extends LitElement {
|
||||||
loadContent() {
|
loadContent() {
|
||||||
let url = window.location.hash.slice(1, Infinity);
|
let url = window.location.hash.slice(1, Infinity);
|
||||||
if (url === "") {
|
if (url === "") {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
fetch(url).then(r => r.text()).then((t) => {
|
fetch(url)
|
||||||
|
.then((r) => r.text())
|
||||||
|
.then((t) => {
|
||||||
this.querySelector("[slot=body]")!.innerHTML = t;
|
this.querySelector("[slot=body]")!.innerHTML = t;
|
||||||
}).then(() => {
|
})
|
||||||
|
.then(() => {
|
||||||
// Ensure anchors only change the hash
|
// Ensure anchors only change the hash
|
||||||
this.querySelectorAll<HTMLAnchorElement>("a:not(.pb-root-link)").forEach(a => {
|
this.querySelectorAll<HTMLAnchorElement>(
|
||||||
|
"a:not(.pb-root-link)"
|
||||||
|
).forEach((a) => {
|
||||||
if (a.href === "") {
|
if (a.href === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -61,8 +76,8 @@ export class AdminSiteShell extends LitElement {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Create refresh buttons
|
// Create refresh buttons
|
||||||
this.querySelectorAll("[role=pb-refresh]").forEach(rt => {
|
this.querySelectorAll("[role=pb-refresh]").forEach((rt) => {
|
||||||
rt.addEventListener("click", e => {
|
rt.addEventListener("click", (e) => {
|
||||||
this.loadContent();
|
this.loadContent();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -71,19 +86,21 @@ export class AdminSiteShell extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html` ${this.loading
|
||||||
${this.loading ? html`
|
? html` <div class="pf-l-bullseye">
|
||||||
<div class="pf-l-bullseye">
|
|
||||||
<div class="pf-l-bullseye__item">
|
<div class="pf-l-bullseye__item">
|
||||||
<span class="pf-c-spinner pf-m-xl" role="progressbar" aria-valuetext="Loading...">
|
<span
|
||||||
|
class="pf-c-spinner pf-m-xl"
|
||||||
|
role="progressbar"
|
||||||
|
aria-valuetext="Loading..."
|
||||||
|
>
|
||||||
<span class="pf-c-spinner__clipper"></span>
|
<span class="pf-c-spinner__clipper"></span>
|
||||||
<span class="pf-c-spinner__lead-ball"></span>
|
<span class="pf-c-spinner__lead-ball"></span>
|
||||||
<span class="pf-c-spinner__tail-ball"></span>
|
<span class="pf-c-spinner__tail-ball"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>`: ""}
|
</div>`
|
||||||
<slot name="body">
|
: ""}
|
||||||
</slot>`;
|
<slot name="body"> </slot>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { LitElement, html, customElement, property } from 'lit-element';
|
import { LitElement, html, customElement, property } from "lit-element";
|
||||||
import { updateMessages } from "../elements/Messages";
|
import { updateMessages } from "../elements/Messages";
|
||||||
|
|
||||||
enum ResponseType {
|
enum ResponseType {
|
||||||
redirect = "redirect",
|
redirect = "redirect",
|
||||||
template = "template"
|
template = "template",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
|
@ -14,7 +14,6 @@ interface Response {
|
||||||
|
|
||||||
@customElement("pb-flow-shell-card")
|
@customElement("pb-flow-shell-card")
|
||||||
export class FlowShellCard extends LitElement {
|
export class FlowShellCard extends LitElement {
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
flowBodyUrl: string = "";
|
flowBodyUrl: string = "";
|
||||||
|
|
||||||
|
@ -26,16 +25,20 @@ export class FlowShellCard extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
fetch(this.flowBodyUrl).then(r => {
|
fetch(this.flowBodyUrl)
|
||||||
|
.then((r) => {
|
||||||
if (!r.ok) {
|
if (!r.ok) {
|
||||||
throw Error(r.statusText);
|
throw Error(r.statusText);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}).then((r) => {
|
})
|
||||||
|
.then((r) => {
|
||||||
return r.json();
|
return r.json();
|
||||||
}).then((r) => {
|
})
|
||||||
|
.then((r) => {
|
||||||
this.updateCard(r);
|
this.updateCard(r);
|
||||||
}).catch((e) => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
// Catch JSON or Update errors
|
// Catch JSON or Update errors
|
||||||
this.errorMessage(e);
|
this.errorMessage(e);
|
||||||
});
|
});
|
||||||
|
@ -54,13 +57,15 @@ export class FlowShellCard extends LitElement {
|
||||||
this.loadFormCode();
|
this.loadFormCode();
|
||||||
this.setFormSubmitHandlers();
|
this.setFormSubmitHandlers();
|
||||||
default:
|
default:
|
||||||
console.log(`passbook/flows: unexpected data type ${data.type}`);
|
console.log(
|
||||||
|
`passbook/flows: unexpected data type ${data.type}`
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
loadFormCode() {
|
loadFormCode() {
|
||||||
this.querySelectorAll("script").forEach(script => {
|
this.querySelectorAll("script").forEach((script) => {
|
||||||
let newScript = document.createElement("script");
|
let newScript = document.createElement("script");
|
||||||
newScript.src = script.src;
|
newScript.src = script.src;
|
||||||
document.head.appendChild(newScript);
|
document.head.appendChild(newScript);
|
||||||
|
@ -78,7 +83,9 @@ export class FlowShellCard extends LitElement {
|
||||||
for (let index = 0; index < form.elements.length; index++) {
|
for (let index = 0; index < form.elements.length; index++) {
|
||||||
const element = <HTMLInputElement>form.elements[index];
|
const element = <HTMLInputElement>form.elements[index];
|
||||||
if (element.value === form.action) {
|
if (element.value === form.action) {
|
||||||
console.log("passbook/flows: Found Form action URL in form elements, not changing form action.");
|
console.log(
|
||||||
|
"passbook/flows: Found Form action URL in form elements, not changing form action."
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,24 +101,29 @@ export class FlowShellCard extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
setFormSubmitHandlers() {
|
setFormSubmitHandlers() {
|
||||||
this.querySelectorAll("form").forEach(form => {
|
this.querySelectorAll("form").forEach((form) => {
|
||||||
console.log(`passbook/flows: Checking for autosubmit attribute ${form}`);
|
console.log(
|
||||||
|
`passbook/flows: Checking for autosubmit attribute ${form}`
|
||||||
|
);
|
||||||
this.checkAutosubmit(form);
|
this.checkAutosubmit(form);
|
||||||
console.log(`passbook/flows: Setting action for form ${form}`);
|
console.log(`passbook/flows: Setting action for form ${form}`);
|
||||||
this.updateFormAction(form);
|
this.updateFormAction(form);
|
||||||
console.log(`passbook/flows: Adding handler for form ${form}`);
|
console.log(`passbook/flows: Adding handler for form ${form}`);
|
||||||
form.addEventListener('submit', (e) => {
|
form.addEventListener("submit", (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let formData = new FormData(form);
|
let formData = new FormData(form);
|
||||||
this.flowBody = undefined;
|
this.flowBody = undefined;
|
||||||
fetch(this.flowBodyUrl, {
|
fetch(this.flowBodyUrl, {
|
||||||
method: 'post',
|
method: "post",
|
||||||
body: formData,
|
body: formData,
|
||||||
}).then((response) => {
|
})
|
||||||
return response.json()
|
.then((response) => {
|
||||||
}).then(data => {
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
this.updateCard(data);
|
this.updateCard(data);
|
||||||
}).catch((e) => {
|
})
|
||||||
|
.catch((e) => {
|
||||||
this.errorMessage(e);
|
this.errorMessage(e);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -141,9 +153,12 @@ export class FlowShellCard extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
loading() {
|
loading() {
|
||||||
return html`
|
return html` <div class="pf-c-login__main-body pb-loading">
|
||||||
<div class="pf-c-login__main-body pb-loading">
|
<span
|
||||||
<span class="pf-c-spinner" role="progressbar" aria-valuetext="Loading...">
|
class="pf-c-spinner"
|
||||||
|
role="progressbar"
|
||||||
|
aria-valuetext="Loading..."
|
||||||
|
>
|
||||||
<span class="pf-c-spinner__clipper"></span>
|
<span class="pf-c-spinner__clipper"></span>
|
||||||
<span class="pf-c-spinner__lead-ball"></span>
|
<span class="pf-c-spinner__lead-ball"></span>
|
||||||
<span class="pf-c-spinner__tail-ball"></span>
|
<span class="pf-c-spinner__tail-ball"></span>
|
||||||
|
@ -153,7 +168,7 @@ export class FlowShellCard extends LitElement {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.flowBody) {
|
if (this.flowBody) {
|
||||||
return html(<TemplateStringsArray><unknown>[this.flowBody]);
|
return html(<TemplateStringsArray>(<unknown>[this.flowBody]));
|
||||||
}
|
}
|
||||||
return this.loading();
|
return this.loading();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
export function getCookie(name: string) {
|
export function getCookie(name: string) {
|
||||||
let cookieValue = null;
|
let cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== '') {
|
if (document.cookie && document.cookie !== "") {
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(";");
|
||||||
for (let i = 0; i < cookies.length; i++) {
|
for (let i = 0; i < cookies.length; i++) {
|
||||||
const cookie = cookies[i].trim();
|
const cookie = cookies[i].trim();
|
||||||
// Does this cookie string begin with the name we want?
|
// Does this cookie string begin with the name we want?
|
||||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
if (cookie.substring(0, name.length + 1) === name + "=") {
|
||||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
cookieValue = decodeURIComponent(
|
||||||
|
cookie.substring(name.length + 1)
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +19,6 @@ export function getCookie(name: string) {
|
||||||
export function convertToSlug(text: string): string {
|
export function convertToSlug(text: string): string {
|
||||||
return text
|
return text
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/ /g, '-')
|
.replace(/ /g, "-")
|
||||||
.replace(/[^\w-]+/g, '');
|
.replace(/[^\w-]+/g, "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,6 @@
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"module": "es2015",
|
"module": "es2015",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"lib": [
|
"lib": ["es2017", "dom", "dom.iterable"]
|
||||||
"es2017",
|
|
||||||
"dom",
|
|
||||||
"dom.iterable"
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue