TinyMCE Enable button while in read only mode - javascript

I have a TinyMCE 4.x instance where the text should be in read only mode. But I still have some buttons that I want to have enabled. For example, one button could provide a character count for the part of the text I've selected.
But when I turn on read only mode for TinyMCE all buttons are disabled. Can I enable just my buttons while still retaining read only mode?

It's probably too late for you but other people may pass by here.
I came up by writing this function
function enableTinyMceEditorPlugin(editorId, pluginName, commandName) {
var htmlEditorDiv = document.getElementById(editorId).previousSibling;
var editor = tinymce.get(editorId);
var buttonDiv = htmlEditorDiv.querySelectorAll('.mce-i-' + pluginName.toLowerCase())[0].parentElement.parentElement;
buttonDiv.className = buttonDiv.className.replace(' mce-disabled', '');
buttonDiv.removeAttribute('aria-disabled');
buttonDiv.firstChild.onclick = function () {
editor.execCommand(commandName);
};
}
It does the trick in 2 steps:
make the button clickable (remove mce-disabled CSS class and remove the aria-disabled property)
assign the good command to the click event
And in my editor init event I call the function.
editor.on('init', function () {
if (readOnly) {
editor.setMode('readonly');
enableTinyMceEditorPlugin(htmlEditorId, 'preview', 'mcePreview');
enableTinyMceEditorPlugin(htmlEditorId, 'code', 'mceCodeEditor');
}
});
Current version of TinyMCE for which I wrote this code is 4.4.3. It may break in a future version, specifically about the selectors to get and modify the good HTML elements.
Command identifiers can be found at this page otherwise you can also find them under tinymce\plugins\PluginName\plugin(.min).js

Here is a simple way to enable your custom toolbar button and attach a click event handler inside a read only TinyMCE editor using JQUERY:
//Initialize read only Tinymce editor so that Lock button is also disabled
function initReadOnlyTinyMCE() {
tinymce.init({
selector: '#main'
, toolbar: 'myLockButton'
, body_class: 'main-div'
, content_css: 'stylesheets/index.css'
, readonly: true
, setup: function (readOnlyMain) {
readOnlyMain.addButton('myLockButton', { //Lock button is disabled because readonly is set to true
image: 'images/lock.png'
, tooltip: 'Lock Editor'
});
}
});
}
function displayReadOnlyTinyMCEwithLockButtonEnabled() {
var edContent = $('main').html();
$("#main").empty();
initReadOnlyTinyMCE(true);
tinyMCE.activeEditor.setContent(edContent);
//enable the lock button and attach a click event handler
$('[aria-label="Lock Editor"]').removeClass("mce-disabled");
$('[aria-label="Lock Editor"]').removeAttr("aria-disabled");
$('[aria-label="Lock Editor"]').attr("onclick", "LockEditor()");
}
function LockEditor() {
alert("Tiny mce editor is locked by the current user!!");
//Write your logic to lock the editor...
}

I couldn't find an easy way to do this. The simplest way is to remove the contenteditable attribute from the iframe body instead and substitute a read only toolbar set. It also means that people will still be able to copy content from the editor.
$("iframe").contents().find("body").removeAttr("contenteditable");

How about this :
editor.addButton('yourButton', {
title: 'One can Enable/disable TinyMCE',
text: "Disable",
onclick: function (ee) {
editor.setMode('readonly');
if($(ee.target).text() == "Disable"){
var theEle = $(ee.target).toggle();
var edit = editor;
var newBut = "<input type='button' style='opacity:1;color:white; background-color:orange;' value='Enable'/>";
$(newBut).prependTo($(theEle).closest("div")).click(function(e){
edit.setMode('design');
$(e.target).remove();
$(theEle).toggle();
});
}
}
});

You can try to run the code below:
$("#tinymce").contentEditable="false";
if you have more than one editors, you can use their id like below
$("#tinymce[data-id='idOfTheEditor']").contentEditable="false";

Related

In Quilljs Editor, How to insert an undeletable block-level element?

Here I customize a block element by Quill.import('blots/block/embed') which I insert into the editor content. I would like to know that if there is any way to make it undeletable, therefore the user could not delete it or edit it? Thanks a lot.
I had a similar issue and the solution I came up with was to intercept the keyboard binding for backspace. In the example here I have a custom 'video' blot. So, if backspace is entered and the cursor is on or directly after a video, it does nothing. Here is the documentation for the Keyboard Module for reference: https://quilljs.com/docs/modules/keyboard/
let _this = this;
this.quill = new Quill(this.contentElement, {
modules: {
keyboard: {
bindings: {
video: {
key: 'backspace',
handler: function(range, keycontext) {
let format = _this.quill.getFormat(range.index - 1);
if (!format.video && !keycontext.format.video) {
// propogate to Quill's default
return true;
} // else do nothing to prevent deleting video
}
}
}
}
},
theme: 'snow'
});
Also, another thing to keep in mind, the editor has contenteditable="true", which your custom blot will inherit. So you'll probably want to set contenteditable="false" on the node in your custom blot.

How to remove buttons in tinymce editor for the non-default wordpress editor

I can see numerous examples on removing buttons in the tinymce editor but I want to do this for a custom editor I am adding from Javascript.
function myplugin_tinymce_buttons( $buttons ) {
//Remove the text color selector
$remove = 'forecolor';
//Find the array key and then unset
if ( ( $key = array_search( $remove, $buttons ) ) !== false )
unset( $buttons[$key] );
return $buttons;
}
There is no mention of editor ID here. How do I do this only for a custom editor? I dont want to change anything in the main editor shown in Wordpress post page.
The best and cleanest way is definitely to change your TinyMCE config before initialization.
Otherwise you can refer to my answer on another question where I set the editor in ReadOnly mode then enable just few buttons.
I didn't test this code but your function should be something like this:
function removeButton(editorId, pluginName, commandName) {
var htmlEditorDiv = document.getElementById(editorId).previousSibling;
var editor = tinymce.get(editorId);
var buttonDiv = htmlEditorDiv.querySelectorAll('.mce-i-' + pluginName.toLowerCase())[0].parentElement.parentElement;
buttonDiv.style.display = "none";
buttonDiv.firstChild.onclick = function () {
//Even if the button is invisible, it's better
//removing the command associated to the button click just in case
};
}
For the list of commands, refer to this page

CKEditor default style for styleCommand (format styles with buttons)

I have created a CKEditor plugin which does the base p, h2, h3, h4 formatting with custom buttons (instead of the stylescombo). It works great, but if I uncheck an element (ex. 'h2'), sets the 'div' tag as parent element for the row. I want to be the 'p' as the default element and also the 'p' button can't be unchecked (unless I clicking on another, ex. 'h2' button). How is this possible?
The plugin looks like:
CKEDITOR.plugins.add('stylesbuttons_custom',{
lang:'en',
icons:'p,h2,h3,h4',
init:function(editor){
var order=0;
var addButtonCommand=function(buttonName,buttonLabel,commandName,styleDefiniton){
if (!styleDefiniton)
return;
var style=new CKEDITOR.style(styleDefiniton);
editor.attachStyleStateChange(style,function(state){
!editor.readOnly && editor.getCommand(commandName).setState(state);
});
editor.addCommand(commandName,new CKEDITOR.styleCommand(style));
if (editor.ui.addButton){
editor.ui.addButton(buttonName,{
label:buttonLabel,
command:commandName,
toolbar:'basicstyles,'+(order+=10)
});
}
};
var lang=editor.lang.stylesbuttons_custom;
addButtonCommand('P',lang.p,'p',{element:'p'});
addButtonCommand('H2',lang.h2,'h2',{element:'h2'});
addButtonCommand('H3',lang.h3,'h3',{element:'h3'});
addButtonCommand('H4',lang.h4,'h4',{element:'h4'});
}
});
I load the plugin like:
config.extraPlugins='stylesbuttons_custom';
I put buttons to toolbar like:
config.toolbar:[['P','H2','H3','H4','Pre']];
Here is a screenshot about the problem:
Cross posting my answer from CKEditor forum.
I think that you need to write your own command instead of using CKEDITOR.styleCommand.
It should work exactly like CKEDITOR.styleCommand when style is not yet applied on current selection.
But when clicked again it should apply the paragraph style, not remove the previously applied style. E.g:
styleCommand.prototype.exec = function( editor ) {
editor.focus();
if ( this.state == CKEDITOR.TRISTATE_OFF )
editor.applyStyle( this.style );
else if ( this.state == CKEDITOR.TRISTATE_ON )
editor.applyStyle( paragraphStyle );
};
PS. I created a ticket: http://dev.ckeditor.com/ticket/10190 because I think that removing block style should revert back to paragraph (in enterMode=P). For now use the above workaround.
Yes, #Reinmar notifies that there is an error in the CKEditor's style.js where the this._.enterMode is not defined.
Doing this on style.js, resolve the problem:
this._ = {
definition: styleDefinition,
enterMode: CKEDITOR.config.enterMode
};
And from now on when a style button is unchecked the block changes to the default 'p' element.
Now my complete working plugin looks like:
(function(){
CKEDITOR.plugins.add('custombuttons',{
lang:'hu,en,de,ro',
init:function(editor){
var order=0,t=this,lang=editor.lang.custombuttons;
// addButtonCommand helper
var addButtonCommand=function(buttonName,buttonLabel,commandName,styleDefiniton){
var style=new CKEDITOR.style(styleDefiniton);
var styleCommand=function(style){
this.style=style;
this.allowedContent=style;
this.requiredContent=style;
this.contextSensitive=true;
};
styleCommand.prototype={
exec:function(editor){
editor.focus();
if (this.state==CKEDITOR.TRISTATE_OFF)
editor.applyStyle(this.style);
else if (this.state==CKEDITOR.TRISTATE_ON)
editor.removeStyle(this.style);
if(commandName!='fakecommand'){editor.execCommand('fakecommand');editor.execCommand('fakecommand');} /* hack to change button state properly */
},
refresh:function(editor,path){
this.setState(path&&this.style.checkApplicable(path)?(this.style.checkActive(path)?CKEDITOR.TRISTATE_ON:CKEDITOR.TRISTATE_OFF):CKEDITOR.TRISTATE_DISABLED);
}
};
editor.addCommand(commandName,new styleCommand(style));
if(editor.ui.addButton){editor.ui.addButton(buttonName,{label:buttonLabel,command:commandName,toolbar:'basicstyles,'+(order+=10),icon:t.path+'images/'+commandName+'.png'});}
};
// _fakebutton (hack)
addButtonCommand('_fakebutton','','fakecommand',{element:'span'});
// style buttons
addButtonCommand('P',lang.p,'p',{element:'p'});
addButtonCommand('H2',lang.h2,'h2',{element:'h2'});
addButtonCommand('H3',lang.h3,'h3',{element:'h3'});
addButtonCommand('H4',lang.h4,'h4',{element:'h4'});
addButtonCommand('Pre',lang.pre,'pre',{element:'pre'});
addButtonCommand('Mini',lang.mini,'mini',{element:'p',attributes:{class:'mini'}});
addButtonCommand('Important',lang.important,'important',{element:'span',attributes:{class:'important'}});
addButtonCommand('Comment',lang.comment,'comment',{element:'span',attributes:{class:'comment'}});
addButtonCommand('Mark',lang.mark,'mark',{element:'mark'});
addButtonCommand('ImgLeft',lang.imgLeft,'imgLeft',{element:'img',attributes:{class:'imgleft'}});
addButtonCommand('ImgRight',lang.imgRight,'imgRight',{element:'img',attributes:{class:'imgright'}});
addButtonCommand('ImgCenter',lang.imgCenter,'imgCenter',{element:'img',attributes:{class:'imgcenter'}});
// button shortcut keys
editor.setKeystroke(
[
[CKEDITOR.CTRL+48,'p'], // Ctrl+0
[CKEDITOR.CTRL+49,'h2'], // Ctrl+1
[CKEDITOR.CTRL+50,'h3'], // Ctrl+2
[CKEDITOR.CTRL+51,'h4'], // Ctrl+3
]);
}
});
})();
There is still a hack in the code. I needed to run a 'fakecommand' to really update (refilter?) the changed tags and all its parent tags. For example the 'p.mini' button caused problems (the state was not updated) when clicked multiple time. So there is still an unelegant solution. Any idea how to force to update or refilter the code after a style is applied?

Use Ckeditor like a simple input text

I need to use CKEDITOR ( http://ckeditor.com/ ) like a simple
<input type="text" />
I modified the file config.js adding the following settings:
config.toolbar = 'SimpleVersion';
config.toolbar_SimpleVersion =
[
['Cut','Copy','Paste','PasteText'],
];
Then, in the main page:
editor = CKEDITOR.replace("mydiv", { toolbar : 'SimpleVersion' });
editor.config.height = 50;
editor.config.removePlugins = 'resize';
editor.config.resize_enabled = false;
It works, but I need, if it's possible, to remove the bottom part where "body" is written, and also inhibit the new line whenever the Return button is pressed.
I think that for the last one, it may be possible to use a JQuery trigger.
Removing plugin works good. But on new line below code worked for me:
editor.on('key', function(e) {
var key = e.data.keyCode;
if(key==13){
e.cancel();
}
}
);
I found the solution:
1) when I create the editor there is a configuration option to toggle the bottom part of the editor
editor = CKEDITOR.replace("mydiv", { toolbar : 'SimpleVersion', removePlugins : 'elementspath' });
2) to inhibite the return button I've created the following trigger on key:
editor.on('key', function(e) {
var key = e.data.keyCode;
if(key==13){
return false;
}
}
);

Assigning some style from the styles-box in CKEditor through JavaScript

How can I simulate user-selection of some style from the styles-box, through JS? I want to put some shortcut buttons that assign some of the popular styles with one click.
EDIT:
I don't care if it'll be in-editor button or outer button.
I don't want css-style assignment; I want CKEditor-style assignment (those of the styles-box).
I haven't used CKEditor, but, I saw your question and thought "That would be fun to figure out." Well, here is what I figured out:
(yes, I found terrible documentation, but, that's not the point...I will give them props for commenting their code, though.)
///
// function to add buttons that trigger styles to be applied.
//
// editor - CKEDITOR - instance of editor you want command attached to.
// buttonName - String - name of the button
// buttonLabel - String - humane readable name of the button
// commandName - String - name of command, the way to call this command from CKEDITOR.execCommand()
// styleDefinition - StyleDefinition - obj defining the style you would like to apply when this command is called.
///
var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, styleDefiniton )
{
var style = new CKEDITOR.style( styleDefiniton );
editor.attachStyleStateChange( style, function( state )
{
!editor.readOnly && editor.getCommand( commandName ).setState( state );
});
editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
editor.ui.addButton( buttonName,
{
label : buttonLabel,
command : commandName
//adding an icon here should display the button on the toolbar.
//icon : "path to img",
});
};
//Get the editor instance you want to use. Normally the same as the ID of the textarea CKEditor binds to.
var editor1 = CKEDITOR.instances.editor1;
//If you look at ckeditor/_source/plugins/styles/default.js you will see that this selects the first element. That list is read into the array 'default'.
var blueTitleStyle = CKEDITOR.stylesSet.registered.default[0];
//Or, you can define the style like this: See http://dev.ckeditor.com/wiki/Components/Styles for more info on style definitions.
var blueTitleStyle = {
name : 'Blue Title',
element : 'h3',
styles : { 'color' : 'Blue' }
};
addButtonCommand(editor1, 'BlueTitle', 'BlueTitle', 'bluetitle', blueTitleStyle);
Here is a Javascript function to aid your click events:
//function used to execute the command. Only used for calling the command when not calling from a button. (Like an A with an onClick bound to it.)
//pulled this function right out of the api.html example in the ckeditor/_samples dir.
function ExecuteCommand( commandName )
{
// Get the editor instance that we want to interact with.
var oEditor = CKEDITOR.instances.editor1;
// Check the active editing mode.
if ( oEditor.mode == 'wysiwyg' )
{
// Execute the command.
// http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.editor.html#execCommand
oEditor.execCommand( commandName );
}
else
{
alert( 'You must be in WYSIWYG mode!' );
}
}
Now, you can create a link like this:
<a href='#' class='setBlueTitle'>Set Blue Title</a>
and use a bit of jQuery to spice it up:
<script type="text/javascript">
$(document).ready(function(){
$(".setBlueTitle").onClick(function(e){
//stops the click from changing the page and whatever other default action would happen.
e.preventDefault();
ExecuteCommand('bluetitle');
});
});
</script>
I am not 100% sure about the button icon part. I didn't have an icon to try it with. But, according to a few posts, it should work fine. Regardless, the jQuery click binding works.
That should be pretty much it! I had to do quite a bit of digging around to figure this out, but it certainly is satisfying to see it work!
Here's one option
First, you can setup the desired styles you want to try out in a CSS class. Then, you can set the className for the test div when you click that button. Here's a simple example:
test.css:
.bold {
font-weight: bold;
}
.italic {
font-style: italic;
}
test.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css" />
</head>
<body>
<input type="button" onclick="document.getElementById('testStyleDiv').className='bold'" value="bold"/>
<input type="button" onclick="document.getElementById('testStyleDiv').className='italic'" value="italic"/>
<div id="testStyleDiv">foo</div>
</body>
</html>

Categories

Resources