How to remove image plugin from Ckeditor4 in vuejs code - vue.js

I am trying to remove the image plugin from ckeditor4 in my vue code below is the code.
<ckeditor v-model="description" :config="editorConfig" name="description"></ckeditor>
import CKEditor from 'ckeditor4-vue';
export default {
components: { ckeditor: CKEditor.component },
data: () => ({
formData : {
description : "",
},
editorConfig: {
removePlugins: [['Image']]
}
}),
}
but the image plugin is not being removed from my ckeditor. I want to keep all other plugins as it is.
kindly suggest the correct way.

Related

TipTap Vue custom component selects the entire line, not the selected one

I will immediately introduce the custom extension Tag.js
import { mergeAttributes, Node } from "#tiptap/core";
import { VueNodeViewRenderer } from "#tiptap/vue-3";
import { markInputRule } from "#tiptap/core";
import { markPasteRule } from "#tiptap/core";
import Component from "~/components/Editor/Tag.vue";
const starInputRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))$/;
const starPasteRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))/g;
const underscoreInputRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))$/;
const underscorePasteRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))/g;
export default Node.create({
name: "vuetag",
group: "block",
content: "inline*",
selectable: true,
parseHTML() {
return [
{
tag: "tag",
},
];
},
renderHTML({ HTMLAttributes }) {
return ["tag", mergeAttributes(HTMLAttributes), 0];
},
addNodeView() {
return VueNodeViewRenderer(Component);
},
addInputRules() {
return [
markInputRule({
find: starInputRegex,
type: this.type,
}),
markInputRule({
find: underscoreInputRegex,
type: this.type,
}),
];
},
addPasteRules() {
return [
markPasteRule({
find: starPasteRegex,
type: this.type,
}),
markPasteRule({
find: underscorePasteRegex,
type: this.type,
}),
];
},
addCommands() {
return {
setTag:
() =>
({ commands }) => {
return commands.setNode(this.name);
},
};
},
});
Component Tag.vue
<template>
<node-view-wrapper>
<el-tag><node-view-content /></el-tag>
</node-view-wrapper>
</template>
<script>
import { NodeViewContent, nodeViewProps, NodeViewWrapper } from "#tiptap/vue-3";
export default {
components: {
NodeViewWrapper,
NodeViewContent,
},
props: nodeViewProps,
};
</script>
<style lang="scss"></style>
There is a text: Did you see that? That’s a Vue component. We are really living in the future.
Let's say I want the phrase Did you see that? specify as a tag. I highlight this phrase and click on the button, the event setTag() is triggered
The result I get is this:<tag>Did you see that? That’s a Vue component. We are really living in the future.</tag>
The problem is that here the whole one line becomes a tag, that is, inside the Tag component.Vue
And there should be such a result: <tag>Did you see that?</tag> That’s a Vue component. We are really living in the future.
As an el-tag, I took from https://element-plus.org/en-US/component/tag.html

How to uses stories in stories.js files from Storybook in a component.vue Vue js project?

Hello I just create my first Vue project using Vue CLI and added Storybook to it. I have by default the file index.stories.js in my stories folder. And I want to use the "withText" button in my component but I don't know how. This is what the default file looks like: (you can dm me if I'm not notified)
import { action } from '#storybook/addon-actions'
import { linkTo } from '#storybook/addon-links'
import MyButton from '../components/MyButton.vue'
export default {
title: 'Button',
}
export const withText = () => ({
components: { MyButton },
template: '<my-button #click="action">Hello Button</my-button>',
methods: { action: action('clicked') }
})
export const withJSX = () => ({
render() {
return <MyButton onClick={linkTo('Button', 'With Some Emoji')}>With JSX</MyButton>;
}
})
export const withSomeEmoji = () => ({
components: { MyButton },
template: '<my-button>😀 😎 👍 💯</my-button>'
})
I tried asking in some discord servers, on youtube, but I found nothing. I'm new on Vue and I hope for an answer to help me see clearer please

How to use Buefy's Dialog component with user provided content and be safe in terms of XSS

Buefy's Dialog component expects a message prop - string. According to a documentation, that string can contain HTML. I would like to use template values in the string, but of course is should be XSS safe.
Current unsafe example
This is unsafe, as this.name is unsafe. I could use a NPM package to html encode the name, but I really prefer to use Vue.
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message: `<p>Hello ${this.name}</p>`, // unsafe - possible XSS!
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
This is an issue of the used Buefy component, as documented here:
Desired Setup
I've created a new component, in this example I call it ModalMessage.Vue
<template>
<p>Hello {{name}}</p>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
name: { type: String, required: true },
},
});
</script>
Then I like to render the ModalMessage.Vue to a string in Typescript:
<script lang="ts">
import Vue from 'vue';
import ModalMessage from 'ModalMessage.vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message:, // todo render ModalMessage and pass name prop
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
Question
How could I render the ModalMessage.Vue, and passing the name prop, to a string?
I'm pretty sure this is possible - I have seen it in the past. Unfortunately I cannot find it on the web or StackOverflow. I could only find questions with rendering a template from string, but I don't need that - it needs to be to string.
Imho your real question is "How to use Buefy's Dialog component with user provided content and be safe in terms of XSS"
So what you want is to create some HTML, include some user provided content (this.name) within that HTML content and display it in a Dialog. You are right that putting unfiltered user input into a message parameter of Dialog is not safe (as clearly noted in Buefy docs)
But your "Desired Setup" seems unnecessary complicated. Imho the easiest way is to use (poorly documented) fact that message parameter of Buefy Dialog configuration objects can be an Array of VNode's instead of a string. It is poorly documented but it is very clear from the source here and here that if you pass an array of VNode's, Buefy puts that content into Dialogs default slot instead of rendering it using v-html (which is the dangerous part)
And easiest way to get Array of VNode in Vue is to use slots...
So the component:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
methods: {
showModal() {
this.$buefy.dialog.confirm({
title: 'myTitle',
message: this.$slots.default, // <- this is important part
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
},
},
});
</script>
and it's usage:
<MyDialog>
<p>Hello {{name}}</p>
</MyDialog>
or
<MyDialog>
<ModalMessage :name="name" />
</MyDialog>
In both cases if the name contains any HTML, it will be encoded by Vue
Here is a simple demo of the technique described above (using plain JS - not TS)
Try this.
<script lang="ts">
import Vue from 'vue';
import ModalMessage from 'ModalMessage.vue';
export default Vue.extend({
props: {
name: { type: String, required: false },
},
methods: {
showModal() {
const message = new Vue({
components: { ModalMessage },
render: h => h('ModalMessage', { name: this.name })
})
message.$mount()
const dialog = this.$buefy.dialog.confirm({
title: 'myTitle',
message: [message._vnode],
cancelText: 'Cancel',
confirmText: 'OK',
type: 'is-success',
onConfirm: async () => {
// something
},
});
dialog.$on('hook:beforeDestroy', () => {
message.$destroy()
});
},
},
});
</script>
Source code:
Demo:

How to download base64 file from remote api by vue-router link?

I need to download files from remote api by vue-router link. Remote api returns files in base64.
I add route:
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/files/:id', name: 'file', component: Vue.component('vue-file'), props: true }
],
});
and add component for it:
<template>
<div>
</div>
</template>
<script>
export default {
name: 'file',
props: {
id: String
},
mounted: function() {
this.download();
},
methods: {
download: function() {
let $this = this;
axios
.get('apiurl' + encodeURIComponent(this.id))
.then(function (response) {
download(response.data.base64content)
});
}
}
}
</script>
It works but I don't want to show component template <template><div></div></template>. I even don't want to refresh the content on the screen. Is it possible?
You shouldn't. Vue Components were done for rendering. Your implementation would be nicer as a mixin or plugin, if you don't want to render anything.
Although, I think you can do something like:
render() {
return null;
},

Using CKEditor 5 with nuxtjs

I'm trying to import a custom build of CKEditor 5 in my Nuxtjs project and I've been tried every possible way to import it correctly but none of them worked for me and this is one of them:
let ClassicEditor
let CKEditor
if (process.client) {
ClassicEditor = require('./../../static/js/ckeditor')
CKEditor = require('#ckeditor/ckeditor5-vue')
}else{
CKEditor = { component : {template:'<div></div>'}}
}
data() {
return {
editor: ClassicEditor,
}
}
components:{
ckeditor: CKEditor.component
},
<client-only><ckeditor :editor="editor" /></client-only>
Every time I change the way a different error appears, for example, Window is not Defined and when i use different way shows a different error so I want to know what is the most correct way to use CKEditor with Nuxtjs in universal mode, consider that i haven't done anything and help me with the correct way starting from the installation
try this
npm install --save #blowstack/ckeditor-nuxt
You can use by importing the package on client side.
Create Editor.vue components
<template>
<ckeditor
:editor="editor"
:config="editorConfig"
/>
</template>
<script>
let ClassicEditor
let CKEditor
if (process.client) {
ClassicEditor = require('#ckeditor/ckeditor5-build-classic')
CKEditor = require('#ckeditor/ckeditor5-vue2')
} else {
CKEditor = { component: { template: '<div></div>' } }
}
export default {
components: {
ckeditor: CKEditor.component
},
data () {
return {
editor: ClassicEditor,
editorConfig: {}
}
}
</script>
Usage:
<client-only placeholder="Loading Text Editor...">
<editor v-model="textInput"/>
</client-only>
window is not defined
If you set ssr: true in the nuxt.config.js and put your custom VCKEditor.vue into the components folder, the Nuxt will scan the components folder by Server Side and it doesn't know the window keyword which is the JavaScript object in #ckeditor/ckeditor5-vue2.
You can see more about components doc.
I don't like use the process.client to check ssr mode.
I have two solutions, just choose one
set components: false in the nuxt.config.js.
Move the your custom VCKEditor.vue to components folder outside.
Finally, register custom VCKEditor.vue as plugins and set plugins ssr: false in the nuxt.config.js.
Here is the sample project.
The code snippet
nuxt.config.js
const path = require('path')
const CKEditorWebpackPlugin = require("#ckeditor/ckeditor5-dev-webpack-plugin")
const CKEditorStyles = require("#ckeditor/ckeditor5-dev-utils").styles
export default {
// ignore other settings...
ssr: true,
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
{
src: '~/plugins/ckeditor.js', ssr: false
},
],
// set false to disable scan the components folder
components: false,
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
transpile: [/ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/],
plugins: [
// If you set ssr: true that will cause the following error. This error does not affect the operation.
// ERROR [CKEditorWebpackPlugin] Error: No translation has been found for the zh language.
new CKEditorWebpackPlugin({
// See https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html
language: "zh",
additionalLanguages: 'all',
addMainLanguageTranslationsToAllAssets: true,
})
],
// If you don't add postcss, the CKEditor css will not work.
postcss: CKEditorStyles.getPostCssConfig({
themeImporter: {
themePath: require.resolve("#ckeditor/ckeditor5-theme-lark")
},
minify: true
}),
extend(config, ctx) {
// If you do not exclude and use raw-loader to load svg, the following errors will be caused.
// Cannot read property 'getAttribute' of null
const svgRule = config.module.rules.find(item => {
return /svg/.test(item.test);
})
svgRule.exclude = [path.join(__dirname, 'node_modules', '#ckeditor')];
// add svg to load raw-loader
config.module.rules.push({
test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
use: ["raw-loader"]
})
}
}
}
components/editor/VCKEditor.vue
<template>
<ckeditor
v-model="editorData"
:editor="editor"
:config="editorConfig"
></ckeditor>
</template>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue2'
import ClassicEditor from '#ckeditor/ckeditor5-editor-classic/src/classiceditor'
import Bold from '#ckeditor/ckeditor5-basic-styles/src/bold'
import Italic from '#ckeditor/ckeditor5-basic-styles/src/italic.js'
import Underline from '#ckeditor/ckeditor5-basic-styles/src/underline'
import Strikethrough from '#ckeditor/ckeditor5-basic-styles/src/strikethrough'
// less Heading + Essentials plugin can't input the text
import Heading from '#ckeditor/ckeditor5-heading/src/heading'
import Essentials from '#ckeditor/ckeditor5-essentials/src/essentials'
import ImageUpload from '#ckeditor/ckeditor5-image/src/imageupload'
import ImageInsert from '#ckeditor/ckeditor5-image/src/imageinsert'
import AutoImage from '#ckeditor/ckeditor5-image/src/autoimage'
import Image from '#ckeditor/ckeditor5-image/src/image'
import ImageResizeEditing from '#ckeditor/ckeditor5-image/src/imageresize/imageresizeediting'
import ImageResizeHandles from '#ckeditor/ckeditor5-image/src/imageresize/imageresizehandles'
import Base64UploadAdapter from '#ckeditor/ckeditor5-upload/src/adapters/base64uploadadapter'
export default {
name: 'VCKEditor',
components: { ckeditor: CKEditor.component },
props: {
value: {
type: String,
},
},
computed: {
editorData: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
},
},
},
data() {
return {
editor: ClassicEditor,
editorConfig: {
plugins: [
Bold,
Italic,
Underline,
Strikethrough,
Heading,
Essentials,
ImageUpload,
ImageInsert,
AutoImage,
Image,
ImageResizeEditing,
ImageResizeHandles,
Base64UploadAdapter,
],
toolbar: {
items: [
'heading',
'|',
'bold',
'italic',
'underline',
'strikethrough',
'|',
'insertImage',
],
},
language: 'zh',
},
}
},
}
</script>
plugins/ckeditor.js
import Vue from 'vue';
import VCKEditor from "../components/editor/VCKEditor.vue";
Vue.component('v-ckeditor', VCKEditor);
pages/index.vue
<template>
<client-only>
<v-ckeditor v-model="text" />
</client-only>
</template>
<script>
export default {
data() {
return {
text: 'Hello World!!',
}
},
}
</script>
Use #blowstack/ckeditor-nuxt package.
Here is editor config for uploader.
Use #blowstack/ckeditor-nuxt package.
Here is editor config for uploader.
editorConfig: {
simpleUpload: {
uploadUrl: `${process.env.apiUrl}/api/console/uploads/single_file`,
headers: {
authorization: `Bearer ${_.get(
this.$store,
"state.agency.global.token"
)}`,
},
},
removePlugins: ["Title"],
}
Response data from upload API like this:
{
url: ".../image.png"
}
Refs: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/upload-adapter.html#passing-additional-data-to-the-response
editorConfig: {
simpleUpload: {
uploadUrl: `${process.env.apiUrl}/api/console/uploads/single_file`,
headers: {
authorization: `Bearer ${_.get(
this.$store,
"state.agency.global.token"
)}`,
},
},
removePlugins: ["Title"],
}