How to add a custom control to the TinyMce 4 toolbar - plugins

I want to introduce a new Control to TinyMce that I can use in the toolbar. In my case I want to add an icon control that can be placed at the start of the toolbar to differentiate between editors.
However there is almost no information about how to properly do this.

Finally I managed to come up with a way to properly do this.
First I introduce a new plugin icon (in icon/plugin.js) that registers a new control Icon. It uses a setting iconClass.
tinymce.PluginManager.add('icon', function() {
tinymce.ui.Icon = tinymce.ui.Widget.extend({
renderHtml: function () {
return '<span class="icon icon-' + this.settings.iconClass + '"> </span>';
}
});
});
Next I add a button facebook to the toolbar in the following way:
editor.addButton('facebook', {
type: 'icon',
iconClass: 'facebook-share'
});
Now I can add it to the toolbar specification:
tinymce.init({
toolbar: "facebook"
})
That's it! The new custom control should not render. The plugin code is only ran once; even if used multiple times.

Related

How to simulate click event for tinyMCE v6x custom toolbar button programmatically

This is simple enough in earlier version of tinyMCE, but I can't find a way to make it work in v6x (suggested answers here only apply to earlier versions, that I can see)
Here's my button:
tinymce.PluginManager.add('newButton', (editor, url) => {
editor.ui.registry.addButton('newButton', {
text: 'Click me',
enabled: true,
onAction: () => {
alert('You clicked me')
}
})
return {
getMetadata: () => ({
name: 'newButton',
url: ''
})
}
});
tinymce.init({
selector: "textarea",
plugins: "newButton",
toolbar1: "newButton"
});
This works fine - click the button and you get an alert telling you you have. What I want to do now is call this click event from code (JaveScript) - I was hoping
tinymce.activeEditor.buttons['newButton'].onclick();
would work, as it does for - say - the "code" plugin; i.e. add this plugin (and button) to the editor and calling
tinymce.activeEditor.buttons['code'].onclick();
simulates clicking the toolbar button. So... how can I "click" my own custon toolbar button?
[edit] well.. that last line did work, I swear it did. Now it doesn't. wt.. :(
This may not be the "right" way (well, I know it isn't!) but I've found a way that works :)
First, I need a way to identify/find my custom button. I figured out tinymce renders them as div elements, and using
var divs = document.querySelectorAll('button');
divs.forEach((div) => {
console.log(div.innerHTML);
})
I am able to identify it and find the HTML used - it is not graced with an id, but we can use the innerHTML property (as identified) to get it and then simulate a click- viz:
var divs = document.querySelectorAll('button');
divs.forEach((div) => {
// NB 'DOC' is the text property of my custom button
if (div.innerHTML === '<span class="tox-tbtn__select-label">DOC</span>') {
// now we can simulate a click on it:
var evt = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true
});
div.dispatchEvent(evt);
return;
}
})
(Thanks to the second answer, by Derek, here:
How to simulate a mouse click using JavaScript?
for the simulate click code)
[edit] better to use a for-loop rather than forEach as there's no sensible way to break out of the latter - that "return" doesn't actually do anything.

Summernote WYSIWYG : set code view as default view

I can't find anything about this on the web. Is there a way to set the default view of Summernote (WYSIWYG jQuery text editor) to be the code/html view. I want to see directly the HTML code when landing on the form page.
Thank you
You can simulate a click on the codeview button (after summernote initialization), it works for me :
$('.summernote').summernote({
oninit: function() {
$("div.note-editor button[data-event='codeview']").click();
}
});
From Summernote documentation:
After v0.7.0, every callbacks should be wrapped by callbacks object.
So, in order to work, the js should be like this:
$('.summernote_editor').summernote({
callbacks: {
onInit: function() {
$("div.note-editor button.btn-codeview").click();
}
}
});
Not very elegant and I don't know if there is a proper way to do it but give this a try if you like:
From what I can tell, and I didn't look very hard, the codeview button does this:
adds a 'codeview' class to div.note-editor
disables all the buttons
adds an 'active' class to the codeview button elemment.
You may discover that it does other things as well but this should put you on a workable path.
$('div.note-editor').addClass('codeview');
$('div.note-editor.codeview button').addClass('disabled');
$("div.note-editor.codeview button[data-event='codeview']").removeClass('disabled').addClass('active');
Well, you can use the init callback.
$('.summernote').on('summernote.init', function () {
$('.summernote').summernote('codeview.activate');
}).summernote({
height: 300,
placeholder: 'Paste content here...',
codemirror: {
theme: 'monokai'
}
});

closethick button disappear liferay popup 6.2

I am migrating the AUI popup dialog window from liferay 6.1 to liferay 6.2. I see that there are some specific changes to be made. I had some problems with display of buttons but it is resolved now. But the problem is with the close icon (x) which should be on the top right corner. It disappeared suddenly as soon as I added a save button.
Here is my code:
myPopup = AUI().use('aui-base','liferay-util-window','aui-io-deprecated', 'event', 'event-custom', function(A) {
var buttons =[{
cssClass: 'button_close',
label: 'Save',
render:true,
id: 'myPopupButton',
on: {
click: function() {
myPopupSubmit();
}}
}];
myPopup = Liferay.Util.Window.getWindow(
{
dialog: {
title : a + ' mytitle',
centered : true,
height : 600,
width : 500,
draggable : true,
resizable : true,
modal : true,
toolbars: {
footer:buttons
},
}}).plug(A.Plugin.IO, {
uri : url
}).render();
myPopup.show();
});
}
Please let me know if you have any idea on it..
on myPopupSubmit I have also written code to close the popup as:
top.document.getElementById('closethick').click();
Since there is no closethick button it returns null.
Using the modal dialog example as a comparison, the X close button is removed when using the toolbars property.
Reviewing the source code for the toolbars property (line 309 at time of writing this) indicates that if you use this property directly, you'll need to include your own X close in the header.
An alternative would be to use the addToolbar function (as seen in the example) to include your buttons while preserving the default toolbars.
modal.addToolbar([{
cssClass: 'button_close',
label: 'Save',
render:true,
id: 'myPopupButton',
on: {
click: function() {
myPopupSubmit();
}
}
}]);
I would also consider making the instance of the dialog available to your myPopupSubmit function so that you would have direct access to perform dialog.hide() or calling dialog.hide() after myPopupSubmit versus using the X close approach.
If sticking with the current approach, the id being used will not work, you'll need to use a CSS selector as the YUI based id will change.

Switch class on tabs with React.js

So I have a tab-component that has 3 items:
React.DOM.ul( className: 'nav navbar-nav',
MenuItem( uid: 'home')
MenuItem( uid: 'about')
MenuItem( uid: 'contact)
)
And in the .render of MenuItem:
React.DOM.li( id : #props.uid, className: #activeClass, onClick: #handleClick,
React.DOM.a( href: "#"+#props.uid, #props.uid)
)
Every time I click an item, a backbone router gets called, which will then call the tab-component, which in turn will call a page-component.
I'm still trying to wrap my head around the fact there's basically a one-way data-flow. And I'm so used to manipulating the DOM directly.
What I want to do, is add the .active class to the tab clicked, and make sure it gets removed from the inactive ones.
I know the CSS trick where you can use a data- attribute and apply different styling to the attribute that is true or false.
The backbone router already has already gotten the variable uid and calls the right page. I'm just not sure how to best toggle the classes between tabs, because only one can be active at the same time.
Now I could keep some record of which tab is and was selected, and toggle them etc. But React.js already has this record-keeping functionality.
The #handleClick you see, I don't even want to use, because the router should tell the tab-component which one to give the className: '.active' And I want to avoid jQuery, because React.js doesn't need direct DOM manipulation.
I've tried some things with #state but I know for sure there is a really elegant way to achieve this fairly simple, I think I watched some presentation or video of someone doing it.
I'm really have to get used to and change my mindset towards thinking React-ively.
Just looking for a best practice way, I could solve it in a really ugly and bulky way, but I like React.js because it's so simple.
Push the state as high up the component hierarchy as possible and work on the immutable props at all levels below. It seems to make sense to store the active tab in your tab-component and to generate the menu items off data (this.props in this case) to reduce code duplication:
Working JSFiddle of the below example + a Backbone Router: http://jsfiddle.net/ssorallen/4G46g/
var TabComponent = React.createClass({
getDefaultProps: function() {
return {
menuItems: [
{uid: 'home'},
{uid: 'about'},
{uid: 'contact'}
]
};
},
getInitialState: function() {
return {
activeMenuItemUid: 'home'
};
},
setActiveMenuItem: function(uid) {
this.setState({activeMenuItemUid: uid});
},
render: function() {
var menuItems = this.props.menuItems.map(function(menuItem) {
return (
MenuItem({
active: (this.state.activeMenuItemUid === menuItem.uid),
key: menuItem.uid,
onSelect: this.setActiveMenuItem,
uid: menuItem.uid
})
);
}.bind(this));
return (
React.DOM.ul({className: 'nav navbar-nav'}, menuItems)
);
}
});
The MenuItem could do very little aside from append a class name and expose a click event:
var MenuItem = React.createClass({
handleClick: function(event) {
event.preventDefault();
this.props.onSelect(this.props.uid);
},
render: function() {
var className = this.props.active ? 'active' : null;
return (
React.DOM.li({className: className},
React.DOM.a({href: "#" + this.props.uid, onClick: this.handleClick})
)
);
}
});
You can try react-router-active-componet - if you working with boostrap navbars.
You could try to push the menu item click handler up to it's parent component. In fact I am trying to do something similar to what you are doing.. I have a top level menubar component that I want to use a menubar model to render the menu bar and items. Other components can contribute to the top level menubar by adding to the menubar model... simply adding the top level menu, the submenuitem, and click handler (which is in the component adding the menu). The top level component would then render the menubar UI and when anything is clicked, it would use the "callback" component click handler to call to. By using a menu model, I can add things like css styles for actice/mouseover/inactive, etc, as well as icons and such. The top level menubar component can then decide how to render the items, including mouse overs, clicks, etc. At least I think it can.. still working on it as I am new to ReactJS myself.

Twitter Bootstrap Modal Form: How to drag and drop?

I would like to be able to move around (on the greyed-out background, by dragging and dropping) the modal form that is provided by Bootstrap 2. Can anyone tell me what the best practice for achieving this is?
The bootstrap doesn't come with any dragging and dropping functionality by default, but you can add a little jQuery UI spice into the mix to get the effect you're looking for. For example, using the draggable interaction from the framework you can target your modal ID to allow it to be dragged around within the modal backdrop.
Try this:
JS
$("#myModal").draggable({
handle: ".modal-header"
});
Demo, edit here.
Update: bootstrap3 demo
Whatever draggable option you go for, you might want to turn off the *-transition properties for .modal.fade in bootstrap’s CSS file, or at least write some JS that temporarily disables them during dragging. Otherwise, the modal doesn’t drag exactly as you would expect.
You can use a little script likes this.
simplified from Draggable without jQuery UI
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
var $selected = this;
var $elements = (opt.handle === "") ? this : this.find(opt.handle);
$elements.css('cursor', opt.cursor).on("mousedown", function (e) {
var pos_y = $selected.offset().top - e.pageY,
pos_x = $selected.offset().left - e.pageX;
$(document).on("mousemove", function (e) {
$selected.offset({
top: e.pageY + pos_y,
left: e.pageX + pos_x
});
}).on("mouseup", function () {
$(this).off("mousemove"); // Unbind events from document
});
e.preventDefault(); // disable selection
});
return this;
};
})(jQuery);
example : $("#someDlg").modal().drags({handle:".modal-header"});
Building on previous answers utilizing jQuery UI, this, included once, will apply to all your modals and keep the modal on screen, so users don't accidentally move the header off screen so they can no longer access the handle. Also sets the cursor to 'move' for better discoverability.
$(document).on('shown.bs.modal', function(evt) {
let $modal = $(evt.target);
$modal.find('.modal-content').draggable({
handle: ".modal-header",
containment: $modal
});
$modal.find('.modal-header').css('cursor', 'move')
});
evt.target is the .modal which is the translucent overlay behind the actual .modal-content.
jquery UI is large and can conflict with bootstrap.
An alternative is DragDrop.js: http://kbjr.github.io/DragDrop/index.html
DragDrop.bind($('#myModal')[0], {
anchor: $('#myModal .modal-header')
});
You still have to deal with transitions, as #user535673 suggests. I just remove the fade class from my dialog.