- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
Piranha 和 Vue 非常新,但不是 .Net Core。试图让我了解如何创建自定义块。我创建了一个新块,试图将 HtmlBlock 和 ImageBlock 结合起来:
using Piranha.Extend;
using Piranha.Extend.Blocks;
using Piranha.Extend.Fields;
namespace YR.Models.Piranha.Blocks
{
[BlockType(Name = "Card", Category = "Content", Icon = "fas fa-address-card", Component = "card-block")]
public class CardBlock : Block
{
public ImageField ImgBody { get; set; }
public SelectField<ImageAspect> Aspect { get; set; } = new SelectField<ImageAspect>();
public HtmlField HtmlBody { get; set; }
public override string GetTitle()
{
if (ImgBody != null && ImgBody.Media != null)
{
return ImgBody.Media.Filename;
}
return "No image selected";
}
}
}
如果我在 BlockTypeAttribute 中省略 Component 属性,则块会起作用,将图像和内容保存为草稿,并在发布时完美更新站点。为了在管理器中获得完整的体验,我还尝试构建一个 Vue 组件,该组件仅结合了 html-block.vue 和 image-block.vue 组件。
Vue.component("card-block", {
props: ["uid", "toolbar", "model"],
data: function () {
return {
imgBody: this.model.imgBody.value,
htmlBody: this.model.htmlBody.value
};
},
methods: {
clear: function () {
// clear media from block
},
onBlur: function (e) {
this.model.htmlBody.value = e.target.innerHTML;
},
onChange: function (data) {
this.model.htmlBody.value = data;
},
remove: function () {
this.model.imgBody.id = null;
this.model.imgBody.media = null;
},
select: function () {
if (this.model.imgBody.media != null) {
piranha.mediapicker.open(this.update, "Image", this.model.imgBody.media.folderId);
} else {
piranha.mediapicker.openCurrentFolder(this.update, "Image");
}
},
update: function (media) {
if (media.type === "Image") {
this.model.imgBody.id = media.id;
this.model.imgBody.media = media;
// Tell parent that title has been updated
this.$emit('update-title', {
uid: this.uid,
title: this.model.imgBody.media.filename
});
} else {
console.log("No image was selected");
}
}
},
computed: {
isEmpty: function () {
return {
htmlBody: piranha.utils.isEmptyHtml(this.model.htmlBody.value),
imgBody: this.model.imgBody.media == null
}
},
mediaUrl: function () {
if (this.model.imgBody.media != null) {
return piranha.utils.formatUrl(this.model.imgBody.media.publicUrl);
} else {
return piranha.utils.formatUrl("~/manager/assets/img/empty-image.png");
}
}
},
mounted: function () {
piranha.editor.addInline(this.uid, this.toolbar, this.onChange);
this.model.imgBody.getTitle = function () {
if (this.model.imgBody.media != null) {
return this.model.imgBody.media.filename;
} else {
return "No image selected";
}
};
},
beforeDestroy: function () {
piranha.editor.remove(this.uid);
},
template:
"<div class='block-body has-media-picker rounded' :class='{ empty: isEmpty }'>" +
" <img class='rounded' :src='mediaUrl'>" +
" <div class='media-picker'>" +
" <div class='btn-group float-right'>" +
" <button :id='uid' class='btn btn-info btn-aspect text-center' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>" +
" <i v-if='model.aspect.value === 0' class='fas fa-cog'></i>" +
" <img v-else :src='iconUrl'>" +
" </button>" +
" <div class='dropdown-menu aspect-menu' :aria-labelledby='uid'>" +
" <label class='mb-0'>{{ piranha.resources.texts.aspectLabel }}</label>" +
" <div class='dropdown-divider'></div>" +
" <a v-on:click.prevent='selectAspect(0)' class='dropdown-item' :class='{ active: isAspectSelected(0) }' href='#'>" +
" <img :src='piranha.utils.formatUrl('~/manager/assets/img/icons/img-original.svg')'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(1)' class='dropdown-item' :class='{ active: isAspectSelected(1) }' href='#'>" +
" <img :src='piranha.utils.formatUrl('~/manager/assets/img/icons/img-original.svg')'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(2)' class='dropdown-item' :class='{ active: isAspectSelected(2) }' href='#'>" +
" <img :src='piranha.utils.formatUrl('~/manager/assets/img/icons/img-original.svg')'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(3)' class='dropdown-item' :class='{ active: isAspectSelected(3) }' href='#'>" +
" <img :src='piranha.utils.formatUrl('~/manager/assets/img/icons/img-original.svg')'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(4)' class='dropdown-item' :class='{ active: isAspectSelected(4) }' href='#'>" +
" <img :src='piranha.utils.formatUrl('~/manager/assets/img/icons/img-original.svg')'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" </div>" +
" <button v-on:click.prevent='select' class='btn btn-primary text-center'>" +
" <i class='fas fa-plus'></i>" +
" </button>" +
" <button v-on:click.prevent='remove' class='btn btn-danger text-center'>" +
" <i class='fas fa-times'></i>" +
" </button>" +
" </div>" +
" <div class='card text-left'>" +
" <div class='card-body' v-if='isEmpty'>" +
" " +
" </div>" +
" <div class='card-body' v-else>" +
" {{ model.body.media.filename }}" +
" </div>" +
" </div>" +
"</div>" +
" <div contenteditable='true' :id='uid' spellcheck='false' v-html='htmlBody' v-on:blur='onBlur'></div>" +
"</div>"
});
它基本上是我在 GitHub 上的 repo 中找到的两个 Vue 组件的融合,但我对其进行了一些调整以使其不会在 DevTools 控制台中吐出错误。如果我能通过保存它们,我会重新审视这些项目。
最佳答案
以防万一这对某人有帮助。事实证明,我在将两个块合并在一起时做得很差。将此归结为对 Piranha 和 Vue.js 缺乏经验。我将文档中的代码与 repo 中的代码混合在一起。不要那样做 - 可以理解的是,文档仍然有点落后。我不是在向开发人员扔石头,我真的在挖掘他们创造的东西,并将继续努力熟练地使用它。
下面是我为 Vue 组件设计的。可能仍然需要进行一些调整以更好地分离 Image-Block 和 Html-Block 代码,但它现在可以工作、保存并且不会在控制台中引发错误。
/*global
piranha
*/
Vue.component("card-block", {
props: ["uid", "toolbar", "model"],
data: function () {
return {
imgBody: this.model.imgBody.value,
htmlBody: this.model.htmlBody.value
};
},
methods: {
clear: function () {
// clear media from block
},
onBlur: function (e) {
this.model.htmlBody.value = e.target.innerHTML;
},
onChange: function (data) {
this.model.htmlBody.value = data;
},
select: function () {
if (this.model.imgBody.media != null) {
piranha.mediapicker.open(this.update, "Image", this.model.imgBody.media.folderId);
} else {
piranha.mediapicker.openCurrentFolder(this.update, "Image");
}
},
remove: function () {
this.model.imgBody.id = null;
this.model.imgBody.media = null;
},
update: function (media) {
if (media.type === "Image") {
this.model.imgBody.id = media.id;
this.model.imgBody.media = {
id: media.id,
folderId: media.folderId,
type: media.type,
filename: media.filename,
contentType: media.contentType,
publicUrl: media.publicUrl,
};
// Tell parent that title has been updated
this.$emit('update-title', {
uid: this.uid,
title: this.model.imgBody.media.filename
});
} else {
console.log("No image was selected");
}
},
selectAspect: function (val) {
this.model.aspect.value = val;
},
isAspectSelected(val) {
return this.model.aspect.value === val;
}
},
computed: {
isImgEmpty: function (e) {
return this.model.imgBody.media == null;
},
isHtmlEmpty: function () {
return piranha.utils.isEmptyHtml(this.model.htmlBody.value);
},
mediaUrl: function () {
if (this.model.imgBody.media != null) {
return piranha.utils.formatUrl(this.model.imgBody.media.publicUrl);
} else {
return piranha.utils.formatUrl("~/manager/assets/img/empty-image.png");
}
},
iconUrl: function () {
if (this.model.aspect.value > 0) {
if (this.model.aspect.value === 1 || this.model.aspect.value === 3) {
return piranha.utils.formatUrl("~/manager/assets/img/icons/img-landscape.svg");
} else if (this.model.aspect.value == 2) {
return piranha.utils.formatUrl("~/manager/assets/img/icons/img-portrait.svg");
} else if (this.model.aspect.value == 4) {
return piranha.utils.formatUrl("~/manager/assets/img/icons/img-square.svg");
}
}
return null;
}
},
mounted: function () {
piranha.editor.addInline(this.uid, this.toolbar, this.onChange);
this.model.getTitle = function () {
if (this.model.imgBody.media != null) {
return this.model.imgBody.media.filename;
} else {
return "No image selected";
}
};
},
beforeDestroy: function () {
piranha.editor.remove(this.uid);
},
template:
"<div class='block-body has-media-picker rounded' :class='{ empty: isImgEmpty }'>" +
" <div class='image-block'>" +
" <img class='rounded' :src='mediaUrl'>" +
" <div class='media-picker'>" +
" <div class='btn-group float-right'>" +
" <button :id='uid + \"-aspect\"' class='btn btn-info btn-aspect text-center' data-toggle='dropdown' aria-haspopup='true' aria-expanded='false'>" +
" <i v-if='model.aspect.value === 0' class='fas fa-cog'></i>" +
" <img v-else :src='iconUrl'>" +
" </button>" +
" <div class='dropdown-menu aspect-menu' :aria-labelledby='uid + \"-aspect\"'>" +
" <label class='mb-0'>{{ piranha.resources.texts.aspectLabel }}</label>" +
" <div class='dropdown-divider'></div>" +
" <a v-on:click.prevent='selectAspect(0)' class='dropdown-item' :class='{ active: isAspectSelected(0) }' href='#'>" +
" <img :src='piranha.utils.formatUrl(\"~/manager/assets/img/icons/img-original.svg\")'><span>{{ piranha.resources.texts.aspectOriginal }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(1)' class='dropdown-item' :class='{ active: isAspectSelected(1) }' href='#'>" +
" <img :src='piranha.utils.formatUrl(\"~/manager/assets/img/icons/img-landscape.svg\")'><span>{{ piranha.resources.texts.aspectLandscape }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(2)' class='dropdown-item' :class='{ active: isAspectSelected(2) }' href='#'>" +
" <img :src='piranha.utils.formatUrl(\"~/manager/assets/img/icons/img-portrait.svg\")'><span>{{ piranha.resources.texts.aspectPortrait }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(3)' class='dropdown-item' :class='{ active: isAspectSelected(3) }' href='#'>" +
" <img :src='piranha.utils.formatUrl(\"~/manager/assets/img/icons/img-landscape.svg\")'><span>{{ piranha.resources.texts.aspectWidescreen }}</span>" +
" </a>" +
" <a v-on:click.prevent='selectAspect(4)' class='dropdown-item' :class='{ active: isAspectSelected(4) }' href='#'>" +
" <img :src='piranha.utils.formatUrl(\"~/manager/assets/img/icons/img-square.svg\")'><span>{{ piranha.resources.texts.aspectSquare }}</span>" +
" </a>" +
" </div>" +
" <button v-on:click.prevent='select' class='btn btn-primary text-center'>" +
" <i class='fas fa-plus'></i>" +
" </button>" +
" <button v-on:click.prevent='remove' class='btn btn-danger text-center'>" +
" <i class='fas fa-times'></i>" +
" </button>" +
" </div>" +
" <div class='card text-left'>" +
" <div class='card-body' v-if='isImgEmpty'>" +
" " +
" </div>" +
" <div class='card-body' v-else>" +
" {{ model.imgBody.media.filename }}" +
" </div>" +
" </div>" +
" </div>" +
" </div>" +
" <br />" +
" <div class='html-block'>" +
" <div class='block-body border rounded' :class='{ empty: isHtmlEmpty }' >" +
" <div contenteditable='true' :id='uid' v-html='htmlBody' v-on:blur='onBlur'></div> " +
" </div>" +
" </div>" +
"</div>"
});
我仍然很想得到一些确认,我没有不必要地做所有这些。如果有更好的方法来完成它,请不要退缩。
关于piranha-cms - Piranha CMS - 自定义 block 不会保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64976918/
Episerver CMS,我想使用 CMS 发布一个简单的通知模式。我不熟悉 CMS。是否有一些网站可以指导我了解 Episerver CMS 的工作原理。向移动网站发布新内容和新模式 最佳答案 您
我喜欢 Drupal 中的分类法,并考虑在其上为一个已经上线多年的网站构建一个 CMS。我想保留数据库原样(它是 mySQL),以确保旧的 CMS 也能正常工作 - 一些使用它的人不愿意学习新东西。相
我正在使用 DjnagoCMS 3,但所有编辑弹出窗口都有烦人的问题。当页面内容大于(高于)浏览器窗口时会发生这种情况。当我尝试编辑文本或任何 cms 插件(双击内容)时,它会显示弹出窗口,但它的高度
我正在按照官方 Introductory Tutorial 创建一个带有 Django-Cms 的网站。我在前端的编辑模式上遇到了一些问题。首先,顶部横幅没有显示,占位符上的编辑菜单全部损坏。 我做的
我按照说明在我的 Mac 上安装了 Django CMS。当我运行“manage.py cms check”时,一切正常,只是它说找不到 template_1.html。当我进入管理员创建页面时,模板
我是 Django 的新手....经过几个小时的努力,我设法在虚拟环境中安装了 django cms。创建一些模板并将一些页面添加到我的 cms。现在我正在尝试添加一些 css....我已经创建了一个
运行 django-cms 2.4.0-RC1、django 1.5.1 和 python 2.7 的全新安装。我正在尝试使用单个字段创建一个非常简单的自定义插件。该插件在管理员中注册并且工作正常。它
我意识到 django-cms 的重点是没有内容类型并将所有内容都视为页面,但暂时忽略这一点,我将如何将它们添加到 django-cms 中?通过“内容类型”,我的意思是一些行为很像 Page 对象的
我按照说明在我的 Mac 上安装了 Django CMS。当我运行“manage.py cms check”时,一切正常,只是它说找不到 template_1.html。当我进入管理员创建页面时,模板
我正在为客户创建一个 django-cms 站点。我想做类似的事情: 想要的效果是有一个地方,CMS 的用户可以为页面选择背景图像。理想情况下,他们会选择使用类似 Filer 的现有图片。 . 有没
我们在 Django-CMS 中构建了一个网站,并开发了一个带有替代 CSS 的移动版本以适应较小的查看区域。除了通常的导航栏外,我们还希望在每个页面的底部包含下一页和上一页链接。 我知道如何使用这段
这是我在管理模式下尝试更改页面的高级设置时遇到的错误: TypeError at /admin/cms/page/5/advanced-settings/ __str__ returned non-s
我有一个 Orchard CMS 应用程序。我想在主页之外创建多个页面。我想在其他页面上显示一个菜单。用户登录时,应根据其角色显示菜单。有人可以给我解决方案吗? 最佳答案 您可以通过选择 在管理仪表板
如何在 Bolt 中列出分类法中的所有术语?不是应用于记录的术语而是所有现有术语(如标签云或类别列表侧边菜单)? 最佳答案 直接在模板中,可以这样做: {% for category in app.c
我正在构建一个非常简单的网络托管服务,以满足 ma 和 pa 类型的小型企业的需求。 现在我的两难选择是我应该从头开始构建它还是使用现有的 CMS。 CMS 需要可定制,因为我希望构建自己的客户端。我
我有文档类型产品,字段为:图像和文本。我想使用 CMS 转发器将 webpart 添加到 kentico,显示所有文档产品,但我想只显示包含图像的文档(不需要字段图像)。我添加了一行 WhereCon
我目前正在为我的个人项目开发一个非常基础的 CMS。这对我自己的教育和任何事情一样重要。我的一个问题是如何在没有文件扩展名的情况下实现 url/永久链接。我了解使用获取变量从数据库中提取数据,但是如何
Piranha 和 Vue 非常新,但不是 .Net Core。试图让我了解如何创建自定义块。我创建了一个新块,试图将 HtmlBlock 和 ImageBlock 结合起来: using Piran
我有两对不同的 CMS 和 CDS。一个在本地网络上,一个在公共(public)域上。我正在向本地网络上的 CMS 添加新的目标类型。此新目标类型的属性包含位于公共(public)域中的 CDS 的
我想使用一些基于 ASP.NET 的 CMS 来创建我的网站,但不知道该选择哪个... 我在 Sitefinity 中开始它,但是很难按照您想要的方式管理代码...并且它会生成 ASP.NET Web
我是一名优秀的程序员,十分优秀!