How can I add custom HTML instead of regular button in TinyMCE 4 inside the split button drop menu?
ed.addButton('demo_button', {
title: 'Demo Button',
type: 'splitbutton',
onclick: function() {
},
menu: [
{
text : 'Some Regular Button', onclick : function() {
}
},
{
//How to add some custom html for combo box here for example?
}
]
});
In previous version (TinyMCE 3) I was able to use this:
var c = cm.createSplitButton('demo_button', {
title : 'Demo Button',
onclick : function() {
}
});
c.onRenderMenu.add(function(c, m) {
m.onShowMenu.add(function(c,m){
var $menu = jQuery('#menu_'+c.id+'_co').find('tbody:first');
if($menu.data('added')) return;
$menu.append('SOME HTML HERE');
$menu.data('added',true);
});
});
So basically my question is how to migrate this piece of code to TinyMCE 4?
Cheers
If you were using TinyMCE 3.0 are now migrating to TinyMCE 4+, may be you can first try using their compat3x plugin, which will allow you to transition most of your old plugins without modifications as per their documentation available here:
TinyMCE compat3x plugin
Like you did with the v3, you have to edit the dom after TinyMCE rendering.
To catch rendering process, use init_instance_callback
See : http://www.tinymce.com/wiki.php/Configuration%3ainit_instance_callback
And this SO answer : https://stackoverflow.com/a/24557748/911718
Related
I created a custom link button and want it appear highlighted/selected when you select/click on the link in the text editor, just like clicking on bold text shows the Bold icon as selected. In TinyMCE 4 you could simply use "stateSelector" to have it highlight when that kind of DOM element was selected, like this:
editor.ui.registry.addButton('SpecialLink', {
icon: 'link',
onAction: makeSpecialLink(),
**stateSelector: 'a[href]'**
});
I can't find anything about what stateSelector was replaced with in TinyMCE 5 and so far all I've been able to do is recreate some of that functionality inside tinymce.init:
init_instance_callback: function(editor) {
editor.on("SelectionChange", function(e){
let elem = editor.selection.getNode();
if( $(elem).is("a") )
console.log("Highlight the Special Link button");
else
console.log("Deselect the Special Link button");
})
}
I can reference myMCE.plugins.SpecialLink, but I can't call setActive(true) on it.
Any help would be greatly appreciated!
You can use addToggleButton rather than addButton, then call setActive.
Here's a snippet of my code.
editor.ui.registry.addToggleButton('my-action', {
icon: null,
text: 'My action',
onAction: function onAction() {
// ...do stuff
},
onSetup: function(api) {
function nodeChangeHandler(){
const selectedNode = editor.selection.getNode();
return api.setActive(selectedNode.id === constants.id);
}
editor.on('NodeChange', nodeChangeHandler);
}
});
}
https://www.tiny.cloud/docs/ui-components/typesoftoolbarbuttons/#togglebutton
#Muki's answer is similar to what I did, but I referenced the core code for anchor button from tinymce's git repo here https://github.com/tinymce/tinymce/blob/develop/modules/tinymce/src/plugins/anchor/main/ts/ui/Buttons.ts
I changed editor.ui.registry.addButton to editor.ui.registry.addToggleButton and added onSetup: (buttonApi) => editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind instead of stateSelector after onAction.
Something like below:
editor.ui.registry.addToggleButton('SpecialLink', {
icon: 'link',
onAction: makeSpecialLink(),
onSetup: (buttonApi) => editor.selection.selectorChangedWithUnbind('a:not([href])', buttonApi.setActive).unbind
});
I'm trying to create a select dialog that supports optgroup. The built in 'select' dialog doesn't handle that so I'm using the 'html' type dialog. It's working fine, but I'd like to put the focus on that select box when the dialog opens.
I've tried various things, but I can't get it to work. I'm wondering if I need to override getInputElement() and have it return the select element so I can call focus() on it, but I have no idea how to do that.
I also tried selecting the element with jQuery and using its focus() method, but that doesn't work.
I found that I can define a focus() function on the dialog element and in there make the appropriate call to the jQuery .focus().
CKEDITOR.dialog.add( 'myDialog', function( editor ) {
"use strict";
return {
title: 'Custom Dialog',
contents: [
{
id: 'tab-basic',
elements: [
{
type: 'html',
id: 'mealplan_select',
html: '<select id="my-select"></select>',
focus: function() {
$('#my-select').focus();
},
onShow: function() {
// focus this element
this.getInputElement().focus();
}
}
]
}
]
};
});
Add the jQuery TextareaResizer jquery.textarearesizer.js library that StackOverflow uses to a textarea form field that us used by the jQuery edit in place library X-Editable
I have a simple working demo of the Textarearesizer.js plugin here http://codepen.io/jasondavis/pen/KpWybW which adds a Drag Hanlde to a textarea field and lets you click and drag to resise it.
I then try to add that same JavaScript code to make it work on a Textarea field generated from X-Editable here on this JSFiddle: http://jsfiddle.net/jasondavis/xBB5x/8558/
X-Editable JavaScript:
$('#description').editable({
type: 'textarea',
url: '/post',
pk: 1,
inputclass: 'task_description resizable',
highlight: '#F1FFE7',
mode: 'inline', // inline | popup
placement: 'top',
title: 'Enter Task Description',
validate: function(value) {
if ($.trim(value) === '') {
return 'Task Description is Required';
}
},
params: function(params) {
//Addition params in addition to the default: pk, name, value
params.userId = 1;
params.projectId = projectTaskModal.cache.projectId;
params.taskId = projectTaskModal.cache.taskId;
return params;
},
success: function(response, newValue) {
if (!response.success) return response.msg;
}
});
Textarea Resizer JavaScript:
/* jQuery textarea resizer plugin usage for Textarea */
$(document).ready(function() {
$('textarea.resizable:not(.processed)').TextAreaResizer();
});
I don't get any error messages however the Textarea field does not run the resizer code.
On the JSFiddle demo http://jsfiddle.net/jasondavis/xBB5x/8558/ when you click teh Text, the Textarea is revealed.
I think it may have something to do with the Textarea not being visible when the $('textarea.resizable:not(.processed)').TextAreaResizer(); code is ran since X-Editable does not show the Textarea until after you click on the text.
I also tried to do this:
$('#description').on('init', function(e, editable) {
$('textarea.resizable:not(.processed)').TextAreaResizer();
});
which runs my callback code when the editable field is initialized
I got it figured out. MY Textarea generated by X-Editable was not being generated in the DOM until after my call to the TextareaReizer plugin.
The solution was to use this Event that is ran after the form textarea is shown in the DOM...
$('#description').on('shown', function(e, editable) {
$('textarea.resizable:not(.processed)').TextAreaResizer();
});
Final solution demo working here http://jsfiddle.net/jasondavis/xBB5x/8559/
I'm working on a TinyMCE plugin and one thing I want it to do is register commands/buttons that toggle custom formatting.
For example if you click the bold button in TinyMCE it will show the bold button highlighted while in bold text. Digging into the source code I see this happens via: tinymce.EditorCommands.addCommands thought I can't seem to figure out how to duplicate it. The documentation of TinyMCE is just horrible as well =(
So given customFormat I want to be able to have a button setup by my plugin that when the customFormat is applied it shows as such like the Bold, Italics, and other such buttons do on the toolbar. And clicking on my customFormat toggles that format on/off. I can easily accomplish the toogle via "addCommand" and "addButton" but then it does not have state tracking like Bold and others do.
Showing my current non-working attempt (this code is inside init of my plugin create method):
tinymce.EditorCommands.call('addCommands', {
'MyFormat' : function(name) {
ed.formatter.toggle("customFormat");
}
},'exec');
tinymce.EditorCommands.call('addCommands', {
'MyFormat' : function(name) {
return ed.formatter.match('customFormat');
}
},'state');
ed.addButton('customformat', {cmd : 'MyFormat'});
And here is the link to the "documentation" of addCommands:
http://www.tinymce.com/wiki.php/API3:method.tinymce.EditorCommands.addCommands
After a lot more looking around I found this which seems to be perfect:
http://www.tinymce.com/wiki.php/API3:method.tinymce.Editor.addQueryStateHandler
But when I implement the code it doesn't change the state of the button:
ed.addCommand('MyFormat', function(ui, v) {
ed.formatter.toggle("thoughtFormat");
});
ed.addQueryStateHandler('MyFormat', function() {
return ed.formatter.match('thoughtFormat');
});
ed.addButton('myformat', {cmd : 'MyFormat'});
In case someone doesn't want to do it the 'plug-in' way, here's the guide for TinyMCE 4.x.
First of all, you need to define a custom format:
formats: {
custom_format: {inline: 'span', styles: {color: "red"}, attributes: {class: 'some_css_class'}}
}
Then you'll have to add a button to your toolbar:
toolbar: "mybutton",
Next, you need to setup your button, so that it toggles the format:
setup: function(editor) {
editor.addButton('mybutton', {
text: 'My button',
icon: false,
onclick: function() {
tinymce.activeEditor.formatter.toggle('custom_format')
}
});
}
Furthermore, if you want the editor to set the state of the button to indicate the format of current node, automatically, add this to setup function:
onPostRender: function() {
var ctrl = this;
editor.on('NodeChange', function(e) {
ctrl.active(e.element.className == "some_css_class")
});
}
Your tinymce.init function should look like this:
tinymce.init({
selector: "textarea",
formats: {
// Other formats...
custom_format: {inline: 'span', styles: {color: "red"}, attributes: {class: 'some_css_class'}}
}
// Other default toolbars
toolbar_n: "mybutton",
// Finally, setup your button
setup: function(editor) {
editor.addButton('mybutton', {
text: 'My Button',
icon: false,
onclick: function() {
tinymce.activeEditor.formatter.toggle('custom_format')
},
onPostRender: function() {
var ctrl = this;
editor.on('NodeChange', function(e) {
ctrl.active(e.element.className == "some_css_class")
});
}
});
}
Note that class attribute I added to my custom format. This approach made it possible for me define my custom styles in a separate stylesheet file and keep my markup as dry as possible (No inline styling!). Point content_css option to your stylesheet and you'll be good to go.
However, due to fact that I'm using Rails as back-end and BatmanJS as front-end (and I'm fairly new to the latter), I couldn't figure out how assets routing works, and ended up adding my custom styles to default content stylesheet file of tinyMCE skin itself (located at skins/SKIN_NAME/content.min.css).
Thanks to Thariama for insights that allowed me to dig deeper finally figuring out how to do this. I'm not sure its the "right way" but as I said TinyMCE has the worst documentation imaginable.
The key for me was to make an hook the onNodeChange event, using the setActive trick. Full example plugin with a custom button that activates when that format is present wherever the cursor is:
(function() {
tinymce.create('tinymce.plugins.CoolPlugin', {
init : function(ed, url) {
ed.addCommand('MyFormat', function(ui, v) {
ed.formatter.toggle("myFormat");
});
ed.addButton("coolformat", {
title : 'MyFormat Tooltip',
cmd : 'MyFormat',
image: url + '/coolformat.png',
});
ed.onNodeChange.add(function(ed, cm, n) {
active = ed.formatter.match('myFormat');
control = ed.controlManager.get('coolformat').setActive(active);
});
ed.onInit.add(function(ed, e) {
ed.formatter.register('myFormat',
{inline: 'span', classes : ['cool'] } );
});
}
});
// Register plugin
tinymce.PluginManager.add('cool', tinymce.plugins.CoolPlugin);
})();
Here is an example:
ed.controlManager.get('my_control_element').setActive(true); // could be bold or whatever
I see a lot of google posts on this but all seems to be talking about how this is in progress. Does anyone know of a working version of jeditable and autocomplete functionality working together so i can click on text and get a textbox and have autocomplete functionality working against that textbox
EDIT:
I am opening a bounty, as it still seems like none of these solutions replicate Stack overflow tags + jeditable where i can use jeditable to get a editable texbox after clicking on text and then be able to enter a comma separated list that autocomplete each entry as i type (similar to entering tags in stack overflow).
Take a look at this
JQuery Based Inplace Editing + AutoComplete
Usage
$('#edit').editable( 'echo.php', // POST URL to send edited content
{ indicator : , // options for jeditable
event: 'click' // check jeditable.js for more options
},
{ url: "search.php", //url form where autocomplete options will be extracted
minChars: 1, // check autocomplete.js for more options
formatItem:formatItem,
selectOnly: 1,
inputSeparator:';' // a new option of inputSeparator was introduced.
}
);
You can use ',' as input separator.
This is exactly what Jeditable custom inputs are for. Check quick and dirty
working demo (start typing something starting with letter a).
Demo was done in 5 lines of code. It uses Jörn Zaefferer's Autocomple plugin for autocompletion:
$.editable.addInputType('autocomplete', {
element : $.editable.types.text.element,
plugin : function(settings, original) {
$('input', this).autocomplete(settings.autocomplete.data);
}
});
Then you can call Jeditable with something like:
$(".autocomplete").editable("http://www.example.com/save.php";, {
type : "autocomplete",
tooltip : "Click to edit...",
onblur : "submit",
autocomplete : {
multiple : true,
data : ["Aberdeen", "Ada", "Adamsville", "Addyston", "Adelphi", "Adena", "Adrian", "Akron"]
}
});
I had the need for the same functionality with jeditable and autocomplete from bassistance, for a list of emails separated by a comma. So, I changed the demo from Mika Tuupola and had it working like this:
$.editable.addInputType('autocomplete', {
element: $.editable.types.text.element,
plugin: function(settings, original) {
$('input', this).autocomplete(settings.autocomplete.urlOrData,
settings.autocomplete.options);
}
});
And when you call jEditable you need to add the following:
$('.autocomplete').editable('http://www.example.com/save', {
type: 'autocomplete',
autocomplete: {
urlOrData: ["Aberdeen", "Ada", "Adamsville"] , // can also be url: 'http://www.example.com/autocomplete',
options: {
multiple: true
}
}
});
The basic thing to understand here is that when you call $('input', this).autocomplete(...) you are actually applying the autocomplete plugin functionality to the editable input, and that's where you must pass the autocomplete options, via the settings object, which is the same as the settings you pass to jeditable.
Editable: jQuery jeditable I've used it recently in my project (as such and with slight modification to work with page methods)
AutoComplete: bassistance
Combining it with jQuery UI isn't much different to Mika's example above. This works for me
$.editable.addInputType('autocomplete', {
element : $.editable.types.text.element,
plugin : function(settings, original) {
$('input', this).autocomplete(settings.autocomplete);
}
});
$(".autocomplete").editable("http://www.example.com/save.php", {
type : "autocomplete",
tooltip : "Click to edit...",
onblur : "submit",
autocomplete : {
minLength : 2,
source : ["Aberdeen", "Ada", "Adamsville", "Addyston", "Adelphi", "Adena", "Adrian", "Akron"]
}
});
Complete working integration of dataTable, dataTables editable (legacy), jEditable, autocomplete jQuery plugins with AJAX source and results updated at bottom on page(i.e. appended to body of html) is solved by:
$.editable.addInputType('autocomplete', {
element: $.editable.types.text.element,
plugin: function(settings, original) {
var $row = $(this).closest('tr').prop('id');
settings.autocomplete.appendTo = "#results-"+$row;
$('input', this).autocomplete(settings.autocomplete);
}
});
Datatable legacy editable code:
{
tooltip: 'Click to update Owner',
type: 'autocomplete',
autocomplete: {
serviceUrl: './search/users/by/name',
minChars: 5,
paramName: 'username',
dataType: 'json'
},
cancel : 'Cancel',
submit : 'Submit',
}
TD in table have:
<td id="results-${obj.taskId}">