jQuery Draggable Handler inside IFrame - jquery-ui

What a mouthful.
Basically I have a parent <div> and inside that an <iframe>. I need an element inside the iframe to be the handle to drag the parent div. Is this even possible?
I have tried:
$(node).draggable("option","handle",$('iframe',node).contents().find('#handle'));
$(node).draggable("option","handle",$('iframe',node).contents().find('#handle')[0]);
It is targeting the right DOM element but it just won't drag. It might be possible to overlay a hidden div ontop of the iframe but I have found the iframe takes the event over the div when position is absolute. Strange.

try this
$('#Div').draggable({ iframeFix: true });
this should work

I decided to take a stab at this and boy, it's a lot of work with little progress using an internal iframe node as a handle. Anyway, here are two solutions, the first one doesn't work really well, but if you can get it to work, it may be more desirable.
main.html (plagiarized from the demo)
<div id="draggable" class="ui-widget-content" style="position:relative;">
<p class="ui-widget-header">I can be dragged only by this handle</p>
<iframe name="iframe1" src="inner-handle.html" height=50 width=80></iframe>
</div>
inner-handle.html
<html>
<head>
<script type="text/javascript" src="../../jquery-1.4.2.js"></script>
</head>
<body>
<div id="innerHandle">handle</div>
</body>
</html>
JavaScript
$(function () {
var moveEvent;
$(document).mousemove(function (e) {
moveEvent = e;
});
$("#draggable").draggable();
$('iframe', '#draggable').load(function () {
$('iframe', '#draggable')[0].contentWindow.$('#innerHandle').mousedown(function (e) {
$('#draggable').draggable().data('draggable')._mouseDown(moveEvent);
return false;
});
});
});
It took me a while to find something that "worked." The problem here was that since the mousedown event occurred on an element inside the iframe, the mouse event is relative to the iframe, not the main document. The workaround is to have a move event on the document and grab the mouse position from there. The problem, once again, is that if the mouse is inside of the iframe, it is "not" moving according to the parent document. This means that the drag event only happens when the mouse reaches the edge of the iframe into the parent document.
A workaround for this might be to manually generate events with the calculated position of the iframe relative to its mouse movement. So when your mouse moves within the iframe, calculate its movement using the coordinate of the iframe to the parent document. This means that you need to use the event from the mousedown and not the mousemove,
$('iframe', '#draggable')[0].contentWindow.$('#innerHandle').mousedown(function (e) {
// do something with e
$('#draggable').draggable().data('draggable')._mouseDown(e);
return false;
});
The second solution is the way you have mentioned, have an absolute positioned div over the iframe itself. I have no trouble in getting the div to be on top of the iframe, that is,
<div id="draggable" class="ui-widget-content" style="position:relative;">
<p class="ui-widget-header">I can be dragged only by this handle</p>
<iframe name="iframe1" src="inner-handle.html" height=50 width=80></iframe>
<div style="position: absolute; height: 30px; width: 30px; background-color: black; z-index: 1000;"></div>
</div>
The problem with your div being behind the iframe might be because the z-index is off. If you declare your div before the iframe and you didn't specify the z-index, then the iframe will be on top.
Whichever way you choose, good luck!

what happens when you do this (with firebug activated):
var frameContent = $('iframe',node).contents()
var handle = frameContent.find('#handle');
console.debug(frameContent, handle)
Does handle contain a list of elements? And if so, look carefully at the Document object which is frameContent - is the URL "about:blank"? It's just a hunch, but if you get these outputs, it's probably executing the jQuery selector before the frame content has loaded (i.e., before the #handle element exists).
In which case, you can add an event to the IFRAME'd document, and communicate with the parent frame via window.parent.

Related

Jquery Mobile: Embed external HTML file without iframe

How can I load a external html page in a div?
<div data-role="page" id="pageone">
<div data-role="panel" id="myPanel">
<!--Load nav.html here-->
</div>
...
I have tried with following code but it doesn't function.
$( "#myPanel" ).load( "nav.html" );
See: http://plnkr.co/edit/N6xTrvLHWdOMG9Lq?open=lib%2Findex.html
The panel is expecting some markup as content, not a whole HTML page.
This will load Your navigation listview inside the panel:
$(document).on('panelcreate', '#myPanel', function () {
$(this).children(".ui-panel-inner").load("nav.html ul", function() {
$(this).enhanceWithin().trigger("updatelayout");
});
});
The full-width listview is requiring some additional CSS:
/* The left reveal panel shadow is 5px inset and blurred by 5px */
.ui-panel-display-reveal.ui-panel-position-left .ui-listview {
margin-right: -10px;
}
EDIT:
To test Your navigation menu and see if it looks as intended, You may design it directly inside the panel. To allow the framework to create the panelInner, simply put somewhat inside the panel div, i.e. a placeholder div or, as said, even better the static version of Your navigation menu. Thus, it will be then correctly replaced by Your external version.
In one word, instead of <!--Load nav.html here--> write <div>...</div>.

Modal Dialog is obscured by opaque background

I am using Element's Notification component but when it is activated the dialog appears but seems to be "behind" the grey background that is also introduced. Clicking anywhere removes the grey background and allows the interaction with the dialog box but without the greyed out background that should be filtering out the noise of the normal screen. Here is a short video that shows the various states:
video
The code to put the component in as follows:
<div class="add-address" #click="showAddDialog = true">
+
</div>
</div>
<el-dialog
title="Add New Address"
:visible.sync="showAddDialog"
width="30%"
:before-close="newAddressDialogClosed">
<span>Postal Address</span>
<el-input v-model="newAddress" type="text"></el-input>
<span slot="footer" class="dialog-footer">
<el-button #click="dialogVisible = false">Cancel</el-button>
<el-button type="primary" #click="dialogVisible = false">Confirm</el-button>
</span>
</el-dialog>
I have used the inspector to poke around at the CSS but I haven't yet understood what's causing this from a CSS perspective nor a Vue/Element perspective. Any help would be appreciated.
I have further analyzed the HTML/CSS and the component appears to introduce two separate blocks in the DOM:
The lower block is the grey background which you'd expect to "blur" the page and focus attention on the modal. It, however, is in front of the dialog. Also of interest is that clicking anywhere seems to target the grey background and dismiss it but in so doing it also has a subtle effect on the placement on the dialog box as can be seen here:
Note that the z-index of the dialog box is greater than the background which intuitively makes sense to me but I'd have thought this would have put the dialog box on top. Guess that's not all there is to this.
I have hacked a work-around for now by changing the background to display: none and then adding the following HTML directly before the modal dialog in the DOM:
<div class="modal-background" v-if="showAddDialog"></div>
These seems to validate my underlying suspicion that placement within the DOM tree is important and the component's attempt to place the modal background at the very end of the DOM is somehow problematic.
I had the same issue and also found changing the z-index of the dialog had no effect. This was occurring when I had nested Element.Eleme.io elements, which appears to be the case for you also.
The z-index is not quite as simple as "higher always means on top". Elements are grouped into different stacking contexts; it is not possible for an element in a lower stacking context to appear above an element in a higher stacking context. Therefore depending on where the different elements were rendered in the DOM, they can land themselves in different stacking contexts, and are destined to remain at the same relation to one another, no matter how much the z-index has changed. (See https://philipwalton.com/articles/what-no-one-told-you-about-z-index/ for a more detailed explanation on the z-index).
Examining with Chrome dev tools, I found that the obscuring modal is not rendered in the same place as the dialog; in fact it is appended to the body, i.e. on the outer reaches of the application, which appears to be the reason they are not within the same stacking context. There is a quick fix; the dialog element has a property "modalAppendToBody". If true, the modal is rendered to the body, and if false it is rendered to the parent element of the dialog. By specifying this as false I managed to solve the issue:
<el-dialog
title="Add New Address"
:visible.sync="showAddDialog"
width="30%"
:before-close="newAddressDialogClosed
:modalAppendToBody="false">
</el-dialog>
you can use the CSS property called z-index
either any object which you want to set to back ? you just have to set z-index: -1; // or more
or you want to set any object on to the front of another ? you just have to set z-index: 1; //or more
Check the Snipet For More Info :
.a {
position: absolute;
left: 0px;
top: 0px;
z-index: -1;
}
.b {
margin-top:150px;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1> I am on Image</h1>
<img class="a" src="http://qnimate.com/wp-content/uploads/2014/03/images2.jpg" width="100" height="140">
<br>
<br>
<br>
<br>
<h1> Image is on me</h1>
<img class="b" src="http://qnimate.com/wp-content/uploads/2014/03/images2.jpg" width="100" height="140">
</body>
</html>

How to make nested layouts with jquery-layout resizable?

I'm trying to create a 4-pane layout using the jQuery-Layout plugin.
Really basic stuff:
The layout (note that I use iframes):
<iframe class="ui-layout-center">Outer Center</iframe>
<iframe class="ui-layout-east">Outer East</iframe>
<div class="ui-layout-west ">
<iframe class="ui-layout-south">Middle South</iframe>
<div class="ui-layout-center ">
<iframe class="ui-layout-center">Inner Center</iframe>
</div>
</div>
The initialization:
$(document).ready(function () {
$('body').layout({
west__childOptions: {
center__childOptions: {
}
}
});
});
Here's a fiddle.
Updated, simpler fiddle.
All is well until I try to resize the panes. It kinda works, but is very rough. When dragging the pane resizer handles it looks like they lose contact with the mouse pointer and stop resizing.
If the panes are simple divs, everything works, but not if the panes are iframes (which is what I need).
Any idea on how I could debug this?
I have found the answer here
Basically, you need to mask each panel (and its parents, in case of nested panels) that contains an iframe.
Like this:
$('body').layout({
center__maskContents: true,
west__maskContents: true
});
Here's the working demo of the fiddle from the question: click

jQuery-UI drop doesn't really drop anything in the droppable

I notice in the jsfiddle here - http://jsfiddle.net/stevea/T4sGh/1/ - that when you drag and drop the red box onto the beige box, it looks like the red box goes inside the beige box, but in the HTML it actually becomes a sibling of the beige box and is just given offsets to place it over the beige box:
<body style="cursor: auto;">
<div id="box" class="ui-droppable"></div>
<div id="redBox" class="ui-draggable" style="position: relative; left: 89px; top: -213px;"></div>
</body>
This was unexpected. I don't recall any jQuery-UI documentation that talks about this.Does anyone have a feel what what is going on here and perhaps be able to point me to some documentation?
Thanks
The draggable and droppable do not change the DOM by default. If you want to do that you can utilize the events that they expose. Here's your fiddle updated. I am using the drop event in order to reposition the draggable inside your droppable container on drop:
var cell_dropOps = {
drop : box_drop,
accept : '#redBox',
drop: function (event, ui) {
$(this).append(ui.draggable);
ui.draggable.css({ top: 0, left: 0});
}
};
If you look at the example on this jQuery UI page, you'll notice that this is the default behavior.
If you wish to make dragable object a child of dropable object, you will have to append it manually in your drop function like:
$(this).append($(ui.helper[0]));
The whole purpose of mentioning accept : '#redBox' is that when you drop #redBox on your dropable div, the drop event gets fired.

How make jquery-ui autocomplete get out iframe?

Is it possible to make the suggestions of autocomplete (jQueryUI) get out one iframe, having the same behaviour of "select" element? I make one example:
http://jsbin.com/ehidef/1
As a matter of fact, it can be done, though some styling will be mandatory. jQueryUI accepts an element to append the options to, and you can pass the parent window as that element. An example:
main window:
<html>
<head></head>
<body>
<iframe src="iframe.html"></iframe>
</body>
</html>
iframe.html
<html>
<head>
<!-- include jQuery and jQuery UI and the like -->
<script type="text/javascript">
jQuery(function($){
// This will take parent frame if in iframe, own body elsehow
var el=top.document.body
// Instructs jQuery UI to show things on that previous element
$('input').autocomplete({appendTo:el});
});
</script>
</head>
<body>
<input type="text"/>
</body>
</html>
The whole example is missing all things not relevant to explainig the point, so it's not functional. Addapt as needed and add some suggar.
As for the styling i was refering before, you will have to give elements a position and style, as 1) position relative to input position is irrelevant on parent window and 2) parent doesn't need to have jqueryui stylesheets loaded, although you can load them dinamically from inside the iframe with a similar technique.
IMPORTANT:
This will only work if both, parent and child are in the same domain [see: SOP]
UPDATE
After finishing doing this same thing, i came up with this solution for styling and position:
var files=[ // UI styles to be loaded on top frame
"css/ui-lightness/jquery-ui-1.10.3.custom.css",
"css/ui-lightness/custom.css"
]
// Create link tag and append to top frame head
for (var a in files) {
var style=$("<link/>", {
rel: "stylesheet",
type: "text/css",
href: files[a]
});
$(top.document).find('head').append(style);
}
// As it turns out i had many iframes, so this will get the right one
var parentIframe=$(el).find('iframe').filter(function(){
return window.frameElement==this
});
$('input').each(function(){ // Cicle inputs to use with ui autocomplete
// set position to left + input offset 2 is a fix for borders on input
var pos= "left+"+($(this).offset().left+2)+
// and to top + input position + height to have it on the bottom
" top+"+($(this).offset().top+$(this).outerHeight()+1);
// Autocomplete
$(this).autocomplete({
appendTo:top.document.body, // put it on top window's body
position:{
at: pos, // at calculated position
of:parentIframe // from parent iframe
}
})
});
Once again, there may be voids, so fill up with relevant code at will

Resources