Get current selection info from Froala editor - javascript

I am using Froala WYSIWYG editor in my project. I would like to create my own font-family select component which will display the current font-family. So I need to listen to changes of an editor's selection, each time get current font-family and update my custom component.
import "froala-editor/js/plugins/font_family.min.js";
import Froala from "froala-editor";
const editor = new Froala("#container", {
events: {
onSelectionChange: function() { // I need something like this.
console.log(this.selection.get().fontFamily); // Eg. "Arial" or "Verdana".
}
}
});
I only found fontFamilySelection option in the docs, however, it will show the current font family in a native editor's component. One way is to read the current font family from the native component, but it's not a very clean solution.
Is there any way to do something like this?

Try these three additional event hooks
input - on user input
click - after clicking somewhere in the editor, perhaps into a different tag and font
commands.after - after any menu command, like the native font picker
These hooks allow you to query the font-family style on the current tag.
const editor = new Froala("#container", {
events: {
onSelectionChange: function() { // I need something like this.
console.log(this.selection.get().fontFamily); // Eg. "Arial" or "Verdana".
},
'input': function (inputEvent) {
// after a user input
console.log(this.selection.element().style.fontFamily);
},'click': function (clickEvent) {
// after a user click
console.log(this.selection.element().style.fontFamily);
},
'commands.after': function (cmd, param1, param2) {
// after a command, e.g. the user used the inbuilt font chooser
console.log(this.selection.element().style.fontFamily);
}
}
});
Others might be useful too, from the list at https://froala.com/wysiwyg-editor/docs/events/

Related

TinyMCE: how to let user mark text when "readonly: true;"

I want to let users select (and copy) text within TinyMCE.
I'm not quite sure, but it seems regarding security that browsers don't allow that.
This Codepen is from the official TinyMCE site:
https://codepen.io/tinymce/pen/NGegZK
Here you can select text.
When you add there the following parameter in the 2nd line of the JavaScript as followed, then you can't longer select text.
readonly: true,
How can I set "readonly: true" and let the user still select text?
I appreciate any help.
I faced this problem too. Moreover, the inability to select text is nothing compared to the inability to click links. I've submitted an issue about this a while ago, but there is still no reaction.
You can use a workaround for now (codepen):
readonly: 1,
setup: function(editor) {
editor.on('SwitchMode', function() {
if (editor.readonly) {
editor.readonly = 1;
}
});
}
It exploits the fact that the event-blocking code uses strict comparison internally (readonly === true) while the rest of the code works fine with any other truthy value, e.g. 1. Of course, this hack might stop working after an update in the future, but it's much better than nothing.
Update: better switch to the inline mode (codepen) if you use this hack. Otherwise clicking links leads to a mess.
I have checked the source code of the lastest nightly and it seems that the behavior is hardcoded. All events are discarded if the editor is in readonly mode. Which means that selection events are discarded too :
var isListening = function (editor) {
return !editor.hidden && !editor.readonly;
};
var fireEvent = function (editor, eventName, e) {
if (isListening(editor)) {
editor.fire(eventName, e);
} else if (isReadOnly(editor)) {
e.preventDefault();
}
};
I might be wrong but I don't think you can change this behavior through customization.
Regards
I solved this issue for achieve readonly mode by myself, I would create an iframe dom node and put the editor's html segment into it.
renderReportPreview = contentHtml => {
const iframe = document.querySelector('iframe[name=preview]')
if (iframe) {
const cssLink = document.createElement('link')
// cssLink.href = 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css'
// I prefer semantic-ui, semantic-ui is more like tinyMce style
cssLink.href = 'https://cdn.bootcss.com/semantic-ui/2.3.1/semantic.min.css'
cssLink.rel = 'stylesheet'
cssLink.type = 'text/css'
iframe.contentWindow.document.head.appendChild(cssLink)
// I escape the origin editor's content, so I need decode them back
iframe.contentWindow.document.body.innerHTML = htmlDecode(contentHtml)
const allTables = iframe.contentWindow.document.body.querySelectorAll(
'table'
)
Array.from(allTables).forEach(table => {
// ui celled table for compatible semantic-ui
// table table-bordered for compatible bootstrap
table.className = 'ui celled table table-bordered'
})
this.setState({
previewRendered: true,
})
}
}
More detail on https://github.com/tinymce/tinymce/issues/4575
It was previously possible to select text in readonly mode, until the fix for #4249 broke it in 4.7.12.
We've just started tracking a fix that allows text to be selected and links to be clicked, follow either of the tickets linked here to be updated when we release a fix.

TinyMCE - disable standard save button

I try to disable programmatically the standard "save" button of the save plugin
tinymce.init
({
selector: '#editorMain',
plugins: "save,code,textcolor,charmap,searchreplace,paste,wordcount",
height: 400,
setup: function(editor) {
editor.on('keyup',function(e){
console.log(getStats('editorMain').chars);
var body = tinymce.get('editorMain').getBody();
var currentValue=tinymce.trim(body.innerText || body.textContent);
var currentCharsCount=getStats('editorMain').chars;
var limit=10;
var diff=limit - currentCharsCount;
if (diff>-1)
{
$("#chars_left").html(diff + " characters left");
}
else
{
$("#chars_left").html("Your comment is too long");
// here should we disable the save button
}
});
},
I googled for a solution and found that in version 3.x there was an object called "ControlManager". This has been removed in version 4 (the one I currently use)
According to the documentation the following should be implemented to do that:
// In TinyMCE 4 you can use the simpler stateSelector setting
editor.addButton('SomeButton', {
text: 'My button',
stateSelector: 'a'
});
but how can this work for the "save" button ? the save button comes when I use the "save" plugin, this does not have to be programmatically added.
well that was a tough one. This:
tinymce.activeEditor.theme.panel.find('toolbar *')[1];
enables to access the button. then the ".disabled(1)" method.
That's a pity that we cannot access the elements using their names or ids...
If you don't want the functionality of the save plugin simply remove it from the list in the plugins: init options. Use the list shown here.
tinymce.init
({
selector: '#editorMain',
plugins: "code,textcolor,charmap,searchreplace,paste,wordcount",
....

How to set On Off state for CKEditor custom button

I have added a custom plugin to CKEditor inline to perform bold operation. The plugin is working as expected but the on/off state of button is not working.
When command is executed its state is always TRISTATE_OFF.
CKEDITOR.plugins.add( 'customBold', {
requires: 'toolbar',
icons: 'bold',
hidpi: false,
init: function( editor ) {
var boldCommand = {
exec: function( editor ) {
document.execCommand('bold', false, null);
}
}
editor.addCommand( 'bold', boldCommand );
editor.ui.addButton && editor.ui.addButton( 'Bold', {
label: 'bold',
command: 'bold',
toolbar: 'basic,10'
});
editor.setKeystroke( [
[ CKEDITOR.CTRL + 66 /*B*/, 'bold' ]
]);
}
});
When user selects the bold text I would like to toggle the bold style in toolbar.
You need to call the command.setState method which will set the state of the command which then automatically affects the state of related button.
However, you need to know when to call that method (when the state changes). CKEditor's plugins like the basicstyle plugin use the CKEditor's styles system which let them easily listen on style state changes:
editor.attachStyleStateChange( style, function( state ) {
!editor.readOnly && editor.getCommand( commandName ).setState( state );
} );
You, however, try to use the native commands, which I highly recommend not to. It is not a coincidence that CKEditor implements its own style system and its own commands.
I'm answering this purely because this result constantly came up when I was looking how to apply a style to a CKEditor custom plugin button on the toolbar.
This ended up being fairly simple, although not especially elegant.
Currently, I do my own handling of CKEditor buttons (outside of the plugin.js files). This is because I'm using CKEditor to dynamically create editor instances, which it doesn't seem very well suited to do and I often have to override functions.
Here's how I apply a style to a 'active' button in the editor on the myplugin button action:
//Catch the initial click
$('.parent_element').on('click', '.cke_button__myplugin', function(){
//Apply a gradiant style to the button
$('.cke_button__myplugin').css({'background':' radial-gradient(#FFF, #6E6E6E)'})
//Logic to handle button click
});
This way, you simply apply a style to the button without having to toggle the actual button.png

Changing the default font family in TinyMCE

I've successfully changed the default font inside the editor using the documentation here but that leaves me with a problem. The original default font no longer works in the font drop down list.
Original default: Verdana
New default: MyCustomFont
When I type into the editor I see my MyCustomFont font by default. If I try to change that to Verdana (original default) nothing happens. I can change it to any font family except Verdana. I noticed also that when I select MyCustomFont in the drop down list the content gets surrounded with a span with inline styles. This does not happen with the original default font (hence why nothing happens).
It seems to me like there's a key piece of documentation missing - how to tell the editor (the font feature in particular) that the font I've defined by default in the css is the default font.
I've Googled quite a bit but had no results. Everybody else seems to be settling for the documentation mentioned above. Am I the only one having this problem? If not, please help! :)
Please note, the answers to this question do not answer my question.
maybe too late but...
$('.tinymce').tinymce({
setup : function(ed) {
ed.onInit.add(function(ed) {
ed.execCommand("fontName", false, "Arial");
ed.execCommand("fontSize", false, "2");
});
}
});
EDIT
For TinyMCE 4, as #jason-tolliver and #georg states, the syntax is:
ed.on('init', function (ed) {
ed.target.editorCommands.execCommand("fontName", false, "Arial");
});
// Init TinyMCE
$('#content').tinymce({
setup : function(ed)
{
ed.on('init', function()
{
this.getDoc().body.style.fontSize = '12px';
this.getDoc().body.style.fontFamily = 'serif';
});
}
});
For those who init timymce with tinymce.init({ and cannot implement Radius Kuntoro answer directly.
My init looks like
tinymce.init({
selector: '#editor',
menubar: false,
plugins: ['bbcode'],
toolbar: 'undo redo | bold italic underline',
setup : function(ed)
{
ed.on('init', function()
{
this.getDoc().body.style.fontSize = '12';
this.getDoc().body.style.fontFamily = 'Arial';
});
},
});
For TinyMCE 4.6.3 this seems to be the way to go:
tinymce.init({
setup: function (ed) {
ed.on('init', function (e) {
ed.execCommand("fontName", false, "Verdana");
});
}
});
As refer to TinyMce website you can embed style sheet within your init function like this :
tinymce.init({
content_css : 'path/to/style/sheet',
body_class: 'define-class-name-without-dot-at-the-first'
});
It works and you do not need to setup anything.
check it out on tinyMCE webpage
Some of you will be working within the confines of the TinyMCE EditorManager, which offers two events: AddEditor and RemoveEditor. When a new instance of TinyMCE is being spawned and AddEditor is fired, the editor isn't actually initialized and so calling getDoc() will return null.
What you need to do is create an init listener within.
tinyMCE.EditorManager.on('AddEditor', function (event) {
... other code ...
event.editor.on('init', function() {
this.activeEditor.getDoc().body.style.fontSize = '12px';
this.activeEditor.getDoc().body.style.fontFamily = 'Times New Roman';
});
... other code ...
}
});
This is at least true as of version 4.3.8
I had difficulties with all solutions here in tinymce 4.x
I couldn't change neither fontsize nor fontname. After trying out a lot I found the solution.
First of all I can confirm Jareds answer, thank you for it! Those two commands will not work by default settings:
tinymce.EditorManager.execCommand("fontName", false, "12px");
tinymce.EditorManager.execCommand("fonSize", false, "Arial");
The default fontsize size is "pt", not "px." So either define displayed fontSize as "px" by [fontsize_formats][1] or just handover the desired size with "pt". With tinymce.EditorManager.execCommand tinymce is also not happy. You have to handover the whole font-family like 'arial, helvetica, sans-serif'. These commands worked on my site:
tinymce.EditorManager.execCommand("fontName", false, "12pt");
tinymce.EditorManager.execCommand("fonSize", false, "arial, helvetica, sans-serif");
None of the above solutions worked for me. So, somehow I managed to fix it using custom logic.
editor.on('change', function (e) {
let node = e.target.selection.getNode();
if (node.nodeName === 'P' || node.parentNode.nodeName === 'BODY') {
editor.dom.setStyle(node, 'font-size', "16px");
}
tinymce.triggerSave(); // to keep your textarea synced with above changes
});
This worked for me:
Look for functions.php in root of your themes directory inside /wp-content/themes/yourtheme/, open it up and add one line after php tag.
add_editor_style('custom-editor-style.css');
In the same directory, create a file called custom-editor-style.css with the following lines in it:
#import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700);
* { font-family: 'Open Sans', sans-serif, Arial, Helvetica;}
Go ahead, clear your browser's cache and this is what you’ll see.
Refer link: https://blog.phi9.com/wordpress-editor-and-its-font/
I tried doing this way.
I use TinyMce 5 and inside the editor there is a body tag generated.
While initialising the editor I set the forced_root_block:'div', which means everytime something is being typed my root element will always be a div.
let tinyMceBody = tinymce.activeEditor.getBody();
let divs = $(tinyMceBody).children('div');
for(let i =0; i<divs.length; i++) {
divs[i].style.fontFamily = 'Nunito';
}
So I try catching all the root elements and set default styles to them.
When you edit something, tinymce surrounds whatever you have edited with a span block with a style attribute, so what ever you manually edit in the editor will be overrided. If you don't edit the text in editor then the default styling that we have attached on the parent element forced_root_block:'div' will be retained.
Try formulating a solution as per your custom req. using the above mentioned technique. Seems like the library doesn't have a prominent internal support for this. z
P.S:-
tinymce.activeEditor.dom.setStyles(tinymce.activeEditor.dom.select('div'), {'font-family' : 'Nunito'});
applies to all divs , but I wanted to apply only for the first level children of the body tag and not all divs( includes children of children). Otherwise this could be a solution too.
For tinymce 5 you can add fullpage plugin to plugins array then new key called
fullpage_default_font_family but i don't know if it works the same way for old versions or not.
This is the Answer. It work for me:
STEP # 1:
Look for functions.php in root of your themes directory inside /wp-content/themes/yourtheme/, open it up and add one line after php tag.
add_editor_style('custom-editor-style.css');
STEP # 2:
In the same directory, create a file called custom-editor-style.css with below lines in it
#import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700);
* { font-family: 'Open Sans', sans-serif, Arial, Helvetica;}
Go ahead, clear your browsers cache and this is what you’ll see.
Tony Ngo

ExtJS: starting HtmlEditor defaulting to source

I'm using ExtJS 3.2.1 and I need a component almost identical to the bundled HtmlEditor, with one exception: it must start editing the HTML source code directly. The reason I don't use a normal TextArea is that the user should be able to preview the result of his actions before submitting.
I've tried calling toggleSourceEdit(), as per ExtJS documentation, with no success. Debugging, I see that the editor object has the sourceEditMode property set to true, and the Source Edit button seems as if it was "pressed", but clicking on it does not render the typed HTML, and clicking it again goes to the Source Mode.
I've tried calling toggleSourceEdit() after the container show() method, on the container afterLayout listener and on the editor afterRender listener. I've tried also calling it on another button that I added to the container. The result is the same on every try.
The only other option I see is updating ExtJS to 3.3.0, but I haven't seem anything related on the changelogs. Either way, it's going to be my next step. EDIT: The app had another problems when updating, we'll make a bigger effort to update later. As of right now, we are using the HtmlEditor in its original setting.
Thanks!
ran into the same problem (using 3.3.0 by the way)
stumbled upon a fix by dumb luck. i have no idea why this works, but second time is the charm. call it twice in a row to achieve the desired effect..
HTMLEditor.toggleSourceEdit(true);
HTMLEditor.toggleSourceEdit(true);
hope that helps!
Rather calling toggleSourceEdit(), try to setup the configuration while you create HtmlEditor Object
Using toggleSourceEdit() caused some problems for me. One was that this seemed to put the editor somewhere in limbo between source edit and WYSIWYG mode unless I used a timeout of 250ms or so. It also puts the focus in that editor, and I don't want to start the form's focus in the editor, especially since it's below the fold and the browser scrolls to the focused html editor when it opens.
The only thing that worked for me was to extend Ext.form.HtmlEditor and then overwrite toggleSourceEdit, removing the focus command. Then adding a listener for toggling to the source editor when the component is initialized. This is for Ext 4.1 and up. For older versions, replace me.updateLayout() with me.doComponentLayout().
var Namespace = {
SourceEditor: Ext.define('Namespace.SourceEditor', {
extend: 'Ext.form.HtmlEditor',
alias: 'widget.sourceeditor',
initComponent: function() {
this.callParent(arguments);
},
toggleSourceEdit: function (sourceEditMode) {
var me = this,
iframe = me.iframeEl,
textarea = me.textareaEl,
hiddenCls = Ext.baseCSSPrefix + 'hidden',
btn = me.getToolbar().getComponent('sourceedit');
if (!Ext.isBoolean(sourceEditMode)) {
sourceEditMode = !me.sourceEditMode;
}
me.sourceEditMode = sourceEditMode;
if (btn.pressed !== sourceEditMode) {
btn.toggle(sourceEditMode);
}
if (sourceEditMode) {
me.disableItems(true);
me.syncValue();
iframe.addCls(hiddenCls);
textarea.removeCls(hiddenCls);
textarea.dom.removeAttribute('tabindex');
//textarea.focus();
me.inputEl = textarea;
} else {
if (me.initialized) {
me.disableItems(me.readOnly);
}
me.pushValue();
iframe.removeCls(hiddenCls);
textarea.addCls(hiddenCls);
textarea.dom.setAttribute('tabindex', -1);
me.deferFocus();
me.inputEl = iframe;
}
me.fireEvent('editmodechange', me, sourceEditMode);
me.updateLayout();
}
})
}
Then to use it:
Ext.create('Namespace.SourceEditor', {
/*regular options*/
listeners: {
initialize: function(thisEditor) {
thisEditor.toggleSourceEdit();
}
}
});
htmlEditor.toggleSourceEdit(true);
one time should be enough if you do this listening to the afterrender event of the editor.

Categories

Resources