adding kirby3-janitor
This commit is contained in:
296
site/plugins/kirby3-janitor/src/components/fields/Janitor.vue
Executable file
296
site/plugins/kirby3-janitor/src/components/fields/Janitor.vue
Executable 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>
|
||||
11
site/plugins/kirby3-janitor/src/index.js
Executable file
11
site/plugins/kirby3-janitor/src/index.js
Executable 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>',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user