I'm using CKEditor 5 in my angular 7 application. ClassicEditor by default shows the Insert Media button on the toolbar as highlighted in the below image.
On researching online I found we can disable particular options by using the removePlugins option in the editorConfig like below.
editor.component.ts
editorConfig = {
removePlugins: ['Image'],
placeholder: 'Type the content here!'
};
Above code is to not remove the Insert Media option but a different option to Insert Image. But it doesn't work. Even after using the above code I could still see Image insert option in my CK Editor.
I also couldn't find online what I need to provide in the removePlugins for disabling the Insert Media option to try if atleast that works. Any help will be appreciated.
Thanks in advance
Instead of removing specific buttons it is possible to set the default configuration of the CKEditor to show only the options which are required to us.
Adding below code to the constructor in your angular component.ts file will create a simple CKEditor with only those options mentioned in the items array. mediaEmbed is the name of the item responsible for displaying Insert Video option in the CKEditor which I've not mentioned in the items array to not display it in the CKEditor.
ClassicEditor.defaultConfig = {
toolbar: {
items: [
'heading',
'|',
'bold',
'italic',
'|',
'bulletedList',
'numberedList',
'|',
'insertTable',
'|',
'imageUpload',
'|',
'undo',
'redo'
]
},
image: {
toolbar: [
'imageStyle:full',
'imageStyle:side',
'|',
'imageTextAlternative'
]
},
table: {
contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ]
},
language: 'en'
};
Result after adding above code
Hopes this will help someone!
This definitely work
<script src="https://cdn.ckeditor.com/ckeditor5/23.1.0/classic/ckeditor.js"></script>
<script>
ClassicEditor
.create(document.querySelector('#editor'), {
removePlugins: ['CKFinderUploadAdapter', 'CKFinder', 'EasyImage', 'Image', 'ImageCaption', 'ImageStyle', 'ImageToolbar', 'ImageUpload', 'MediaEmbed'],
})
.catch( error => {
console.error( error );
} );
</script>
Try passing the config in an input.
It's very unintuitive, I know.
ClassicEditor
.create(document.querySelector(selector), {
removePlugins: ['CKFinderUploadAdapter', 'CKFinder', 'EasyImage', 'Image', 'ImageCaption', 'ImageStyle', 'ImageToolbar', 'ImageUpload', 'MediaEmbed'],
})
.catch(error => {
console.error(error);
});
You can get a list of all plugins available like this:
console.log(ClassicEditor.builtinPlugins.map(plugin => plugin.pluginName));
The first way to solve this problem
Go to node modules -> #ckeditor -> ckeditor-build-classic -> build ->ckeditor.js
Go or search for defaultConfig in ckeditor.js --- you will find out in the last few lines
Here remove the unwanted fields like table, media, etc
The second way to solve the problem
defaultConfig={toolbar:{items:["heading","|","bold","italic","link","bulletedList","numberedList","|","indent","outdent","|","imageUpload","blockQuote","insertTable","mediaEmbed","undo","redo"]},image:{toolbar:["imageStyle:full","imageStyle:side","|","imageTextAlternative"]},table:{contentToolbar:["tableColumn","tableRow","mergeTableCells"]},language:"en"}}]).default}
Here are the complete list:
Eg - remove the table from the Editor
defaultConfig={toolbar:{items:["heading","|","bold","italic","link","bulletedList","numberedList","|","indent","outdent","|","imageUpload","blockQuote","mediaEmbed","undo","redo"]},image:{toolbar:["imageStyle:full","imageStyle:side","|","imageTextAlternative"]},language:"en"}}]).default}
put in the constructor of the component.ts file
ClassicEditor.defaultConfig={toolbar:{items:["heading","|","bold","italic","link","bulletedList","numberedList","|","indent","outdent","|","imageUpload","blockQuote","mediaEmbed","undo","redo"]},image:{toolbar:["imageStyle:full","imageStyle:side","|","imageTextAlternative"]},language:"en"}}]).default}
I think you're on the right track. I was able to accomplish this by using the removePlugins config option. The key was making sure that the items in your removePlugins array match the item names in the default toolbar config.
const defaultToolbarItems = [
...,
'imageUpload',
'mediaEmbed',
...
];
const editorConfig = {
placeholder: 'Type the content here!',
removePlugins: ['imageUpload','mediaEmbed'],
}
Related
I fetch data from a MySQL database, the data stored is this:
<p><script>alert('123');</script><br /></p>
When I fetch the data normally I get this as result:
<script>alert('123');</script>
This is fine and works as expected, however when I fetch the data into a textarea which is initialized with Summernote I get an alert like this:
Somehow Summernote converts the escaped html tags to functioning HTML.
How do I fix this?
I have already tried the answer of this question:
Escaped HTML in summernote
It did not work.
Why are you not sanitising data both at the time of storage, and when displayed in the Editor, or outside of the editor? Typically, in my CMS, I don't allow <script/> tags as way to help mitigate users adding potentially dangerous scripts.
That said, there is a PR that is being discussed about how we can best go about fixing this issue. https://github.com/summernote/summernote/pull/3782 information or help would be greatly appreciated to move it along, or even another PR fixing the issue.
I managed to fix it by instead of fetching the data in the textarea fetching it in via jQuery like this:
<textarea name="description" id="description"></textarea>
<script>
$('#description').summernote({
height: 250,
codeviewFilter: false,
codeviewIframeFilter: true,
// toolbar
toolbar: [
['font', ['bold', 'italic', 'underline', 'clear']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['view', ['fullscreen', 'codeview', 'help']]
],
}).on("summernote.enter", function(we, e) {
$(this).summernote('pasteHTML', '<br /> ');
e.preventDefault();
});
$("#description").summernote("code", "<?php echo $video->getDetails('', $fileName, 'desc'); ?>");
</script>
Now it doesn't convert > and $lt; to <> if it is the script tag.
See more information here:
https://github.com/summernote/summernote/pull/3782#issuecomment-774432392
Using javascript you can easily fix this. It worked for me in a React + Django project. I also used django_summer_note and it was also showing data like yours. Then I got that solution:
//simply just create a function like this which will return your data (which one you used with django_summernote).
const createBlog = () => {
return { __html: blog.description };
};
// now in your HTML(JSX) show your data like this.
<div className='' dangerouslySetInnerHTML={createBlog()} />
I want to add badge in nebular menu for inbox count dynamically. Help me on this. Thanks
import { NbMenuItem } from '#nebular/theme';
export const MENU_ITEMS: NbMenuItem[] = [
{
title: 'Dashboard',
link: '/pages/dashboard',
home: true,
},{
title: 'Inbox',
link: '/pages/inbox',
home: true,
}]
I would like to extend the question and ask if it is possible to place a custom component or at least HTML tags within the menu item? Currently the interface allow only string (title) ...
The question above (about adding a badge) is just an example for the missing functionality - enable formatting of the menu item.
I would appreciate an example code to solve this limitation, even if it contains extending nebular framework classes.
Thx,
Yohay
I want to add a custom drop down in tiny mce editor, I am using yii framework and using a yii plugin to integrate the editor
You haven't added any details in your question but since you are a new
bee here and SO Code of Conduct
has been revised to be more nice and humble towards newcomers, so I am
adding the answer for you, do go through the How to Ask a
Question? before posting a
question next time.
You can add the dropdown in the TinyMCE using setup option which takes a callback function with a parameter editor which holds the editor instance, and then you need to call the editor.addButton(label, options) with the options to create the custom dropdown button.
As you have not added any details in the question like what are the options that you are going to display in the dropdown so, I will assume here as usernames from the database in the variable $users.
Steps to Implement
First, we will convert $users array to js array by using yii\helpers\Json::encode().
Iterate that array to create the drop-down options with onclick event to insert the content to the editor.
Use editor.addButton('users',options) to create a button of type dropdown with label users to be later used when initializing the editor toolbar buttons.
Add the following code on top of the view
$usersList = \yii\helpers\Json::encode($users);
$tinyMCECallback = <<< JS
function (editor) {
let usersList = $usersList;
let options = [];
//iterate the user array and create the options with text and
//onclick event to insert the content on click to the editor
$.each(usersList, function(label, mapping) {
options.push({
text: label,
onclick: function() { tinymce.activeEditor.insertContent(label); }
});
});
//add the dropdown button to the editor
editor.addButton('users', {
type: 'menubutton',
text: 'Users',
icon: false,
menu: options
});
}
JS;
Now all you need to do is to pass the $tinyMCECallback to the setup option of the tinyMCE widget, if you are using the active form you code should be like below.
Note: Don't forget to add the users label of the button to the toolbar options, or if you change it in the javascript code change it accordingly in the editor toolbar options otherwise it won't show up
<?php
echo $form->field(
$model, 'body'
)->widget(
TinyMce::class, [
'options' => ['rows' => 10],
'language' => 'en',
'clientOptions' => [
'menubar' => false,
'statusbar' => false,
'toolbar' => "undo redo | users",
'setup' => new \yii\web\JsExpression($tinyMCECallback),
],
]
);
?>
I want to creat two level context menu but there is no api for this.Just look like this
level context menu image
what I can do?
It is rather straighforward to acheive a multi level context menu by deriving from Autodesk.Viewing.UI.ObjectContextMenu. Simply provide an array in the target field:
buildMenu (event, node) {
var menu = []
switch (node.type) {
case 'hubs':
menu.push({
title: 'Show details',
className: 'fa fa-share',
target: [{
title: 'Hub details',
className: 'fa fa-cloud',
target: () => {
this.emit('context.details', {
event, node, type: 'hubs'
})
}
}, {
title: 'Projects details',
className: 'fa fa-folder',
target: () => {
this.emit('context.details', {
event, node, type: 'hubs.projects'
})
}
}]
})
break
A complete example of this can be found here: DataContextMenu.js
Unfortunately, it's not available on current viewer version. You might have to write your own context menu in deep. But there is a workaround that you can follow:
Override functions of Autodesk.Viewing.Private.ContextMenu to provide multiple level menus.
Refer codes from Autodesk.Viewing.UI.ObjectContextMenu, then create your owned ObjectContextMenu and replace contextMenu property with the your owned multiple levels ContextMenu from the step 1.
Refer codes from Autodesk.Viewing.Extensions.ViewerObjectContextMenu, then write your owned ViewerObjectContextMenu that inherits the custom ObjectContextMenu from the step 2.
P.S. This is just a workaround, it's not the formal solution, you might have to use it at your own risk.
I`m trying to insert a custom link to a special page in VisualEditor toolbar. See the image below.
See Image
I googled a lot but without success. Someone please give a path...
My answer is based on the following resources:
MediaWiki core JS doc (ooui-js)
VisualEditor JS doc (+ reading code of both repositories used for VE, mediawiki/extension/VisualEditor and VisualEditor)
Also, I'm pretty sure, that there is no documented way of adding a tool to the toolbar in VE, as far as I know. Although it's possible to add a tool to a group, which is already added, mostly used for the "Insert" tool group, like in Syntaxhighlight_GeSHi). There is, probably, a much easier or "better" way of doing this :)
First, VisualEditor provides a way to load additional modules (called plugins) when the main part of VE loads (mostly, when you click the "Edit" button). The modules needs to be registered via the global variable $wgVisualEditorPluginModules (or the equivalent in extension.json, if you're using the new extension registration). In your extension registration file, you should initialize a module (with your required script files to add the tool) and add it as a VE plugin.
Example PHP (old extension registration via PHP files):
// other setup...
$wgResourceModules['ext.extName.visualeditor'] = array(
'localBasePath' => __DIR__,
'remoteExtPath' => 'extName'
'dependencies' => array(
'ext.visualEditor.mwcore',
),
'scripts' => array(
'javascripts/ve.ui.ExtNameTool.js',
),
'messages' => array(
'extname-ve-toolname',
),
);
$wgVisualEditorPluginModules[] = 'ext.extName.visualeditor';
// other setup...
extension.json (new JSON-based extension registration):
// other setup...
"ResourceModules": {
"ext.geshi.visualEditor": {
"scripts": [
"javascripts/ve.ui.ExtNameTool.js"
],
"dependencies": [
"ext.visualEditor.mwcore"
],
"messages": [
"extname-ve-toolname"
]
}
},
"VisualEditorPluginModules": [
"ext.extName.visualeditor"
],
// other setup...
Now, if VE starts, it will load your module, named ext.extName.visualeditor in this example, with the script ve.ui.ExtNameTool.js. In this script, you can now do, what ever you want. As an example, this is a way to add a new module to the end of the toolgroup list in the toolbar:
Example of ve.ui.ExtNameTool.js:
( function () {
// create a new class, which will inherit ve.ui.Tool,
// which represents one tool
ve.ui.extNameTool = function extNameTool( toolGroup, config ) {
// parent constructor
ve.ui.extNameTool.super.apply( this, arguments );
// the tool should be enabled by default, enable it
this.setDisabled( false );
}
// inherit ve.ui.Tool
OO.inheritClass( ve.ui.extNameTool, ve.ui.Tool );
// every tool needs at least a name, or an icon
// (with the static property icon)
ve.ui.extNameTool.static.name = 'extname';
// don't add the tool to a named group automatically
ve.ui.extNameTool.static.autoAddToGroup = false;
// prevent this tool to be added to a catch-all group (*),
although this tool isn't added to a group
ve.ui.extNameTool.static.autoAddToCatchall = false;
// the title of the group (it's a message key,
// which should be added to the extensions i18n
// en.json file to be translateable)
// can be a string, too
ve.ui.extNameTool.static.title =
OO.ui.deferMsg( 'extname-ve-toolname' );
// onSelect is the handler for a click on the tool
ve.ui.extNameTool.prototype.onSelect = function () {
// show an alert box only, but you can do anything
alert( 'Hello' );
this.setActive( false );
}
// needs to be overwritten, but does nothing so far
ve.ui.extNameTool.prototype.onUpdateState = function () {
ve.ui.extNameTool.super.prototype.onUpdateState.apply( this, arguments );
}
// the tool needs to be registered to the toolFactory
// of the toolbar to be reachable with the given name
ve.ui.toolFactory.register( ve.ui.extNameTool );
// add this tool to the toolbar
ve.init.mw.Target.static.toolbarGroups.push( {
// this will create a new toolgroup with the tools
// named in this include directive. The naem is the name given
// in the static property of the tool
include: [ 'extname' ]
} );
} )();
After installing the extension in your LocalSettings.php and starting VE, you should see a new tool in the toolbar with the given name. Clicking it will show an alert box with content "Hello". Like written in the inline comments: In the click handler (onSelect) you can do whatever you want, e.g. open a link in a new tab, e.g. to a Special page. To get the link to a special page I would suggest to use mw.Title to get a localized namespace. For example:
var relativeUrl = mw.Title.newFromText( 'RecentChanges', -1 ).getUrl();
The first parameter of mw.Title.newFromText() is the name of the page, the second parameter is the ID of the namespace (-1 is the default for special pages and should always work).
I hope that helps!
I am not sure I understand your question entirely. It is as simple as selecting some text, clicking the chain icon, then clicking the External Link tab and pasting your link there.