I have created a simple plugin to move some of the formatting buttons to a dropdown button. The dropdown button has both an icon and a label. The plugin works as intended except that when clicked on the label shows both the intended text as well as adding "(selected)" to the end.
Here is the button default view (the formatting button):
And here is how it looks when clicked on:
Here is the code for the plugin:
CKEDITOR.plugins.add( 'sf_formatting', {
init: function( editor ) {
var format = {};
editor.addMenuGroup( 'format_group' );
format.indent = {
label: 'Increase Indent',
group: 'format_group',
command: 'indent',
order: 6
};
format.outdent = {
label: 'Decrease Indent',
group: 'format_group',
command: 'outdent',
order: 7
};
editor.addMenuItems( format );
editor.ui.add( 'Formatting', CKEDITOR.UI_MENUBUTTON, {
label: 'Formatting',
// Disable in source mode.
modes: {
wysiwyg: 1
},
icon: 'dropdown',
onMenu: function() {
var active = {};
// Make all items active.
for ( var p in format )
active[ p ] = CKEDITOR.TRISTATE_OFF;
return active;
}
} );
}
});
I have a second issue
The outdent (decrease indent) only appears when the text has been indented. In the main menu it is always there but greyed out. How can I force the outdent button to always be visible in the dropdown box but not accessible.
Here is a screenshot of the dropdown when the text has been indented:
I'd be really grateful for any help.
I managed to create a hack to make this work as no one seems to know the answer.
In the language file, the relevant entry is "%s (Selected)". %s is replaced by the menu title in the plugin code.
I just removed the "(Selected") and now it works fine FOR MY USE.
It may break other things I am unaware of, but it works for me
Related
Here's my code
CKEDITOR.rbcPluginTools.addCustomPlugins('custom_author_signature', [
{
name: "author_signature",
title: "Подпись автора",
tooltip: "Добавить подпись автора",
icon: 'author_signature',
hidpi: true,
toolbar: "media,9",
exec: function (plugin, editor) {
selection = editor.getSelection();
if(selection.getSelectedText()) {
editor.insertHtml(`<div class="back_container author_signature">${editor.getSelection().document.getBody().getHtml()}</div>`);
}
}
}
]);
'back_container' is for background-color. Looks like it duplicates divs for some weird reason, cause after 2 executions it makes 3 back colors instead of two.
Expected behavior:
select text -> press plugin button -> 1 background container
select text inside this background container -> press plugin button -> 2 background containers (not 3!)
Is there a way to only show part of a document, or in monacos case of a model, while still getting intellisense for the whole document?
I only want a user to edit a part of a document, but the user should be able to get the right contextual intellisense.
It would be best for my usecase to hide the uneditable sections, but deactivating them would also be ok.
In case this is not possible, is there any embedded editor that can do this, or can this be achived by modifying the language server?
Monaco editor loads every line as a container under a section with the class name "view-lines". Once the editor content has loaded, set "display: none" to the corresponding container for each line that you want to hide.
Implementation: https://jsfiddle.net/renatodc/s6fxedo2/
let value = `function capitalizeFirstLetter(string) {
\treturn string.charAt(0).toUpperCase() + string.slice(1);
}
$(function() {
\tlet word = "script";
\tlet result = capitalizeFirstLetter(word);
\tconsole.log(result);
});
`
let linesToDisable = [1,2,3];
let editor = monaco.editor.create(document.getElementById('container'), {
value,
language: 'javascript',
theme: 'vs-dark',
scrollbar: {
vertical: "hidden",
handleMouseWheel: false
},
scrollBeyondLastLine: false
});
// onLoad event for Monaco Editor: https://github.com/Microsoft/monaco-editor/issues/115
let didScrollChangeDisposable = editor.onDidScrollChange(function() {
didScrollChangeDisposable.dispose();
setTimeout(function() {
$(".monaco-editor .view-lines > div").each(function(i) {
if(linesToDisable.includes(i+1)) {
$(this).css("display","none");
$(this).css("pointer-events","none");
}
});
},1000);
});
Scrolling from Monaco will render the lines again and break the implementation. To prevent this, disable the scrolling feature in Monaco, set a fixed height for the editor container, and use the browser or a parent container to scroll instead.
If you use the arrow keys 'up' or 'down' to navigate to the hidden content, the cursor will still work, and typing will break the implementation. You might be able to use the editor's onKeyDown event to prevent this.
If you're looking for a break-proof implementation, I would suggest loading Monaco editor only with the portion of the document that you wish to edit. Then extend the completion provider (Intellisense) as shown in this example: https://microsoft.github.io/monaco-editor/playground.html#extending-language-services-completion-provider-example
monaco.languages.registerCompletionItemProvider('javascript', {
provideCompletionItems: function(model, position) {
return {
suggestions: [
{
label: "capitalizeFirstLetter",
kind: monaco.languages.CompletionItemKind.Method,
documentation: "Capitalize the first letter of a word",
insertText: "capitalizeFirstLetter("
}
]
};
}
});
monaco.editor.create(document.getElementById("container"), {
value: `$(function() {
\tlet word = "script";
\tlet result = capitalizeFirstLetter(word);
\tconsole.log(result);
});
`,
language: "javascript"
});
Use an AST parser like Esprima to get the identifiers from your source document, and plug these into the suggestions array.
I am developing one custom plugin for the CKEditor 4.7 which do a simple think take in case user select some stuff it will put it in a div with specific class, else it will put a div with same class just with text like 'Add content here'
I try to use some functions according to CKEditor docs but have something really wrong.
here is the code for the plugin folder name=> customdiv, file=> plugin.js
CKEDITOR.plugins.add('customdiv', {
icons: 'smile',
init: function (editor) {
editor.addCommand( 'customdiv',{
exec : function( editor ){
var selection = editor.getSelection();
if(selection.length>0){
selection='<div class="desktop">'+selection+'</div>';
}else{
selection='<div class="desktop">Add your text here </div>';
}
return {
selection
};
}
});
editor.ui.addButton( 'Customdiv',
{
label : 'Custom div',
command : 'customdiv',
toolbar: 'customdiv',
icon : this.path + 'smile.png'
});
if (editor.contextMenu) {
editor.addMenuGroup('divGroup');
editor.addMenuItem('customdiv', {
label: 'Customdiv',
icon: this.path + 'icons/smile.png',
command: 'customdiv',
group: 'divGroup'
});
editor.contextMenu.addListener(function (element) {
if (element.getAscendant('customdiv', true)) {
}
});
}
}
});
According to some docs it have to return the result good.
Also this is how I call them in my config.js file
CKEDITOR.editorConfig = function (config) {
config.extraPlugins = 'templates,customdiv';
config.allowedContent = true;
config.toolbar = 'Custom';
config.toolbar_Custom = [
{ name: 'divGroup', items: [ 'Customdiv' ] },
{name: 'document', items: ['Source', '-', 'Save', 'Preview', '-', 'Newplugin']},
/* MOre plugins options here */
];
};
Note: the official forum was close and moved here :(
UPDATE
I have change the function like this
exec : function( editor ){
var selection = editor.getSelection();
if(selection.length>0){
selection='<div class="desktop">'+selection+'</div>';
CKEDITOR.instances.editor1.insertHtml( selection );
}else{
selection='<div class="desktop">Add your text here </div>';
CKEDITOR.instances.editor1.insertHtml( selection );
}
}
This makes it work for the else part, but still can't get the selected one.
UPDATE 2
After change of the if I can get data if is selected, but when I do insert selected between <div> I face a problem.
var selection = editor.getSelection();
give like result an object, and I funded out a more complex function and I get collected data like this
var selection = editor.getSelection().getNative();
alert(selection);
from this in alert I see the proper selection and not just object,but when I insert it like
CKEDITOR.instances.editor1.insertHtml('<div class="desktop">' + selection + '</div>');
it just put all selected in one line and not adding the div, new div for else case working with this syntax.
UPDATE 3
The problem now is this function
CKEDITOR.instances.editor1.insertHtml('<div>' + selection + '<div>');
it delete all existing HTML tags even if I add just selection without <div> I am not sure if this is because of the way I insert data or way I collect data, just in alert when I collect data I see correct space like in the editor.
user select some stuff it will put it in a div with specific class
If you want to check if selection is not empty, please instead of selection.length>0 try using !selection().getRanges()[0].collapsed.
If you need something more advanced you could also try using
!!CKEDITOR.instances.editor1.getSelection().getSelectedText() to see if any text was selected and !!CKEDITOR.instances.editor1.getSelection().getSelectedElement() to see if any element like e.g. image, tabl,e widget or anchor was selected.
EDIT:
If you need selected HTML please use CKEDITOR.instances.editor1.getSelectedHtml().getHtml();
Please also have a look at CKEditor documentation:
https://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-getSelectedHtml
https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_dom_documentFragment.html#method-getHtml
https://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-getSelectedText
https://docs.ckeditor.com/#!/api/CKEDITOR.dom.selection-method-getSelectedElement
i'm trying to create a dropdown menu in CKEditor to group some normal button tool just because i need to compress the toolsbar. For this i'm trying to create, for example, a justify group button menu, for this i have compile this plugin :
CKEDITOR.plugins.add('justifygroup', {
requires: ['justify'],
init: function (editor) {
var items = {
justifyleft: {
label: editor.lang.justify.left,
group: 'justify_group',
command: 'justifyleft',
// icon: CKEDITOR.getUrl(this.path + 'icons/icon.png'),
order: 1
},
justifycenter: {
label: editor.lang.justify.center,
group: 'justify_group',
command: 'justifycenter',
order: 2
},
justifyright: {
label: editor.lang.justify.right,
group: 'justify_group',
command: 'justifyright',
order: 3
},
justifyblock: {
label: editor.lang.justify.block,
group: 'justify_group',
command: 'justifyblock',
order: 4
}
};
editor.addMenuGroup('justify_group');
editor.addMenuItems(items);
editor.ui.add('JustifyGroup', CKEDITOR.UI_MENUBUTTON, {
label: 'Justify Group',
icon: 'JustifyLeft',
// Disable in source mode.
modes: {
wysiwyg: 1
},
onMenu: function () {
var activeItems = {};
// Make all items active.
for (var prop in items)
activeItems[prop] = CKEDITOR.TRISTATE_OFF;
return activeItems;
}
});
}
});
here it is a demo of this plugin : https://codepen.io/seltix/pen/dWxWbO
CKEDITOR.replace('textarea', {
extraPlugins: 'justifygroup',
toolbar:[{name: 'test', items: ['JustifyGroup']}]
});
the problems :
1 - if i dont call one of the align buttons on the toolbar ('JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock') the
button menu does not show any button
2 - i'm unable to control some
sort of visual mark to show what alignment is in use (like on the
toolbar buttons)
UPDATE : I found the solution for this problem on the "onMenu" function replacing activeItems[prop] = CKEDITOR.TRISTATE_OFF; with activeItems[prop] = editor.getCommand(items[prop].command).state;
3 - i dont know why but the first option is always
with "focus", how can I set the focus to match a specific item?
thanks all!
1 - The problem that is causing buttons not to display is ACF. Buttons that you're grouping in your dropdown requires certain tags/attrs to be available. In the simplest case it requires text-align to be applicable on p.
It looks that there's a bug in CKEditor that buttons added using editor.addMenuItems are not registering properly new ACF rules, while they do if added directly to the toolbar.
3 - I couldn't find a proper function for that, IMHO it should be doable in onMenu function, however it does not provide enough references to do that. Sounds like a feature request.
Generally you should look at language plugin, as it has many things you are looking for so it's a nice source of inspiration.
For future reference, please create separate StackOverflow question for each case. Though these issues were releated, they are a different cases.
CKEditor's Mathjax plugin contains several elements in the dialog: one textarea (id: equation) and one div (id: preview).
https://github.com/ckeditor/ckeditor-dev/blob/master/plugins/mathjax/dialogs/mathjax.js
When some mathjax code is entered in the textarea, the formula is written in the div. I am trying to add several predefined buttons that add usual formulae mathjax text to the textarea, so users only have to populate these formulae.
Adding a button into the elements works nice, but I can only access to change the div element. Accessing the textarea does not work, it seems that is not available in any scope at all.
id: 'info',
elements: [
{
id: 'testButton',
type: 'button',
button: 'aaaa',
onClick: function() {
// Changing the ID value does work
preview.setValue('Test');
// but changing the textarea does not.
// equation.setValue('Test');
// document.getElementById('equation').setValue('Test');
}
},
{
id: 'equation',
type: 'textarea',
label: lang.dialogInput,
onLoad: function() {
var that = this;
if ( !( CKEDITOR.env.ie && CKEDITOR.env.version == 8 ) ) {
this.getInputElement().on( 'keyup', function() {
// Add \( and \) for preview.
preview.setValue( '\\(' + that.getInputElement().getValue() + '\\)' );
} );
}
},
Sorry if this is a simple question, but how can I access to equation textarea?
After much reading, it seems that this is a way, not sure it's the best way though.
onClick: function() {
this._.dialog.setValueOf("info","equation","TEST");
}