TinyMCE opened in jqueryUI modal dialog - javascript

When using tinyMCE in a jqueryUI modal dialog, I can't use the hyperlink or 'insert image' features.
Basically, after lots of searching, I've found this:
http://www.tinymce.com/develop/bugtracker_view.php?id=5917
The weird thing is that to me it seams less of a tinyMCE issue and more of a jqueryUI issue since the problem is not present when jqueryUI's modal property is set to false.
With a richer form I saw that what happens is that whenever the tinyMCE loses focus, the first element in the form gets focus even if it's not the one focused / clicked.
Does some JavaScript guru have any idea how I might be able to keep the dialog modal and make tinyMCE work?

This fixed it for me when overriding _allowInteraction would not:
$(document).on('focusin', function(e) {
if ($(event.target).closest(".mce-window").length) {
e.stopImmediatePropagation();
}
});
I can't really take credit for it. I got it from this thread on the TinyMCE forums.
(They have moved their bugtracker to github. tinymce/issues/703 is the corresponding github issue.)

It seems there are no propper solution for this issue yet. This is kind of a hack but it really worked for me.
Every time you open the Dialog remove the text area and re add it like following,
var myDialog = $('#myDialog');
var myTextarea = myDialog.find('textarea');
var clonedTextArea = myTextarea.clone(); // create a copy before deleting from the DOM
var myTextAreaParent = myTextarea.parent(); // get the parent to add the created copy later
myTextarea.remove(); // remove the textarea
myDialog.find('.mce-container').remove(); // remove existing mce control if exists
myTextAreaParent.append(clonedTextArea); // re-add the copy
myDialog.dialog({
open: function(e1,e2){
setTimeout(function () {
// Add your tinymce creation code here
},50);
}
});
myDialog.dialog('open');

This seems to fix it for me, or at least work around it (put it somewhere in your $(document).ready()):
$.widget('ui.dialog', $.ui.dialog, {
_allowInteraction: function(event) {
return ($('.mce-panel:visible').length > 0);
}
});

Related

Proper Way Of Modifying Toolbar After Init in TinyMCE

I am extending a cloud-hosted LMS with javascript. Therefore, we can add javascript to the page, but cannot modify the vendor javascript for different components.
The LMS uses tinyMCE frequently. The goal is to add a new button on to the toolbar of each tinyMCE editor.
The problem is that since the tinyMCE modules are initialized in the vendor's untouchable code, we cannot modify the init() call. Therefore, we cannot add any text on to the "toolbar" property of the init() object.
So I accomplished this in a moderately hacky way:
tinyMCE.on('AddEditor', function(e){
e.editor.on('init', function(){
tinyMCE.ui.Factory.create({
type: 'button',
icon: 'icon'
}).on('click', function(){
// button pressing logic
})
.renderTo($(e.editor.editorContainer).find('.mce-container-body .mce-toolbar:last .mce-btn-group > div')[0])
});
});
So this works, but needless to say I am not totally comfortable having to look for such a specific location in the DOM like that to insert the button. Although this works, I do not believe it was the creator's intention for it to be used like this.
Is there a proper way to add the button to a toolbar, after initialization, if we cannot modify the initialization code?
I found a more elegant solution, but it still feels a bit like a hack. Here is what I got:
// get an instance of the editor
var editor=tinymce.activeEditor; //or tinymce.editors[0], or loop, whatever
//add a button to the editor buttons
editor.addButton('mysecondbutton', {
text: 'My second button',
icon: false,
onclick: function () {
editor.insertContent(' <b>It\'s my second button!</b> ');
}
});
//the button now becomes
var button=editor.buttons['mysecondbutton'];
//find the buttongroup in the toolbar found in the panel of the theme
var bg=editor.theme.panel.find('toolbar buttongroup')[0];
//without this, the buttons look weird after that
bg._lastRepaintRect=bg._layoutRect;
//append the button to the group
bg.append(button);
I feel like there should be something better than this, but I didn't find it.
Other notes:
the ugly _lastRepaintRect is needed because of the repaint
method, which makes the buttons look ugly regardless if you add new
controls or not
looked in the code, there is no way of adding new controls to the
toolbar without repainting and there is no way to get around it
without the ugly hack
append(b) is equivalent to add(b).renderNew()
you can use the following code to add the button without the hack, but you are shortcircuiting a lot of other stuff:
Code:
bg.add(button);
var buttonElement=bg.items().filter(function(i) { return i.settings.text==button.text; })[0];
var bgElement=bg.getEl('body');
buttonElement.renderTo(bgElement);

Prevent typeahead.js dropdown from closing on select

How can I prevent a typeahead dropdown from closing when an item is selected? I've tried using preventDefault like this:
$('#q').bind('typeahead:selected',function(obj, datum, name) {
...
obj.preventDefault();
});
But no success.
Edit:
I've managed to "fix" this by building Typeahead with lines 217-218 commented from typeahead_views.js:
byClick && utils.isMsie() ?
utils.defer(this.dropdownView.close) : this.dropdownView.close();
But there has to be another way without modifying source files?
Had the same problem and the (very easy) solution doesn't seem to be documented anywhere
$(document).on('typeahead:beforeclose', function(event, data) {
event.preventDefault()
})
(this just prevents the dropdown from closing at all which can be very helpful during development, use 'typeahead:beforeselect' if you want to prevent closing just on selet).
Trigger the focus of the input on the closed callback.
$('#typeahead-input').on('typeahead:closed', function(e, d) {
$('#typeahead-input').focus();
});
I'm working on typeahead inside tokenfield so the first part is me accessing the Typeahead.dropdown object, which in itself took some hunting.
Tried toying with isOpen or overwriting close functions, in the end closest I got was this. Breaking down the marshalling of events. You'd have to reimplement any saving of values etc, basically the first 3 lines of Typeahead.select.
I myself was blocked at being able to put a form (focus stays in input field) in the dropdown and still a bit more hunting if were to put something interactive in there. Think I'll go for a roll-your-own solution on this one but might help someone who just wants to block the closing, put the original function in a var to put it back in place when you're finished.
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').dropdown.trigger = function(e) {};
Also this has potential:
$('input[id="test"]').data('bs.tokenfield')
.$input.data('ttTypeahead').eventBus.trigger = function(e) {};
A simpler way:
input.data('tt-typeahead')._selectOld = input.data('tt-typeahead')._select
input.data('tt-typeahead')._select = function(datum) {
if (false)
this._selectOld(datum)
}

Creating CodeMirror dynamically - rendering issues

I recently started to develop a class that manipulates over CodeMirror - dynamically links necessary libraries, provides comunication with server and so on.
Because of that I hold everything in variables, and upon initialisation, the CodeMirror is appended to DOM node which is not within document tree. Just like that:
var holder = document.createElement("div");
var textarea = document.createElement("textarea");
holder.appendChild(textarea);
this.editor = CodeMirror.fromTextArea(textarea, {/*options*/});
Then I append the DIV myself when .show() method is called upon my class:
this.show(node) {
if(this.editor!=null) {
node.parentNode.replaceChild(holder,node);
}
}
The editor is OK since click into it and try to draw, or after I resize window. But before, I just see blank area with disabled scroll bar. I believe this is because of way I initialise whole CodeMirror.
So what should I do to make it work, if I want to keep my class structure?
Link to live code (not for IE).
A more direct way would be to call .refresh() on the CodeMirror instance after showing it. See http://codemirror.net/doc/manual.html#refresh
So I solved the issue very simply - I dispatch onresize event after adding editor to dom tree:
node.parentNode.replaceChild(holder,node);
var evt = document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false,window,0);
window.dispatchEvent(evt);
Based on How to dispatch resize event? question.

jquery minimal rich textbox plugin

I am looking for a very minimal jQuery rich textbox plugin for a web app I am working on.
The user will only need to see the 'textbox', and not any toolbars as all of the rich formatting will be coded depending on what they type.
I have attempted to create my own with an iframe, but there are problems. One of them being when wrapping strings in divs, the caret is moved to the beginning and it can't be moved inside the div without clicking. http://jsfiddle.net/DVjYa/
This is a problem because I need it to behave like a normal textbox. In a normal textbox, you would be able to navigate with the arrow keys without having to click. Hence why I am looking for a plugin which has already overcome these problems.
You can use CLEDITOR which is very lightweight. You can disable all the toolbar buttons and hide the toolbar as well. In addition to this, it lets you make the selection bold/italic using keyboard shortcuts (CTRL+B/CTRL+I) even though the toolbar does not exist.
Demo: http://jsfiddle.net/Rft3A/
var editorDoc;
$(function() {
var editor = document.getElementById ("editable");
if (editor.contentDocument) {
editorDoc = editor.contentDocument;
} else {
editorDoc = editor.contentWindow.document;
}
var editorBody = editorDoc.body;
if ('contentEditable' in editorBody) {
// allow contentEditable
editorBody.contentEditable = true;
}
else { // Firefox earlier than version 3
if ('designMode' in editorDoc) {
// turn on designMode
editorDoc.designMode = "on";
}
}
});
will add another answer although post is a little old
Trumbowyg A lightweight and amazing WYSIWYG JavaScript editor - 15kB only (from github page)

Jquery UI Dialog Remove Issue

Back from this issue
Multiple Dialog
I was able to solve the issue but now problem is that it removes the div so when I access that Div it give error. It gives error because when I open dialog it works fine after removing on close it gives e.rror
I don't want to removed jQuery('#divPopup') If there is only one div present. If multiple jQuery('#divPopup') are there remove() should be working fine.
jQuery('.register_button_class').live('click',function () {
var iFrameobj = createIframe('',iframeUrl);
jQuery('#divPopup').html(iFrameobj);
createDialogWithClose(url,'#bodyId');
return false;
});
Dummy Div for Dialog Popup, This get removed, when Click on Close Jquery Ui Popup.
So when I say
jQuery('#divPopup').html(iFrameobj);
It gives error.
<div id="divPopup"></div>
I'm assuming that your function:
createDialogWithClose(url, '#bodyId');
removes the div id="divPopup" each from the DOM when you close it.
I would suggest not initially including that div in your markup and change your function to create the div and append it to the DOM when it runs. Then remove like you're already doing.
jQuery('.register_button_class').live('click',function () {
var iFrameobj = createIframe('',iframeUrl);
jQuery("body").append("<div id='divPopup' />").html(iFrameobj);
createDialogWithClose(url,'#bodyId');
return false;
});
It's hard to tell what other issues you may be running into with this bit of code that you posted, however, jQuery("body").append("<div id='divPopup' />").html(iFrameobj); will create the divPopup each time the function runs. So, when you close it and it gets removed it will just get created again the next time that button is clicked.
EDIT: How to check if a Div exists -
if ($("#divPopup").length > 0){
// do something here
}
I solved like this
var length = jQuery('#divPopup').length;
if(length>1)
{
jQuery('#divPopup').dialog('destroy').remove();
}else
{
jQuery('#divPopup').dialog('destroy');
}

Categories