Moving ModalPopup Outside the IFrame. Possible? - asp.net

I have an iframe inside my main page. There is a modalpopup inside the iframe page. So when the modalpopup is shown, the parent of the modalpopup is the iframe body and the main page parent body. Thus the overlay only covers the iframe and not the entire page.
I tried moving the modalpopup from the iframe to the parent windows body element (or any other element inside the parents body) using jQuery. I am getting an invalid argument error.
How do I show a modalpopup from an page inside iframe and it should cover the entire document, parent document as well?
Update:
Since few users are interested in achieving the same behavior .. here is the workaround
The best workaround that I would suggest would be to have the modalpopup in the main page .. and then invoke it from the iframe .. say something like this ..
/* function in the main(parent) page */
var _onMyModalPopupHide = null;
function pageLoad(){
// would be called by ScriptManager when page loads
// add the callback that will be called when the modalpopup is closed
$find('MyModalPopupBehaviorID').add_hidden(onMyModalPopupHide);
}
// will be invoked from the iframe to show the popup
function ShowMyModalPopup(callback) {
_onMyModalPopupHide = callback;
$find('MyModalPopupBehaviorID').show();
}
/* this function would be called when the modal popup is closed */
function onMyModalPopupHide(){
if (typeof(_onMyModalPopupHide) === "function") {
// fire the callback function
_onMyModalPopupHide.call(this);
}
}
/* functions in the page loaded in the iframe */
function ShowPopup(){
if(typeof(window.parent.ShowMyModalPopup) === "function") {
window.parent.ShowMyModalPopup.apply(this, [OnPopupClosed]);
}
}
// will be invoked from the parent page .. after the popup is closed
function OnPopupClosed(){
// do something after the modal popup is closed
}
Hope it helps

If you're using the iframe simply for scrollable content you might consider a styled div with overflow: auto or scroll, instead.
A set up such as this makes it easier to modify the appearance of the entire page since you're not working with multiple documents that each essentially have their own window space inside the page. You can bypass some of the cross-frame communication and it may be easier to keep the information in sync if you need to do that.
This may not be suitable for all situations and may require ajax (or modifying the dom with javascript) to change the div contents instead of just loading a different document in the iframe. Also, some older mobile browsers such as Android Froyo builds don't handle scrollable divs well.

You answered your own question in your update. The modal dialog needs to live on the parent page and invoked from the iframe. Your only other option is to use a scrolling div instead of an iframe.

It is not possible the way you are asking. Think of it this way: an iframe is a seperate window. You cannot (for the time being) move a div in one webpage into another.

I have done this by writing a small code for jQuery see below maybe this can help :
NOTE: Make sure you are doing on same domain
HTML:
<button type="button" id="popup">Show Popup</button>
<br />
<br />
<iframe src="your url" style="width: 100%; height:400px;"></iframe>
JS:
// Author : Adeel Rizvi
// It's just a attempt to get the desire element inside the iframe show outside from iframe as a model popup window.
// As i don't have the access inside the iframe for now, so I'll grab the desire element from parent window.
(function () {
$.fn.toPopup = function () {
return this.each(function () {
// Create dynamic div and set its properties
var popUpDiv = $("<div />", {
class: "com_popup",
width: "100%",
height: window.innerHeight
});
// append all the html into newly created div
$(this).appendTo(popUpDiv);
// check if we are in iframe or not
if ($('body', window.parent.document).length !== 0) {
// get iframe parent window body element
var parentBody = $('body', window.parent.document);
// set height according to parent window body
popUpDiv.css("height", parentBody.height());
// add newly created div into parent window body
popUpDiv.appendTo(parentBody);
} else {
// if not inside iframe then add to current window body
popUpDiv.appendTo($('body'));
}
});
}
})();
$(function(){
$("#popup").click(function () {
// find element inside the iframe
var bodyDiv = $('iframe').contents().find('YourSelector');
if (bodyDiv.length !== 0) {
// Show
$(bodyDiv).toPopup();
} else {
alert('Sorry!, no element found');
}
});
});
CSS:
.com_popup {
background-color: Blue;
left: 0;
position: absolute;
top: 0;
z-index: 999999;
}

Related

CSS spinner causing 2 get requests when js code is triggered

I am trying to create a loading spinner to put at the bottom of a div like this jsfiddle so its always at the bottom when my returned code is appended to its sibling above its child element. Then when I scroll to the bottom of the page my endless scroll script runs and changes display from none to block of the spinner and once the next set of results is appended the spinner is hidden again.
The problem is is that once the scrollbar hits the bottom of the page the spinner triggers the get request twice for some reason and my results are doubled upon being appended. This happens only when the spinner div is inside the container element. My code runs fine with the spinner there appending the results once. Even using position:relative; on the container and absolute on the spinner div and setting bottom:0px; causes two get requests.
No matter how I create the spinners with CSS they all do the same thing multiple get requests. I have had to place the spinner in a div with overflow:hidden; also to prevent the jumping behavior of the scrollbar which causes continuous get requests when my code triggers.
Am I going the right way about this or is my logic flawed or what is wrong here?
EDIT js code that triggers the get request
$(document).ready(function() {
if ($('.pagination').length) {
$('#id2').scroll(function() {
var currentuserfeed = $('#currentuserfeed .pagination .next_page').attr('href');
if (currentusershow && $('#id2')[0].scrollHeight > 820 && $('#id2').scrollTop () >= $('#id2')[0].scrollHeight - $('#id2').height ()) {
return $.ajax({
type: 'GET',
url: currentusershow,
data: { currentusershow: 'user' },
dataType: 'script',
});
};
});
return $('#id2').scroll();
};
};

Creating a TinyMCE inline editor AND making it visible from a button

I'd like to use TinyMCE 4.1.7 in inline mode. When the user right-clicks a DIV and selects Edit, indicating they want to edit the DIV, I execute
var id= g.currentElement$.attr('id');
tinymce.init({
selector: "div#"+id,
inline:true,
});
This adds a TinyMCE editor (I know because I catch an AddEditor event) but it doesn't seem to append the editor elements to the DOM (I can't see them in Chrome DevTools Elements tab). For the editor to appear I have to click inside the DIV.
I want to change this behavior so that when the user right-clicks the DIV and selects Edit, my handler will also trigger whatever is triggered now by clicking in the DIV. So after I've launched the editor, as above, I need to call some other method that will append the editor to the DOM and make it visible, so clicking Edit in the context menu is all I need to bring up the TinyMCE editor.
Could someone tell me what I need to do to accomplish this?
(The reason I can't just click the DIV to bring up the editor is that a click already means something else. A single click selects the DIV, where it can be deleted, duplicated, nudged, etc. A drag on the DIV moves it. And a drag on a DIV corner resizes the DIV. A right-click with an Edit option is all I have left.)
Thanks for your help.
Steve
I got this working as follows.
I first run the tinymce init:
var id= g.currentElement$.attr('id');
tinymce.init({
selector: "div#"+id,
inline:true,
});
That creates an editor for the element but doesn't render or show it. Rendering and showing the editor normally requires a mousedown on the element.
After stepping through a lot of tinymce code I realized that firing a focusin event on the editor instance is what gets the editor rendered and displayed. So I created a callback for AddEditor. The AddEditor event comes in early in the editor create process, though, and I didn't want to fire focusin until the editor was complete, so at the AddEditor event I get the editor instance and create a callback for "NodeChange," which happens at the end of the editor create.
When NodeCreate comes in I fire a "focusin" on the editor and that renders and displays the editor, as I wanted. A single click, now, runs tinymce init and leaves an inline editor displayed and ready on top of the element.
The total code is:
tinymce.on('AddEditor', function(e) {
e.editor.on('NodeChange', function(e) { // now that we know the editor set a callback at "NodeChange."
e.target.fire("focusin"); // NodeChange is at the end of editor create. Fire focusin to render and show it
});
});
If anyone sees anything wrong with this I'd be very grateful for any comments.
Thanks
tinymce.init({
selector: "div#"+id,
inline:true,
setup: function (ed) {
ed.on('init', function(e) {
e.target.fire("focusin");
});
}
});
This will do the trick for the initiating editor instance. Better then globally firing for every single NodeChange event for every single editor instance on the page. (Assuming there multiple editors but also works with single editor.)
BUT WAIT...
There is a better practice using JS Promises. tinymce.init returns a Promise Object.
let tinyMcePromise= tinymce.init({
selector: "div#"+id,
inline:true
});
tinyMcePromise.then(function(editors){
editors[0].focus();
});
Official documentation: https://www.tinymce.com/docs/api/tinymce/root_tinymce/#init
Beware: Some older versions of tinyMce have a bug about init Promise.
**Please first add jquery and tinymce library..**
<script src="latestjquery.js" type="text/javascript" charset="utf-8"></script>
<script src="tinymce.min.js"></script>
<form method="post">
<textarea>here firstly onlciki will show menu and when edit will be selcted then it will be converted into ediotr</textarea>
</form>
<ul class='custom-menu'>
<li data-action = "first">First thing</li>
<li data-action = "second">Second thing</li>
<li data-action = "third">Third thing</li>
</ul>
<script>
//Trigger action when the contexmenu is about to be shown
$("textarea").bind("contextmenu", function (event) {
// Avoid the real one
event.preventDefault();
// Show contextmenu
$(".custom-menu").finish().toggle(100).
// In the right position (the mouse)
css({
top: event.pageY + "px",
left: event.pageX + "px"
});
});
// If the document is clicked somewhere
$("textarea").bind("mousedown", function (e) {
// If the clicked element is not the menu
if (!$(e.target).parents(".custom-menu").length > 0) {
// Hide it
$(".custom-menu").hide(100);
}
});
// If the menu element is clicked
$(".custom-menu li").click(function(){
tinymce.init({
selector: "textarea"
});
// This is the triggered action name
switch($(this).attr("data-action")) {
// A case for each action. Your actions here
case "first": alert("first"); break;
case "second": alert("second"); break;
case "editor": alert("editor will appear");
break;
}
// Hide it AFTER the action was triggered
$(".custom-menu").hide(100);
});
</script>
<style>
.custom-menu {
display: none;
z-index: 1000;
position: absolute;
overflow: hidden;
border: 1px solid #CCC;
white-space: nowrap;
font-family: sans-serif;
background: #FFF;
color: #333;
border-radius: 5px;
}
.custom-menu li {
padding: 8px 12px;
cursor: pointer;
}
.custom-menu li:hover {
background-color: #DEF;
}
</style>

How do URL fragment (the #stuff) interacts with CSS?

How does URL fragments interact with CSS? I have a page, say: http://example.boom/is_this_a_bug.html. The code for the page is shown in https://gist.github.com/3777018
When I load the page with the URL like that, the .tab-pane elements are not showed because they overflow their container, and it has an overflow: hidden property.
However, if I load the page by appending a valid fragment (#00) to the URL, then the .tab-pane gets visible, just as if the left:100% was not taken into account. Pressing the button just removes and resets left:100%, and then I get the overflowing tab-panes.
This happens in both Firefox 15.0.1 and Chromium 18.0.1025.168 (Developer Build 134367 Linux) Ubuntu 12.04.
Any ideas why this is happening? Is this a bug, or is documented elsewhere?
Best regards,
Manuel.
When you load a page with a fragment identifier in the URL, if that fragment identifier matches the ID of an element on the page the browser will scroll the page to bring that element into view.
An alternative can be use javascript applied styles.
(function hashStyle() {
if (window.location.hash == '#COLOR') {
var css = document.createElement('style'),
s = document.getElementsByTagName('script')[0],
styles = 'body { background-color: #b0c4de; }';
css.type = 'text/css';
if (css.styleSheet) {
css.styleSheet.cssText = styles;
} else {
css.appendChild(document.createTextNode(styles));
}
s.parentNode.insertBefore(css, s);
}
})();

Applying Events Handler to Child Elements (Event Propogation in jQuery)

Edit : Problem wasn't related Event Propagation, if you want to know how to stop propagation in jQuery, then use event.stopPropagation();
When user moves his/her mouse over <span> element my jQuery code appends an <img>into this <span> element and when he moves out his mouse off <span> than the element appended is removed. It helps people to edit the field when clicking on the appended <img> element.
The reason I used append() method to add <img> into <span> is because I want to keep <img> element visible when user moves his mouse over to appended <img> element (<img> is becoming <span>'s child element) But it didn't happen and when user moves his mouse over it <img> is being deleted. I am thinking it is because event propagation but I couldn't find how to activate it in jQuery as we do with addEventListener in Firefox based browsers.
Here is the code :
JQuery Code :
$(document).ready(function() {
$('.EditEnabled').bind("mouseover", ShowEditFields);
$(".EditEnabled").bind("mouseout", HideEditFields);
});
function ShowEditFields(event) {
$(event.target).append(" <img id='editImg' src='images/edit.png' style='margin-bottom:-3px'/>");
}
function HideEditFields(event) {
$(event.target).children("#editImg").remove();
}
Simple HTML :
<span id="something" class="EditEnabled">Something Here</span>
Can you explain my how to solve it.
Thank you.
You want to use the jQuery mouseenter and mouseleave events, not mousover and mouseout. The reason is that mouseout will fire when you move the mouse over the img.
Thankfully, jQuery combines this into a hover method:
$(document).ready(function() {
$('.EditEnabled').hover(ShowEditFields, HideEditFields);
});
However I agree with the other answer that you should use CSS to do this vs. manipulating the DOM. I would just use the :hover pseudo selector, and then add special support for IE6.
CSS
span.EditEnabled img { display: none }
span.EditEnabled:hover img,
span.EditEnabled.hover img { display: block }
Make sure you have the img in the span in your HTML to begin with, and that is all you need for most browsers and IE7+
To support IE6 add:
<!--[if lte IE 6]>
<script type="text/javascript">
$(function(){
$(".EditEnabled").hover(
function(){ $(this).addClass('hover') },
function(){ $(this).removeClass('hover')}
);
});
</script>
<![endif]-->
Firstly, I would avoid as much DOM manipulation as you can. The ideal scenario is to construct your markup like this:
<span class="editEnabled">Some data<img ...></span>
with CSS:
span.editEnabled img { display: none; }
span.editEnabled img.visible { display: inline; }
and Javascript:
$(function() {
$("span.editEnabled").hover(function() {
$(this).children("img").addClass("visible");
}, function() {
$(this).children("img").removeClass("visible");
});
});
That should pretty much do it.
I would avoid the jQuery effects as making things visible will make them block level elements rather than inline like you want.
I've found another answer actually, the way I am looking for. It might not be a best practice but at least I've found out how to solve that.
$(document).ready(function() {
// $('.EditEnabled').bind("mouseenter", ShowEditFields);
// $(".EditEnabled").bind("mouseleave", HideEditFields);
$(".EditEnabled").hover(ShowEditFields, HideEditFields);
});
function ShowEditFields(event) {
var target = $(event.target);
if (target.is(":has(#editImg)") == false)
target.append(" <img id='editImg' src='images/edit.png' style='margin-bottom:-3px;display:inline'></img>");
}
function HideEditFields(event) {
// event.stopPropagation();
// if ($(event.relatedTarget).is("#editImg") == false)
$(event.target).children("#editImg").remove();
}

Iframe transparent background

My app has a modal dialog with an iframe inside it. I've written my jQuery code such that when the dialog opens, it sets the appropriate 'src' attribute of the iframe so the content loads up. However, during the delay between the dialog opening and the content loading, the iframe appears conspicuously as a white box. I'd prefer the iframe have a transparent background.
I've tried setting allowtransparency="yes" on the iframe. Any ideas? Thanks!
I've used this creating an IFrame through Javascript and it worked for me:
// IFrame points to the IFrame element, obviously
IFrame.src = 'about: blank';
IFrame.style.backgroundColor = "transparent";
IFrame.frameBorder = "0";
IFrame.allowTransparency="true";
Not sure if it makes any difference, but I set those properties before adding the IFrame to the DOM.
After adding it to the DOM, I set its src to the real URL.
<style type="text/css">
body {background:none transparent;
}
</style>
that might work (if you put in the iframe)
along with
<iframe src="stuff.htm" allowtransparency="true">
Set the background color of the source page to none and allow transparency in the iframe element.
Source page (for example, source.html):
<style type="text/css">
body
{
background:none transparent;
}
</style>
Page with iframe:
<iframe src="source.html" allowtransparency="true">Error, iFrame failed to load.</iframe>
Why not just load the frame off screen or hidden and then display it once it has finished loading. You could show a loading icon in its place to begin with to give the user immediate feedback that it's loading.
You need to make the iframe's body transparently. It works for me:
const iframe = document.createElement( 'iframe' );
iframe.onload = function() {
const doc = iframe.contentWindow.document,
head = doc.querySelector( 'head' ),
style = doc.createElement( 'style' );
style.setAttribute( 'type', 'text/css' );
style.innerHTML = 'body { background: transparent!important; }';
head.appendChild( style );
}

Resources