How to remove MenuItemTitle from TinyMCE? - javascript

I have enabled the 'fontsizeselect' plugin in tinyMCE. My question is how do I remove the header (title) of the drop-down menu?
Edit:
I've tried removing it using JQuery .remove(), but after that the height of whole list is calculated wrong.
The second option I tried was:
http://www.tinymce.com/wiki.php/API3:method.tinymce.ui.DropMenu.remove
But that just went wrong and "fontsizeselect.remove(title)" (analogically to .add) makes error to whole tinyMCE - "missing : after property id". Problably it is completly bad method to do this.
The third option was editing tiny_mce\themes\advanced\editor_template_src.js line 467:
c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) {...}
but seems, that TinyMCE developers thought, that every drop-down must have title/header

SOLVED:
before initialization of MCE we have to override the menu rendering function
(function(tinymce) {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, undef;
tinymce.create('tinymce.ui.ListBoxNoTitle:tinymce.ui.ListBox', {
renderMenu : function() {
var t = this, m;
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
menu_line : 1,
'class' : t.classPrefix + 'Menu mceNoIcons',
max_width : 250,
max_height : 150
});
m.onHideMenu.add(function() {
t.hideMenu();
t.focus();
});
/* m.add({
title : t.settings.title,
'class' : 'mceMenuItemTitle',
onclick : function() {
if (t.settings.onselect('') !== false)
t.select(''); // Must be runned after
}
});
*/
each(t.items, function(o) {
// No value then treat it as a title
if (o.value === undef) {
m.add({
title : o.title,
role : "option",
'class' : 'mceMenuItemTitle',
onclick : function() {
if (t.settings.onselect('') !== false)
t.select(''); // Must be runned after
}
});
} else {
o.id = DOM.uniqueId();
o.role= "option";
o.onclick = function() {
if (t.settings.onselect(o.value) !== false)
t.select(o.value); // Must be runned after
};
m.add(o);
}
});
t.onRenderMenu.dispatch(t, m);
t.menu = m;
}
});
})(tinymce);
And with this comment on "m.add" You just have to add
tinyMCE.init({
setup : function(ed) {
ed.onBeforeRenderUI.add(function(ed){
ed.controlManager.setControlType('listbox', tinymce.ui.ListBoxNoTitle);
});
}
});
this setup to standard initialization of tinyMCE. So, it can be done without editing source files.

Related

FullCalendar v4 add onclick eventListener to events displayed on eventLimitClick popover

I have a custom development with FullCalendar v4 js and I'm encountering a problem with eventLimitClick method.
When I click on it I want all events displayed inside popover to have a custom onclick eventListener for me to display aditional information of this current event in another custom popup.
This is my method so far:
eventLimitClick : function(info){
info.segs.forEach(function(seg){
seg.el.querySelector('div.fc-content').addEventListener('click', function(event){
console.log('event definition', event);
});
});
return "popover";
}
But this is adding the listener to the elements I already see in my calendar. I also tried with hiddenSegs instead of segs but it's not working.
So is there any way to achieve this without having to create a custom popup with all the events?
** EDIT ** [included code]
calendar object
{
locale : 'en',
plugins : ['dayGrid','timeGrid','list','interaction'],
header : {
left : 'prev,next today',
center : 'title',
right : 'dayGridWeek, dayGridMonth, dayGridDay'
},
allDaySlot : false,
aspectRatio : 1.8,
displayEventTime : false,
editable : false,
navLinks : true,
eventLimit : true,
views : {
dayGridMonth : {
eventLimit : 2
}
},
events : this.eventLIST,
datesRender : this.calendarviewRender,
eventClick : this.calendareventClick,
eventRender : this.calendareventRender
}
datesRender, eventClick and eventRender functions:
calendarviewRender = (info) => {
//set current and end dates
this.endDate = info.view.activeEnd;
this.currentDate = info.view.activeStart;
//retrieve fresh event/task info
this.refreshCalendar();
}
calendareventClick = (info) => {
this.info = {id : info.event.id,
tipo : info.event.extendedProps.tipo,
tipoObj : info.event.extendedProps.tipoObj,
isClosed : info.event.extendedProps.isClosed && info.event.extendedProps.isClosed !== null ? (info.event.extendedProps.isClosed === 'false' ? false : true) : false,
campos : info.event.extendedProps.lCamposInfo};
//allow second button
this.info.displaysecondbutton = !this.info.isClosed && this.info.tipoObj === 'Task';
//allow popup display
this.allowpopup = true;
info.jsEvent.preventDefault();
}
calendareventRender = (info) => {
let html = "<i class='fa fa-" + info.event.extendedProps.icon + " fa-lg'></i>";
info.el.querySelector('div.fc-content').style.cssText = 'height: 100%;';
//if month view apply padding
if(info.view.type.includes('dayGrid')) info.el.querySelector('div.fc-content').classList.add('slds-p-around_x-small');
//center elements
info.el.querySelector('div.fc-content').classList.add('slds-align_absolute-center');
//append icon
info.el.querySelector('div.fc-content').innerHTML = html;
}
I also removed eventLimitClick.
Based on your comments i see you were working with lightning-web-components.
I was facing same issue as you when working with LWC on salesforce.
I was able to solve this by editing main.js in daygrid package and add delay when Popover was getting hidden.
Here is snippet of code
function Popover(options) {
var _this = this;
this.isHidden = true;
this.margin = 10; // the space required between the popover and the edges of the scroll container
// Triggered when the user clicks *anywhere* in the document, for the autoHide feature
this.documentMousedown = function (ev) {
if (_this.el && !_this.el.contains(ev.target)) {
setTimeout(function () {
_this.hide();
}, 1000);
}
};
this.options = options;
}
functions starts in line 100 of main.js.
I was using Fullcalendar v4

Wordpress Tiny MCE - Custom Button only in Visual Mode

I've seen pretty much the same question here [ TinyMCE custom buttons only appear in "Visual" mode. How to make them appear in "Text" mode too ], but it appears derelict.
The Problem
I've added a custom button to the TinyMCE editor in wordpress using the functions.php file. However, the button only appears/works whilst in visual mode. I'd also like the button to be available in the text mode.
Any ideas what's going on?
The Code
// FUNCTIONS.PHP
function add_button() {
if ( current_user_can('edit_posts') && current_user_can('edit_pages') )
{
add_filter('mce_external_plugins', 'add_plugin');
add_filter('mce_buttons', 'register_button');
}
}
add_action('init', 'add_button');
function register_button($buttons) {
array_push($buttons, "section");
return $buttons;
}
function add_plugin($plugin_array) {
$plugin_array['section'] = get_bloginfo('template_url').'/js/customcodes.js';
return $plugin_array;
}
// THE JAVASCRIPT
(function() {
tinymce.create('tinymce.plugins.section', {
init : function(ed, url) {
ed.addButton('section', {
title : 'Add a section',
image : url+'/image.png',
onclick : function() {
var sectionNumber = prompt('Your section number', '1');
ed.selection.setContent("[section number= " + sectionNumber + "]" + "[/section]");
}
});
},
createControl : function(n, cm) {
return null;
}
});
tinymce.PluginManager.add('section', tinymce.plugins.section);
})();

Dynamically add UI Elements in CKEditor Dialog

I'm trying to trigger a callback to dynamically populate a CKEditor dialog with checkboxes when the dialog is opened. I've read other solutions that use iframes, but this won't work for me because the dialog needs to be populated based on other elements on the same page.
Here is what I have so far. There are no errors, but the dialog is just empty when it opens. I expect the addContents function to fill in the dialog. I've confirmed that dialog.definition.contents does include the contents and elements that I want, but it's just not filling in the actual dialog. What am I missing?
(function() {
CKEDITOR.plugins.add( 'embeds', {
icons: 'embed',
init: function(editor) {
var self = this,
elements = [];
CKEDITOR.dialog.add('EmbedsDialog', function (instance) {
return {
title : 'Embeds',
minWidth : 550,
minHeight : 200,
contents: [],
onShow: function() {
var dialog = this,
elements = [];
$('#embeds-fields tr').each(function() {
var title = $(this).find('input[type=text]').val(),
url = $(this).find('input[type=url]').val();
if(url != "") {
elements.push({
label : "embed",
title : url,
type : 'checkbox'
});
}
});
dialog.definition.removeContents('embeds');
dialog.definition.addContents({
id : 'embeds',
expand : true,
elements : elements
});
},
}; // return
});
editor.addCommand('Embeds',
new CKEDITOR.dialogCommand('EmbedsDialog', {
allowedContent: 'a[*](*)'
})
);
editor.ui.addButton('Embeds', {
label : 'Embeds',
command : 'Embeds',
toolbar : 'embeds'
});
} // init
}); // add
})(); // closure
Based off of this example, I ended up with this solution, where "main" is the ID of the original content.
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
if (dialogName == 'EmbedsDialog') {
var main = dialogDefinition.getContents('main');
$('#embeds-fields tr').each(function() {
var title = $(this).find('input[type=text]').val(),
url = $(this).find('input[type=url]').val();
if(url != "") {
main.add({
type : 'checkbox',
label : title,
});
}
});
}
});

Adding a custom context menu item to elFinder

I'm using elfinder and I would like to add new functionality by adding a command to the context menu. I found a solution on the github issue tracker of the project but I can't get it to work. Here's what I do:
var elf;
jQuery().ready(function() {
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype._options.contextmenu.files.push('editimage');
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
console.log('hallo');
}
}
elf = jQuery('#elfinder').elfinder({
...
//elfinder initialization
The context menu item does not show up, no error message is to be found in the console. I also tried putting editimage under contextmenu->"files" in the init part in case that was overwritten by the initialization.
I found the solution: The examples don't show the fact that you need to have a function called this.getstate inside of the elFinder.prototype.commands.yourcommand function. It shall return 0 when the icon is enabled and -1 when it's disabled.
So the full code for adding your own menu item or context menu item looks like this:
var elf;
jQuery().ready(function() {
elFinder.prototype.i18.en.messages['cmdeditimage'] = 'Edit Image';
elFinder.prototype.i18.de.messages['cmdeditimage'] = 'Bild bearbeiten';
elFinder.prototype._options.commands.push('editimage');
elFinder.prototype.commands.editimage = function() {
this.exec = function(hashes) {
//do whatever
}
this.getstate = function() {
//return 0 to enable, -1 to disable icon access
return 0;
}
}
...
elf = jQuery('#elfinder').elfinder({
lang: 'de', // language (OPTIONAL)
url : '/ext/elfinder-2.0-rc1/php/connector.php', //connector URL
width:'100%',
uiOptions : {
// toolbar configuration
toolbar : [
...
['quicklook', 'editimage'],
/*['copy', 'cut', 'paste'],*/
...
]},
contextmenu : {
...
// current directory file menu
files : [
'getfile', '|','open', 'quicklook', 'editimage', ...
]
}
}).elfinder('instance');
});
Hope this helps someone with the same problem.
Thanks for the answer, great!
One thing that wasn't clear was how the variables pass through.
So, for anyone else who finds this page....
elFinder.prototype.commands.editpres = function() {
this.exec = function(hashes) {
var file = this.files(hashes);
var hash = file[0].hash;
var fm = this.fm;
var url = fm.url(hash);
var scope = angular.element("body").scope();
scope.openEditorEdit(url);
}
// Getstate configured to only light up button if a file is selected.
this.getstate = function() {
var sel = this.files(sel),
cnt = sel.length;
return !this._disabled && cnt ? 0 : -1;
}
}
To get your icon to show up, add the following to your css file:
.elfinder-button-icon-editpres { background:url('../img/icons/editpres.png') no-repeat; }

Dynamically changing variables within object dependent on DOM

I would like to have an object that returns status true/false based on the presence of an element in the DOM. I can't get the variable to actually maintain a state other than the state of the loaded page. My last attempt was rather stupid and resulted in Maximum call stack size exceeded, which was expected. Any way that I could have these variables change with the DOM?
var navigation = function runNav(){
runNav();
var navigation = {
globe : {
element : $("#icons .globe"),
status : (function(){
return ($(".window_stable.globe").length == 1) ? true : false;
})()
},
cart : {
element : $("#icons .cart"),
status : (function(){
return ($(".window_stable.cart").length == 1) ? true : false
})()
},
phone : {
element : $("#icons .phone"),
status : (function(){
return ($(".window_stable.phone").length == 1) ? true : false
})()
}
}
return navigation;
}();
example
navigation.cart.status
false
-- Enabled the element
navigation.cart.status
false
($(".window_stable.cart").length == 1) ? true : false
true
You should remove the call to runNav() at the start of your code. It's causing an infinite recursion loop. Other than that, your code looks fine.
I think I get what you're trying to do. I think you want the function you've defined for status to run every time you access the status property.
To my knowledge, I don't think you can do it just by making it a property. I think you need to make it a function.
Like this: (jsFiddle)
var navigation = {
globe: {
element: $("#icons .globe"),
getStatus: function() { return ($(".window_stable.globe").length > 0); }
},
cart: {
element: $("#icons .cart"),
getStatus: function() { return ($(".window_stable.cart").length > 0); }
},
phone: {
element: $("#icons .phone"),
getStatus: function() { return ($(".window_stable.phone").length > 0); }
}
};
alert("status = "+ navigation.cart.getStatus());
The problem that you are seeing is because the "status" property is being set immediately. So if the navigation object is initialized before these elements are added to the DOM, "status" will always be false.
If you are dead set on accessing "status" like you would a property, you can use the Object.defineProperty pattern: http://jsfiddle.net/TFVFS/
var navigation = (function runNav(){
var navigation = {
globe : {
element : $("#icons .globe")
},
cart : {
element : $("#icons .cart")
},
phone : {
element : $("#icons .phone")
}
};
Object.defineProperty(navigation.globe, "status", {
get:function(){return $(".window_stable.globe").length == 1 ? true : false;}
});
Object.defineProperty(navigation.cart, "status", {
get:function(){return $(".window_stable.cart").length == 1 ? true : false;}
});
Object.defineProperty(navigation.phone, "status", {
get:function(){return $(".window_stable.phone").length == 1 ? true : false;}
});
return navigation;
})();
console.log(navigation.cart.status);
console.log(navigation.globe.status);
console.log(navigation.phone.status);
This isn't fully backwards compatible, and isn't fully supported in IE prior to version 9.
#Travesty3's answer will be backwards compatible, but it requires a change in syntax. Personally, I would recommend his answer if you need to support version of IE before 9.

Categories

Resources