bntwmrt
November 9, 2021, 10:42am
1
Hi,
After this question
Hi,
In the panel how to make a block that injects the content of another page into the editor?
For example I have member pages and I want to add a member’s biography + avatar in a block.
I cooked my own without manual mode and I want to edit the text in the block (.k-block-type-card-text
).
panel.plugin("cookbook/block-factory", {
blocks: {
card: {
data() {
return {
text: "No text value"
};
},
computed: {
heading() {
return this.page.text;
},
image() {
return this.page.image || {}
},
pageId() {
return this.page ? this.page.id : '';
},
page() {
return this.content.page[0] || {};
},
},
watch: {
"page": {
handler (value) {
if(this.pageId) {
this.$api.get('pages/' + this.pageId.replace('/', '+')).then(page => {
this.text = page.content.text.replace(/(<([^>]+)>)/gi, "") || this.text;
});
}
},
immediate: true
}
},
template: `
<div @dblclick="open">
<k-aspect-ratio
class="k-block-type-card-image"
cover="true"
ratio="1/1"
>
<img
v-if="image.url"
:src="image.url"
alt=""
>
</k-aspect-ratio>
<h2 class="k-block-type-card-heading">{{ heading }}</h2>
<div class="k-block-type-card-text">{{ text }}</div>
</div>
`
},
}
});
card.yml is short
name: field.blocks.card.name
icon: image
fields:
page:
type: pages
max: 1
query: kirby.page('photography').children.listed
I don’t know where I can make it editable (and I don’t want to edit the original ‘photography’ post).
Hm, you would probably need additional fields where you can actually store the content. So you would have to fill a new editable field with the response from the API and then store this field in the block in addition to the page id (which is currently the only value that is stored, the rest is fetch dynamically).
OK, add the field in card.yml I can do this, but for the next step, I don’t know where.
Is it in computed :
?
Hm, filling the new fields is not the problem, but I don’t really know how to decouple them from the watcher which will immediately undo every change.
So I need to do some tricky-ugly JS to fetch content ?
Let’s assume you add two new fields to your card.yml
name: field.blocks.card.name
icon: image
fields:
page:
type: pages
max: 1
query: kirby.page('photography').children.listed
heading:
type: writer
inline: true
text:
type: writer
inline: false
Then you can fill them with the content from the page:
panel.plugin("cookbook/block-factory", {
blocks: {
card: {
data() {
return {
};
},
computed: {
image() {
return this.page.image || {}
},
pageId() {
return this.page ? this.page.id : '';
},
page() {
return this.content.page[0] || {};
},
headingField() {
return this.field("heading");
},
textField() {
return this.field("text");
}
},
watch: {
"page": {
handler (value) {
if(this.pageId) {
this.$api.get('pages/' + this.pageId.replace('/', '+')).then(page => {
this.content.text = page.content.text.replace(/(<([^>]+)>)/gi, "") || '';
this.content.heading = page.content.title.replace(/(<([^>]+)>)/gi, "") || '';
});
}
},
immediate: true
}
},
template: `
<div @dblclick="open">
<k-aspect-ratio
class="k-block-type-card-image"
cover="true"
ratio="1/1"
>
<img
v-if="image.url"
:src="image.url"
alt=""
>
</k-aspect-ratio>
<h2 class="k-block-type-card-heading"">
<k-writer
ref="heading"
:inline="headingField.inline"
:marks="headingField.marks"
:placeholder="headingField.placeholder || 'Add a heading'"
:value="content.heading"
@input="update({ heading: $event })"
/>
</h2>
<div class="k-block-type-card-text">
<k-writer
ref="text"
:inline="textField.inline"
:marks="textField.marks"
:placeholder="textField.placeholder || 'Add some text'"
:value="content.text"
@input="update({ text: $event })"
/>
</div>
</div>
`
},
}
});
But this misses a mechanism to stop the API call in the watcher, unless the page field really changes.
So you need some conditions that empty those fields again when the page field is empty etc.
This seems to work as expected:
watch: {
"page": {
handler (value) {
if(typeof value.id === 'undefined') {
this.content.text = '';
this.content.heading = '';
}
if(this.pageId) {
this.$api.get('pages/' + this.pageId.replace('/', '+')).then(page => {
if (value.id === page.id && this.content.text !== '') {
this.content.text = this.content.text;
this.content.heading = this.content.heading;
} else {
this.content.text = page.content.text.replace(/(<([^>]+)>)/gi, "") || '';
this.content.heading = page.content.title.replace(/(<([^>]+)>)/gi, "") || '';
}
});
}
},
immediate: true
}
},
Maybe refine conditions a bit.
1 Like
Wow! It’s perfect!
Try to understand, what is this.content
?
Is there a video/doc about computed and watch?
I think I need to rewatch this Kirby 3: Field Plugin Intro - YouTube