1
0

adding kirby3-janitor

This commit is contained in:
Philip Wagner
2024-10-14 14:22:24 +02:00
parent b0db09492d
commit 94fbb996f0
204 changed files with 27855 additions and 4 deletions

View File

@@ -0,0 +1,296 @@
<template>
<div class="janitor-wrapper">
<k-button
:id="id"
:class="['janitor', button.state]"
:icon="currentIcon"
:job="job"
:disabled="!isUnsaved && hasChanges"
@click="runJanitor"
>
{{ button.label || label }}
</k-button>
<a
v-show="downloadRequest"
ref="downloadAnchor"
class="visually-hidden"
:href="downloadRequest"
download
/>
<a
v-show="urlRequest"
ref="tabAnchor"
class="visually-hidden"
:href="urlRequest"
target="_blank"
/>
</div>
</template>
<script>
const STORAGE_ID = "janitor.runAfterAutosave";
export default {
props: {
label: String,
progress: String,
job: String,
cooldown: Number,
status: String,
data: String,
pageURI: String,
clipboard: Boolean,
unsaved: Boolean,
autosave: Boolean,
intab: Boolean,
confirm: String,
icon: {
type: [Boolean, String],
default: false,
},
},
data() {
return {
button: {
label: null,
state: null,
},
downloadRequest: null,
clipboardRequest: null,
urlRequest: null,
isUnsaved: false,
icons: {
"is-running": "janitorLoader",
"is-success": "check",
"has-error": "alert",
},
};
},
computed: {
id() {
return (
"janitor-" +
this.hashCode(this.job + (this.button.label ?? "") + this.pageURI)
);
},
hasChanges() {
return this.$store.getters["content/hasChanges"]();
},
currentIcon() {
return this.icons[this.status] ?? this.icon;
},
},
created() {
this.$events.$on(
"model.update",
() => sessionStorage.getItem(STORAGE_ID) && location.reload()
);
if (sessionStorage.getItem(STORAGE_ID) === this.id) {
sessionStorage.removeItem(STORAGE_ID);
this.runJanitor();
}
},
methods: {
/**
* Source: https://stackoverflow.com/a/8831937
*/
hashCode(str) {
let hash = 0;
if (str.length === 0) {
return hash;
}
for (const i of str) {
hash = (hash << 5) - hash + str.charCodeAt(i);
// convert to 32bit integer
hash = hash & hash;
}
return hash;
},
async runJanitor() {
if (this.confirm && !window.confirm(this.confirm)) {
return;
}
if (this.autosave && this.hasChanges) {
// lock janitor button, press save and listen to `model.update` event
const saveButton = document.querySelector(
".k-panel .k-form-buttons .k-view"
).lastChild;
// revert & save
if (saveButton) {
this.isUnsaved = false;
sessionStorage.setItem(STORAGE_ID, this.id);
this.simulateClick(saveButton);
return;
}
}
if (this.clipboard) {
this.clipboardRequest = this.data;
this.button.label = this.progress;
this.button.state = "is-success";
setTimeout(this.resetButton, this.cooldown);
this.$nextTick(() => {
this.copyToClipboard(this.data);
});
return;
}
if (this.clipboardRequest) {
await this.copyToClipboard(this.clipboardRequest);
this.resetButton();
this.clipboardRequest = null;
return;
}
if (this.status) {
return;
}
let url = this.job + "/" + encodeURIComponent(this.pageURI);
if (this.data) {
url = url + "/" + encodeURIComponent(this.data);
}
this.getRequest(url);
},
async getRequest(url) {
this.button.label = this.progress ?? `${this.label}`;
this.button.state = "is-running";
const { label, status, reload, href, download, clipboard } =
await this.$api.get(url);
if (label) {
this.button.label = label;
}
if (status) {
this.button.state = status === 200 ? "is-success" : "has-error";
} else {
this.button.state = "has-response";
}
if (reload) {
location.reload();
}
if (href) {
if (this.intab) {
this.urlRequest = href;
this.$nextTick(() => {
this.simulateClick(this.$refs.tabAnchor);
});
} else {
location.href = href;
}
}
if (download) {
this.downloadRequest = download;
this.$nextTick(() => {
this.simulateClick(this.$refs.downloadAnchor);
});
}
if (clipboard) {
this.clipboardRequest = clipboard;
} else {
setTimeout(this.resetButton, this.cooldown);
}
},
resetButton() {
this.button.label = null;
this.button.state = null;
},
simulateClick(element) {
const evt = new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window,
});
element.dispatchEvent(evt);
},
async copyToClipboard(content) {
try {
await navigator.clipboard.writeText(content);
} catch (err) {
console.error("navigator.clipboard is not available");
}
},
},
};
</script>
<style>
.janitor {
background-color: var(--color-text);
color: white;
border-radius: 3px;
padding: 0.5rem 1rem;
line-height: 1.25rem;
text-align: left;
}
.janitor:hover {
background-color: #222;
}
.janitor .k-button-text {
opacity: 1;
}
.janitor.is-running {
background-color: var(--color-border);
}
.janitor.is-running .k-button-text {
color: var(--color-text);
}
.janitor.has-response {
background-color: var(--color-text);
}
.janitor.is-success {
background-color: var(--color-positive);
}
.janitor.has-error {
background-color: var(--color-negative-light);
}
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
border: 0;
padding: 0;
margin: 0;
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,11 @@
import Janitor from "./components/fields/Janitor.vue";
window.panel.plugin("bnomei/janitor", {
fields: {
janitor: Janitor,
},
icons: {
janitorLoader:
'<g fill="none" fill-rule="evenodd"><g transform="translate(1 1)" stroke-width="1.75"><circle cx="7" cy="7" r="7.2" stroke="#000" stroke-opacity=".2"/><path d="M14.2,7c0-4-3.2-7.2-7.2-7.2" stroke="#000"><animateTransform attributeName="transform" type="rotate" from="0 7 7" to="360 7 7" dur="1s" repeatCount="indefinite"/></path></g></g>',
},
});