TinyMCE editor content missing after drag and move - javascript

I've got a page with multiple TinyMce editors and i have drag and drop feature enabled which allows me to change the order of each items.
But as i drag-drop an editor its content gets removed.
See the screen shots :
Before Drag-Drop
After Drag-Drop

Finally fixed the issue...
The solution is to first shut down the tinymce instance (id needed!)
tinymce.execCommand('mceRemoveControl',true,'editor_id');
then do the DOM action and reinit the tinymce instance
tinymce.execCommand('mceAddControl',true,'editor_id');

Add following code on drag end event:
onDragEnd(event: any) {
var tinymceId = 'tinymceId_' + event.source.data.index; //get selected element id
tinymce.get(tinymceId ).remove(); //remove existing instance
$('#' + tinymceId ).closest('.mce-tinymce.mce-container').show();
tinymce.init({id: tinymceId , selector: '#' + tinymceId , height: 200}; //you can add other properties into init()
}

Related

Wordpress Detect Click on Gallery Shortcode Preview in TinyMCE

Working on customizing the wordpress gallery with some different settings for different gallery types.
Short of the long is I'm using multiple wp_editors on page and I'm having a focus problem when jumping between editors.
I'm making use of wp.media.view.Settings.Gallery.extend to switch between gallery types and display different js templates.
The functionality is actually all good and gallery shortcodes are going where they need to and being updated as needed.
For certain gallery types I am extending the attachment details with
an extend that looks something like this slimed down version:
var $gal_media = wp.media;
$gal_media.view.Attachment.Details = $gal_media.view.Attachment.Details.extend({
initialize: function(){
this.model.on('change', this.render, this);
},
render: function(){
var check_active_editor = window.wpActiveEditor;
return this;
}
});
The problem lies here when I'm attempting to detect the current editor during the render part of the function with window.wpActiveEditor;
It's working correctly providing you get focus on the current editor but if you just click the gallery preview or edit gallery pencil window.wpActiveEditor; will return the last focused editor.
Tried several different attempts to change focus on the editor in the wp_editor call using on click events during init like so:
'tinymce' => array(
'init_instance_callback' => 'function(gallery_editor) {
gallery_editor.on("click", function(){
tinyMCE.get(gallery_editor.id).focus();
});
}'
)
but they are not called when clicking on the gallery preview or edit.
Any suggestion on either:
1) Getting the proper id?
Obviously the Gallery knows it as it's returning the shortcode to the proper editor.
or
2) Toggling Focus/Blur on Multiple Editors when Gallery Preview or Edit button is pressed.
Much appreciated!
If anyone finds themselves in a similar situation I was able to resolve this issue with an on click callback on my editors that cycles through all the editors and removes the data-mce-selected attribute from any other gallery nodes that were selected.
Then it sets focus on the editor that was just clicked.
Not the prettiest but it's behaving as expected.
The key for me was using tinyMCE.dom.DomQuery
'tinymce' => array(
'init_instance_callback' => 'function(ed) {
ed.on("click", function(){
for (edId in tinyMCE.editors){
if(edId !== ed.id){
var this_editor = tinyMCE.get(edId);
var $ = tinyMCE.dom.DomQuery;
$("div[data-wpview-type]", this_editor.dom.doc).removeAttr("data-mce-selected");
}
}
tinyMCE.get(ed.id).focus();
});
}'
)

Programmatically collapse Leaflet JS layer control

How can the Leaflet JS layer control be closed using JS code? On desktop, the control closes nicely when the mouse cursor leaves the control. However, on mobile phones, the user needs to tap outside the control to close it. I would like to manually close it once a user selects a layer inside the control.
The state of this control is controlled by the leaflet-control-layers-expanded class. If you add or remove this class to the leaflet-control-layers element, then you can control the state.
These examples use jQuery for simplicity.
To expand the control:
$(".leaflet-control-layers").addClass("leaflet-control-layers-expanded")
To collapse the control:
$(".leaflet-control-layers").removeClass("leaflet-control-layers-expanded")
For mobile devices, I would simply add a close button to the div and then use js to change the class as mentioned above:
Note that I changed the leaflet source code here but it should be feasible externally as well. Add the following code before the line container.appendChild(form); in your leaflet source - tested with 0.7.7)
if (L.Browser.android || L.Browser.mobile || L.Browser.touch || L.Browser.retina) {
var yourCloseButton = this.yourCloseButton = L.DomUtil.create('div', className + '-close');
this.yourCloseButton = L.DomUtil.create('div', className + '-close', form);
this.yourCloseButton.innerHTML = '<button class="btn-close-layers-control">X</button>';
L.DomEvent.on(this.yourCloseButton, 'click', this._collapse, this);
}
`Then position the button with css.

ExtJS 4.1 - Drag and Drop with RowExpander Issues

Update 9/11/13 - Here is a fully working jsFiddle demonstrating the issue... to experience the issue, expand the grid and attempt to drag the nested row over to the TreePanel. The drag element will be obfuscated by the TreePanel, as if it is behind it. Link here: http://jsfiddle.net/ZGxf5/
Here's a bit of a unique roadblock I've run into... I figured it would be best illustrated with an image:
As you can see in the picture, I am attempting to drag a div, generated via the rowBodyTpl property of the RowExpander plugin utilized in the grid shown in the bottom left of the image. I am able to "grab" the element and move it about, however it is seemingly constrained to the RowExpander generated div. I cannot drag the div any further left, nor upwards from where its original position. Attempting to move it into the panel to the right results in the dragging div being obfuscated, as shown in the picture.
I have attempted to completely eliminate all constraints in the startDrag method as you will see in the code below, but to no avail. I am basically just using the code provided in Sencha's 5 Steps to Understanding Drag and Drop with ExtJS Blog Post, but it obviously needs some tweaking for my implementation.
Below is my code for initializing the Drag on the target div..
/**
* NOTE: The following code is executed whenever
* the contents of the grid's store change
*/
var me = this, // ENTIRE left panel, including the TreePanel and lower GridPanel
divs = Ext.select('div[name=storage-item-div]', false, me.getEl().dom),
dragOverrides = {}; // provided separately, see below
Ext.each(divs.elements, function(el){
console.warn("mkaing new dd", el);
var dd = new Ext.dd.DD(el, 'storageItemDDGroup',{
isTarget: false
});
Ext.apply(dd, dragOverrides);
});
The dragOverrides object is defined as follows (note my debugging for Constrain)
dragOverrides = {
b4StartDrag : function() {
// Cache the drag element
if (!this.el) {
this.el = Ext.get(this.getEl());
}
//Cache the original XY Coordinates of the element, we'll use this later.
this.originalXY = this.el.getXY();
},
startDrag: function(){
/** DEBUGGING */
_t = this;
this.resetConstraints();
this.setXConstraint(1000,1000);
this.setYConstraint(1000,1000);
},
// Called when element is dropped not anything other than a dropzone with the same ddgroup
onInvalidDrop : function() {
// Set a flag to invoke the animated repair
this.invalidDrop = true;
},
// Called when the drag operation completes
endDrag : function() {
// Invoke the animation if the invalidDrop flag is set to true
if (this.invalidDrop === true) {
// Remove the drop invitation
this.el.removeCls('dropOK');
// Create the animation configuration object
var animCfgObj = {
easing : 'elasticOut',
duration : 1,
scope : this,
callback : function() {
// Remove the position attribute
this.el.dom.style.position = '';
}
};
// Apply the repair animation
this.el.moveTo(this.originalXY[0], this.originalXY[1], animCfgObj);
delete this.invalidDrop;
}
}
Finally, I think the rowBodyTpl portion of the lower grid's configuration may be useful in solving the issue, so here is the source for that!
rowBodyTpl : ['<div id="OrderData-{item_id}" style="margin-left: 50px;">'+
'<tpl for="order_data">'+
'<tpl for=".">' +
'<div name="storage-item-div" class="draggable" style="padding-bottom: 5px;">' +
'<b>{quantity}</b> from Purchase Order <b>{purchase_order_num}</b> # ${purchase_cost}' +
'<input type="button" style="margin-left: 10px;" name="storageViewOrderButton" orderid="{purchase_order_id}" value="View Order"/>' +
'</div>' +
'</tpl>' +
'</tpl>'+
'</div>']
I was able to get this working in a Fiddle, but I had to switch my RowExpander template to instead render an Ext.view.View rather than the div which I was previously using. Using an Ext.view.View allowed me to basically just follow the Sencha demo for using DragZone and DropZone.. kinda wish it wasn't so complicated but hey, that's just how it is sometimes, I guess.
See the very messy jsFiddle source here for a working demo using DragZone and DropZone, feel free to tweak for your own needs: http://jsfiddle.net/knppJ/
Again, the issue here was dragging a nested div from inside a RowExpander generated row inside a gridpanel to a separate adjacent panel. The issue I was encountering is thoroughly described in my question above. I was not able to get a regular div working the way I wanted it to, so I ended up using an Ext.view.View in place of the grid. This required adding a bit of extra logic in the onbodyexpand event fired by the RowExpander plugin, basically just rendering an Ext.view.View to the div generated by the RowExpander.

NicEdit - Unbind Events

I decided to use NicEdit on a project, because is lightweight.
So, now I have a variable number of instances in my page, loaded on click and removed on editor blur.
I need to know how to unbind events from this component. I tried to unbind it manually, but I didn't understand where they are linked!
$('.container').bind('click', function(){
var _form = $(this).parentsUntil('form').parent();
var textarea = _form.find('textarea.edit');
var ta_id = textarea.attr('id');
var ed = new nicEditor(niceditOptions).panelInstance(ta_id);
// Show Preview and update textarea and so on
ed.addEvent('blur', function() {
var _ed = nicEditors.findEditor(ta_id);
var ev_type, evt, events = this.eventList;
for (ev_type in events){
for (evt in ev_type){
if (this.removeEventListener){
this.removeEventListener(ev_type, events[ev_type][evt]);
}
else {
this.detachEvent('on' + ev_type, events[ev_type][evt]);
}
}
}
this.removeInstance(ta_id);
});
});
There are potentially other ways of going about your solution, but in this scenario I prefer to use one version of a nicEditor panel and bind all of my WYSIWYG instances. The reason for this is that I think its slightly tidier. I will assume that you know how to bind one editor to multiple editable instances.
On load my HTML would probably look something like this:
<div id="instance1">text</div>
...
<div id="instance2">text</div>
...
<div id="myNicPanel" style="display:none;position:relative;"></div>
So, once the page has completed it's load cycle, i should have two editable areas and a hidden editor. I would then use the following jQuery to reposition and show the editor when an instance is selected for editing:
$('#instance1 , #instance2').click(function () {
//Reposition the editor to just above the selected instance
$('#myNicPanel').css({
top: $(this).position().top,
left: $(this).position().left,
display: 'block',
width: $(this).width() - 2 //manual adjustment,
position: 'absolute'
});
//Make the width of the editor equal to that of the instance
$('#myNicPanel').css({
top: $(this).position().top - $('#myNicPanel').height()
});
});
You would of course already have initiated your editor and instances prior to this, and if you also want to have the editor hide again on blur, you could attach your hide() function to one of the nicEditor events.

Jquery .ClickOut Event

Hi everybody,
I have some issue with one of my project. I'm currently developing a toolbar for Google Chrome. The concept is that my extension insert by using a content script an iframe in every page i visit. Materialized in Red on my Printscreen.
After that i've created another iframe who appear when i click on the "Menu" Button. This iframe appear like a dropMenu. Materialized in orange in the printscreen.
Well now let me explain my problem :
When i click on the "dropMenuButton" i execute this code :
$( "#dM1").click( function() {
dropMenu('dropMenu1', $(this).position().left);
});
To be clear the function "dropMenu" will call my background page (by messaging exchange) to show or hide the dropMenu, in function if it's allready activated or not.
Here is the executed code by the "dropMenu function"
if(document.getElementById("dropMenu"))
{
$("#dropMenu").slideUp(800, function() {
$(this).remove();
});
}
else
{
var body = $('body'),
MenuURL = chrome.extension.getURL(dropMenuPage + ".html"),
iframe = $('<iframe id="dropMenu" scrolling="no" src="'+MenuURL+'">');
body.append(iframe);
$("#dropMenu").hide().slideDown(800);
// Shift the menu (Left)
$("#dropMenu").css({left: marginLeft+'px'});
}
So the event on dropMenuButton work perfectly but i want to provide some ameliorations like a .ClickOut event. What i want is that when somebody click outside the dropMenu (in orange) the menu will be hide.
I've tried a lot of things but nothing work...
Hope somebody will provide me some help !
Thanks in advance.
Edit (Injection) :
I've tried to inject the javascript like this :
var injectJs = $('<script type=text/javascript>' +
'$(document).click(function() {' +
'dropMenu("dropMenu1", 0);' +
'});');
body.append(injectJs);
injectJs = $('$("#dropMenu").click( function(e) {' +
'e.stopPropagation();' +
'});' +
'</script>');
body.append(injectJs);
But it didn't seems to inject on the page. It should have a problem somewhere...
Can't you just add a click event on the document? Then on the actual drop down menu (or any other events where you don't want to hide the drop down) prevent any clicks from bubbling up:
$(document).click(function(){
// hide drop down clicking anywhere on page:
$("#dropMenu").slideUp(800, function() {
$(this).remove();
});
});
$("#dropMenu").click( function(e) {
e.stopPropagation(); // prevent click on drop menu from removing the drop down.
});
It works great but like this :
$(document).click(function(){
// hide drop down clicking anywhere on page:
dropMenu('slideUp', 0);
});
$("#dM1").click( function(e) {
e.stopPropagation(); // prevent click on drop menu from removing the drop down.
dropMenu('dropMenu1', $(this).position().left);
});
Now i have to insert the similar code on the global page, someone have an idea how i can insert dynamically a js code ?

Categories