I'm using QuillJs as a text editor on my website. In a long post the screen view jumps to top when pasting text or changing heading type or alignment or color or inserting a link or video. Can't find out why.
QuillJs version: 1.2.6
Browser: Chrome 58.0.3029.110
OS: Windows 10
Initialization:
var toolbarOptions = [
[{ 'header': [1, 2, 3, 4, 5, 6, false] },
'bold', 'italic', 'underline', 'strike', { 'align': [] },
{ 'list': 'ordered' }, { 'list': 'bullet' },
{ 'color': [] }, { 'background': [] }],
['image', 'blockquote', 'code-block', 'link', 'video'],
['clean']
];
var quill = new Quill('#editor', {
modules: {
toolbar: toolbarOptions
},
theme: 'snow'
});
This happens when any option is clicked from the quill toolbar. I had similar issue and I was using react-quill 0.4.1.
Try using event.preventDefault and event.stopPropagation on quill toolbar to fix this.
The following fixed the issue for me.
componentDidMount()
{
$('.quill-toolbar').on("mousedown", function(event){
event.preventDefault();
event.stopPropagation();
});
}
If you want an editor to be scrolled and maintained by a web page's main scrollbar, you need to set scrollingContainer property to 'body' during configuration of Quill object.
var quill = new Quill('#editor', {
modules: { toolbar: toolbarOptions },
theme: 'snow',
scrollingContainer: 'body'
});
Setting scrollingContainer to html was the only solution that worked for me:
var quill = new Quill('#editor', {
modules: { toolbar: toolbarOptions },
theme: 'snow',
scrollingContainer: 'html'
});
this is happening because of these two lines:
https://github.com/quilljs/quill/blob/5715499c57091db262c176985f6c5370d73db5dd/modules/toolbar.js#L86
and
https://github.com/quilljs/quill/blob/5b28603337f3a7a2b651f94cffc9754b61eaeec7/core/quill.js#L171
this.scrollingContainer => could be not an actual scrolling element.
The fix could be is to assign the nearest scrolling element directly.
If you are not sure what it is you can use this snippet to find it:
const regex = /(scroll)/;
const style = (node, prop) => window.getComputedStyle(node, null).getPropertyValue(prop);
const scroll = (node) => regex.test( style(node, "overflow") + style(node, "overflow-y") + style(node, "overflow-x"));
export const scrollparent = (node) => {
return !node || node===document.body ? document.body : scroll(node) ? node : scrollparent(node.parentNode);
};
editor.scrollingContainer = scrollparent(editor.container);
Related
I am using the quill text editor in a php based web-app and I need to retrieve the contents of the text editor as a string with the HTML included but the docs are a little sparse on this subject. Ultimately I want to write that data to a database.
This is how I tried to get the content
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
},
placeholder: 'Compose an Des...',
theme: 'snow' // or 'bubble'
});
var delta = quill.getContents();
var text = editor.getText();
Try the following:
let html = quill.root.innerHTML;
I've been trying a couple of rich text editors, and Quill seems to be the best tool to implement into my projects. I'm using Node/Express and MongoDB/Mongoose. In my 'newPost route', I have a form that just takes a title and the main content. Since I'm just testing it out, the title field is outside of the Quill editor. Here the error I'm getting:
This is after I hit "submit". The console shows not only the title but also the main content that has a code-block with syntax highlight which is exactly what I wanted. But it's not being added to the database.
There's also this message Use of Mutation Events is deprecated. Use MutationObserver instead., and it seems I'm required to change Quill's source code myself to fix this.
Getting the main content of the post on the console kind of gave me a feeling that I'm halfway of getting this to work.
Is there a not-so-hard way to get this to work? Thanks!!
js
var quill;
var metaData = [];
hljs.configure({ // optionally configure hljs
languages: ['javascript', 'ruby', 'python']
});
hljs.initHighlighting();
$(document).ready(function() {
var toolbarOptions = [['blockquote', 'code-block'],
["bold", "italic", "underline", "strike"], // toggled buttons
//['blockquote'],
[{ list: "ordered" }, { list: "bullet" }],
[{ script: "sub" }, { script: "super" }], // superscript/subscript
[{ indent: "-1" }, { indent: "+1" }], // outdent/indent
[{ direction: "rtl" }], // text direction
[{ size: ["small", false, "large", "huge"] }], // custom dropdown
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
[{ font: [] }],
[{ align: [] }],
["clean"] // remove formatting button
];
quill = new Quill("#snow-container", {
placeholder: "Compose an epic...",
modules: {
syntax: true,
toolbar: toolbarOptions
},
theme: "snow"
});
var oldDelta = {"ops":[{"attributes":{"color":"#000000"},"insert":"This is sample text."}]};
quill.setContents(oldDelta);
});
var form = document.querySelector('form');
form.onsubmit = function() {
// Populate hidden form on submit
var formContent = document.querySelector('input[name=content]');
formContent.value = JSON.stringify(quill.getContents());
console.log("Submitted", $(form).serialize(), $(form).serializeArray());
// No back end to actually submit to!
//alert('Open the console to see the submit data!')
return false;
};
I am tasked with fixing a problem with my company's CMS. We use CKEditor. When users cut from microsoft word and paste into the editor, tags are removed. This was done intentionally by someone who no longer works at the company, and now we want to allow a tags.
I am able to find the editor by going into the javascript console. When I inspect the object, I find that editor.config.allowedContent is set to "p[*](*){*}; h1[*](*){*}; h2[*](*){*}; em; b; u; ul[*](*){*}; ol[*](*){*}; li[*](*){*}; img[*](*){*}; iframe[*](*){*}; a[*](*){*}; object[*](*){*}; param[*](*){*}; embed[*](*){*}; video[*](*){*}; i; table[*](*){*}; tr[*](*){*}; td[*](*){*}; script[*](*){*}; h3[*](*){*}; span[*](*){*}; br[*](*){*}; div[*](*){*}; strong; blockquote[*](*){*} which contains an a tag.
What other possible causes could their be for the link tags being stripped on copy + paste?
Thanks!
Edit:
Here is config.js:
CKEDITOR.editorConfig = function( config ) {
config.toolbarGroups = [
{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
{ name: 'links' },
{ name: 'insert' },
{ name: 'forms' },
{ name: 'tools' },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
{ name: 'others' },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ] },
{ name: 'styles' },
{ name: 'colors' },
{ name: 'about' }
];
config.removeButtons = 'Underline,Subscript,Superscript';
config.format_tags = 'p;h1;h2;h3;pre';
config.removeDialogTabs = 'image:advanced;link:advanced';
config.fillEmptyBlocks = false;
config.baseFloatZIndex = 100001;
config.extraAllowedContent = 'a';
};
CKEDITOR.config.fillEmptyBlocks = false;
Furthermore it seems some config options are set dynamically:
this.editorObject = CKEDITOR.inline(this.$editable[0],{
forcePasteAsPlainText: true,
title: this.label,
customConfig: '',
removePlugins: 'autocorrect,format,stylescombo',
removeButtons: 'PasteText,Flash,Anchor,ShowBlocks,About',
extraPlugins: extraPlugins,
linkShowAdvancedTab: false,
linkShowTargetTab: true,
youtube_responsive: true,
youtube_related: false,
scayt_autoStartup: true,
readOnly: this.disabled,
floatSpacePinnedOffsetY: 100,
floatSpaceDockedOffsetY: 25,
toolbar: this.toolbarDefinitions[this.variant],
allowedContent: allowedContent,
blockedKeystrokes: blockedKeystrokes,
keystrokes: keystrokes,
on: {
instanceReady: _.bind(function(e) {
if (this.fieldname == 'inc_clean_text' && this.area) {
this.area.generateInlineVideoPlayers();
var area = this.area;
async.nextTick(function() {
_.each(area.inlineVideoPlayers, function(player) {
player.menu && player.menu.show();
});
});
}
this.$editable.focus();
// When triggerred will focus on the editor.
this.$editable.on('focusCursor', (function() {
var range = this.editorObject.createRange();
range.moveToElementEditablePosition(this.editorObject.editable(), true);
this.editorObject.getSelection().selectRanges([range]);
}).bind(this));
if (this.editorObject.document.$.getElementById('caret-position-placeholder')) {
// When there is a caret placeholer present will put the cursor there and
// remove the placeholder element.
var node = new CKEDITOR.dom.element(this.editorObject.document.$.getElementById('caret-position-placeholder'));
var range = new CKEDITOR.dom.range(this.editorObject.document);
range.selectNodeContents(node);
this.editorObject.getSelection().selectRanges([range]);
$(this.editorObject.document.$.getElementById('caret-position-placeholder')).remove();
}
if (this.$editable.hasClass('pancaption_override')) {
// ! TODO Move elsewhere.
// Code specific to the main feature image caption editor.
if (this.$editable.data('reshow')) {
this.$editable.data('reshow', false);
$('.pancaption_default').hide();
this.$editable.attr('contenteditable', true);
this.$editable.show().focus().trigger('click');
this.editorObject.setReadOnly(this.disabled);
}
if (this.$editable.html() == '') this.$editable.trigger('focusCursor');
}
// When on the new article page and clicking on a field with default text then empty
// the editable text.
//this.editorObject.setData('');
//this.$editable.trigger('focusCursor');
//this.$editable.toggleClass('empty', true);
}, this),
change: _.bind(this.contentChanged, this)
}
});
Let me know if I should trace any of these variables.
Controlling which tags are allowed or disallowed is done through the config.js file usually located in the root of the CKEditor directory. http://docs.ckeditor.com/#!/guide/dev_configuration
As you've discovered through the console you can either allow or disallow certain tags through config.allowContent or config.disallowedContent respectively. http://docs.ckeditor.com/#!/guide/dev_acf
i have uploaded codesnippet plugin inside /ckeditor/plugins/ directory.
My config.js file codes are:
CKEDITOR.editorConfig = function( config ) {
config.toolbar = [
{ name: 'basic', items: [ 'Bold', 'Italic', 'Underline' ] },
{ name: 'font', items: [ 'Font' ] },
{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', 'Blockquote' ] },
{ name: 'links', items: [ 'Link', 'Unlink' ] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule' ] },
{ name: 'last', items: [ 'Maximize' ] }
];
config.extraPlugins = 'codesnippet';
config.format_tags = 'p;h1;h2;h3;pre';
config.entities = false;
config.removeDialogTabs = 'image:advanced;link:advanced;table:advanced';
config.disableNativeSpellChecker = false;
};
But when i add config.extraPlugins = 'codesnippet'; line then editor do not work even i can't see textarea field.
And when i remove config.extraPlugins = 'codesnippet'; line then editor works perfectly.
Use the online builder to add the codesnippet plugin to your editor. Most probably your editor is missing dependencies.
Most plugins in CKEditor require some additional plugins to operate. If you download manually plugin A, there is a chance that you need to download dependencies for plugin A... and plugin B, which is required by plugin A. And sometimes you will need to download dependencies for plugin C, which was required by plugin B. Sounds like a nightmare, this is why we created online builder and why package managers exist.
I am doing like below to group set of commands into single dropdown but all items are not showing up
CKEDITOR.config.toolbar = [{
name: 'paragraph',
groups:['list', 'indent', 'blocks', 'align', 'bidi'],
items: ['More']
}];
CKEDITOR.replace(editorName, {
on: {
pluginsLoaded: function () {
var editor = this,
items = {}, groupName = 'Justify_Group',
config = CKEDITOR.config;
var more_Group = 'More_Group';
editor.addMenuGroup(more_Group);
var moreButtons = {
Subscript: 'Sub Script',
Superscript: 'Super Script',
NumberedList: 'Numbered List',
BulletedList: 'Bullet List',
Outdent: 'Outdent',
Indent: 'Indent',
Blockquote: 'Blockquote',
RemoveFormat: 'Remove Format'
}, moreItems = {};
for (var i in moreButtons) {
var v = moreButtons[i];
moreItems[i.toLowerCase()] = {
label: v,
group: more_Group,
command: i.toLowerCase(),
order: 1
};
}
editor.ui.add('More', CKEDITOR.UI_MENUBUTTON, {
label: 'More',
name: 'More',
modes: {
wysiwyg: 1
},
onMenu: function () {
var active = {};
for (var p in moreItems)
active[p] = null
return active;
}
});
}
}
});
But same thing works well for Justify buttons. In above list of commands only Bulleted Lists are showing up in dropdown that too with (properties) text added to given label.
How can I fix this issue
Well the only thing that you're missing is adding proper menu items.
It's done with editor.addMenuItem.
Why adding menu items?
CKEditor UI menus work with menu items, not buttons or anything like that.
Mentioned Bullet List / Numbered List were just a coincidence, most likely because other plugin registered them to use it in context menu (as it reuses menu objects).
How to fix it in your case?
To make things easier we'll use editor.addMenuItems.
And it would be it, if you wouldn't include lowercasing for command names. I'll fix it as well.
CKEDITOR.config.toolbar = [{
name: 'paragraph',
groups:['list', 'indent', 'blocks', 'align', 'bidi'],
items: ['More']
}];
CKEDITOR.replace(editorName, {
on: {
pluginsLoaded: function () {
var editor = this,
items = {}, groupName = 'Justify_Group',
config = CKEDITOR.config;
var more_Group = 'More_Group';
editor.addMenuGroup(more_Group);
var moreButtons = {
subscript: 'Sub Script',
superscript: 'Super Script',
numberedlist: 'Numbered List',
bulletedlist: 'Bullet List',
outdent: 'Outdent',
indent: 'Indent',
blockquote: 'Blockquote',
removeFormat: 'Remove Format'
}, moreItems = {};
for (var i in moreButtons) {
var v = moreButtons[i];
moreItems[i.toLowerCase()] = {
label: v,
group: more_Group,
command: i,
order: 1
};
}
editor.addMenuItems( moreItems );
editor.ui.add('More', CKEDITOR.UI_MENUBUTTON, {
label: 'More',
name: 'More',
modes: {
wysiwyg: 1
},
onMenu: function () {
var active = {};
for (var p in moreItems)
active[p] = null
return active;
}
});
}
}
});
What can go weird?
You'll need to note that the default menu implementation won't show menu items of which related command status is equal to CKEDITOR.TRISTATE_OFF.
You can always check this condition by evaluating editor.commands.bold.state !== CKEDITOR.TRISTATE_DISABLED.
You can workaround this problem by passing onClick callback that will call your command, rather than providing command as a string, but then you'll need also to manually care about command state. Similar trick was used in language plugin. Further explainations goes out of scope of this question.