Hi We have a silverlight control hosted in a hidden div (and height 0px) which is then shown within a jquery dialog when a user clicks a button the page
The initial showing of the dialog calls the onLoad param and initialises the silverlight control correctly. However the user has the option to close the dialog and hide the silverlight control.
The user can then show this dialog again (without reloading a page), however, in IE the onLoad param is not fired and consequently our silverlight control is not initialised correctly as we are handling hardware within it. In Chrome, however, the onLoad param is fired everytime the jquery dialog is shown
Two very different behaviours. I cant remove the the hidden div from the dom as it might be needed again
Is there a solution to forcibly reload the silverlight control so that the param onLoad is fired everytime the control is displayed with the jquery dialog?
TIA
Andrew
Not sure I got an overall idea. Raising onLoad is definitely not good.
but let me suggest solution above.
Register communication objects(aka functions) in JS and silverlight as well. So you will be able to communicate JS -> Silverlight
<script type="text/javascript">
function updateSilverlight() {
// call silverlight control method
var control = document.getElementById("silverlightControl");
control.Content.Page.SomeMethod("someData');
}
</script>
Annotate class like this:
[ScriptableType]
public partial class SomePage: UserControl
{
Annotate appropriate method inside SomePage
[ScriptableMember]
public void SomeMethod(string somedata)
{
var data = somedata;
}
where data is your re-init params...
hope that helps
Below is the code for opening dialog that contained the silverlight control
$('#ReadCard').on('click', function (e) {
$('#silverlightControlHost').height('300');
e.preventDefault();
//show the read card dialog
$("#readCardDialog").dialog({
autoOpen: true,
height: 390,
width: 550,
modal: true,
resizable: false,
buttons: {
'Close': function () {
Call_SL_OnBeforeUnload();
$(this).dialog("close");
}
}
});
});
On loading the silverlight control there is a method call to SilverlightInitialisation:
function onSilverlightLoad(sender, eventargs) {
.....
pluginElem.Content.SR_SMT.SilverlightInitialisation(inputArray);
}
Which was called by the optional silverlight paramater:
<param name="onload" value="onSilverlightLoad" />
This started the hardware that the silverlight control was talking to.
When the dialog was closed the method is called to stop the hardware:
Call_SL_OnBeforeUnload();
However when the dialog is shown again in IE the SilverlightInitialisation method is never called unless the user would refresh the page.
A work around was to alter the method (OnLoad) to the silverlight control that was always called when the dialog was opened but that checked a flag (hasLoaded) to see if it loaded previously:
Silverlight
[ScriptableMember]
public string OnLoad()
{
string retVal = G4T.SilverlightBadge.Resources.ResourcesFile.Present_Card;
if (_badgeReadCtrl != null && hasLoaded)
{
if (!_badgeReadCtrl.Initialise())
{
retVal = "Failed to initialise reader device";
}
}
return retVal;
}
The OnFirstLoad method was added which was called when the silverlight control first loaded and set the flag accordingly
[ScriptableMember]
public string OnFirstLoad()
{
string retVal = G4T.SilverlightBadge.Resources.ResourcesFile.Present_Card;
if (_badgeReadCtrl != null)
{
if (!_badgeReadCtrl.Initialise())
{
retVal = "Failed to initialise reader device";
}
}
hasLoaded = true;
return retVal;
}
Javascript
open: function (event, ui) {
try {
var plugin = document.getElementById('SilverlightMainControl');
if (plugin) {
plugin.Content.SR_SMT.OnLoad();
}
}
catch(e){}
},
Like I said above this always worked in Chrome without the modifications but in IE the initialisation is never called more than once
Hope all this makes sense - but i had to document it for future ref
Related
[!Newbie alert!] I'm using a ecommerce platform that doesn't allow me to edit the source code. I can only add new codes (html, js or css) to try to do the modifications I want. And what I want to do is to find a way to disable the script of a newsletter popup on only one specific page. The only way I thought of doing it is adding an extra JS script limiting the action of the previous script that I am not allowed to edit. Is it possible to do?
The original script for de Newsletter Popup is this:
<script type="text/javascript">
$(function() {
iniciarModalNews();
});
function iniciarModalNews() {
if (!$.cookie('showModalNews')) {
showModalNews();
};
}
function showModalNews() {
$.fancybox.open({
type: 'html',
minWidth: 270,
maxWidth: 350,
content: $('#modalNewsletter'),
beforeClose: function() {
$.cookie('showModalNews', 'hide', {
expires: 1,
path: '/'
});
}
});
}
</script>
It runs on all pages of the website and I want to exclude just one page. Is there a way to do this?
Thanks
Full Disclosure: This suggestion would not be considered a best practice but if its a one-off scenario where you don't have access to the source code it'll work.
If you only need to disable this on one page and have access to insert a block of script below the declaration of showModalNews() { ... } you can override the showModalNews() function by writing a new function with the same name. The method that calls the showModalNews method is inside an closure via IIFE (https://developer.mozilla.org/en-US/docs/Glossary/IIFE) but the method showModalNews() is NOT wrapped in a closure which would give you access to override it.
Example of the overridden method
function showModalNews() { ; }
I have the following situation on a web application.
A dialog is built and opened on the fly when clicking on a link:
var dialogInitiator = $("<div id='dialog-initiator' style='background-color: "+bgcolor+";'>Loading...</div>");
dialogInitiator.appendTo(parentFrame);
dialogInitiator.dialog({
modal:true,
autoOpen: false
}).on('keydown', function(evt) {
if (evt.keyCode === $.ui.keyCode.ESCAPE) {
dialogInitiator.dialog('close');
}
evt.stopPropagation();
});
dialogInitiator.dialog('open');
Right after that, I load a new html page into the dialog, with an < object >, like this:
var objectFrame = $('<object style="border: 0;width:'+(dlwidth-30)+'px;min-height:'+(dlheight-46)+'px;" type="text/html" style="overflow:auto;" data="'+url+'"></object>');
dialogInitiator.html(objectFrame);
Now, the "url" variable contains a link to this new html document. When that page is ready, it will focus on an input field. This prevents the ESCAPE key from closing the dialog. So, I am trying to manually trigger the .dialog('close') event on escape keypress.
I do the following, from within the loaded document:
$('#dialog-initiator', window.parent.document).dialog('close');
It get the following error:
"Error: cannot call methods on dialog prior to initialization; attempted to call method 'close'"
Strange thing is, when i call:
console.log( $('#dialog-initiator', window.parent.document).html() );
it shows me the html from the dialog. So it actually IS initiated.
Well, I have tried to fix this error with the help of Google, but without success. I guess my situation is quite specific.
Note: we are forced to use the technique with loading this whole webpage into the dialog due to older functionality we used in modalDialogs. Since they are depricated in the latest Google Chrome, we've built a temporary solution with jQuery dialog.
I hope someone can help me out. I appreciate it!
You can try a global method created after the modal is created
dialogInitiator.dialog({
modal: true,
autoOpen: false,
create: funtion(e,ui) {
window.closeMyDialog = function() {
$('#dialog-initiator').dialog('close');
};
}
})...
Then call it by doing window.parent.closeMyDialog();.
Why not use JQuery UI? It's easier than making your own.
http://jqueryui.com/dialog/#default
I am trying to use 2 jQuery navigation scripts on one page (Superfish for desktops and FlexNav for mobile). I am currently using matchMedia along with the polyfill by Paul Irish to respond to CSS3 media query state changes within JavaScript.
The current code is only accomplishing 50% of the overall goal. If you access the web page initially with a window size equal to or greater than 999px wide then you get Superfish and if you initially access the web page with a window size less than 999px then you get FlexNav. The problem occurs when you resize the window above or below 999px as both scripts become active.
// media query event handler
if (matchMedia) {
var mq = window.matchMedia("(min-width: 999px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
$("ul.sf-menu").superfish({
delay: 350,
speed: 400,
});
} else {
$("ul.flexnav").flexNav({
'animationSpeed': '250',
'transitionOpacity': true,
'buttonSelector': '.menu-button',
'hoverIntent': false
});
}
}
As much as I would like to get this working with matchMedia, I am open to all suggestions.
Update: Thanks to Stephan's suggestion I now have the following code:
jQuery(document).ready(function () {
// add destroy function for FlexNav
flexNavDestroy = function () {
$('.touch-button').off('touchstart click').remove();
$('.item-with-ul *').off('focus');
}
// media query event handler
if (matchMedia) {
var mq = window.matchMedia("(min-width: 999px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
if (typeof (flexNav) != "undefined") {
flexNavDestroy();
}
superfish = $("ul.sf-menu").superfish({
delay: 350,
speed: 400,
});
} else {
if (typeof (superfish) != "undefined") {
superfish.superfish('destroy');
}
flexNav = $("ul.flexnav").flexNav({
'animationSpeed': '250',
'transitionOpacity': true,
'buttonSelector': '.menu-button',
'hoverIntent': false
});
}
}
});
Remaining Issue:
The destroy function for FlexNav is only partially destroying it.
The best way would probably be to destroy the other plugin when you're activating one.
If I look in the source of Superfish there is a destroy function which does this, but flexNav doesn't have such a function. You can create one though:
flexNavDestroy = function(){
$('.touch-button').off('touchstart click').remove();
$(('.item-with-ul *').off('focus');
}
Then you could do this:
function WidthChange(mq) {
if (mq.matches) {
if(typeof(flexNav) != "undefined") {
flexNavDestroy();
}
superfish = $("ul.sf-menu").superfish({
delay: 350,
speed: 400,
});
} else {
if(typeof(superfish) != "undefined") {
superfish.superfish('destroy');
}
flexNav = $("ul.flexnav").flexNav({
'animationSpeed': '250',
'transitionOpacity': true,
'buttonSelector': '.menu-button',
'hoverIntent': false
});
}
}
UPDATE
I've looked a little bit more into FlexNav, and there's a few things I missed.
I think the styles are colliding because FlexNav sets a lot of styles by default. We can easily prevent that by using two classes: One for flexnav styling (the default .flexnav) that we can remove to hide all it's styles, and one for binding the javascript function (that will always stay there, or we can't re-attach it).
I generally like to prepend any classes that are meant as JS hooks with js-, so in my example (below) I replaces the .flexnav class on the menu with .js-flexnav. Then to activate flexnav you have to add this line just before you call $('ul.flexnav').flexNav()
$('.js-flexnav').addClass('flexnav');
In the destroy function you will have to remove the class again, which I will show shortly.
In addition, I'm not sure how Superfish does the showing and hiding, but since FlexNav collapses all submenus, it's also safe to say you should re-show them so that Superfish can do it's own thing.
The updated destroy function to reflect this:
function flexNavDestroy(){
$('.touch-button').off('touchstart click').remove();
$('.item-with-ul *').off('focus');
$('.js-flexnav').removeClass('flexnav').find('ul').show(); // removes .flexnav for styling, then shows all children ul's
}
Here's a jsFiddle that shows activating/deactivating flexNav with the new code: http://jsfiddle.net/9HndJ/
Let me know if this does the trick for you!
here is an alternative path :
once page is loaded :
cache the menu in a jquery object, clone it & instantiate both plugin one on each clone
$menucontainer= $("#menu_container");
$memufish = $menucontainer.find(".menu");
$menuflex=$menufish.clone();
$menufish.superfish().detach();
$menuflex.prependTo($menucontainer).flexnav().detach();
(they are loaded anyway so it's no big deal even if most of the time one won't be needed, it will be there & ready just in case - however test if you can instantiate on the clone without appending it to the DOM)
depending on width append / prepend the required one
$menuflex.prependTo($menucontainer);
on change width detach one reattach the other
$menufish.detach();
$menuflex.prependTo($menucontainer);
you could also work your way checking if plugin was instantiated on a width change (in order to not instantiate uselessly onload) but in any way I believe the use of clone() and detach() are very much adapted to solve easily your problem. The destroy way seems to be a hassle, lots of work (for the script as well when some user is raving with window resize) loss of time & a risk of many bugs to me ( expect more and more lag at every destroy re instantiate - with detach() no worries)
cons : will use a bit more memory overhaul
pros :
script will work less & it will be real fast to switch from one to the other
you could make a plugin from this and add other menu plugin to your app very easily without worry about conflict and how to destroy
I am creating a small wrapper for the fantastic BlockUI plugin used in my application to easily create dialogs that meet my needs.
Sometimes I am a bit jQuery retarded and would like to know from any of the aficionados out there how they would do this particular task.
This function creates a header, middle and footer custom to my application. Uses some passed in options to fill out the HTML further. Composes the dialog and then inserts it into the BlockUI plugin.
function blockApp(element, options){
var header = jQuery('<div class="modal-header clearfix"><h2></h2><span></span></div>'),
center = jQuery('<div class="modal-content"></div>'),
footer = jQuery('<div class="modal-footer"></div>');
//Compose dialog
var opts = jQuery.extend({}, dialogDefaults, options);
header.find('h2').html(opts.title);
center.html(jQuery(element).html());
var comp = jQuery('<div></div>').append(header).append(center).append(footer);
jQuery('#notificationUI').block(jQuery.extend({}, standardBlock, {
message: comp,
}));
jQuery('.blockOverlay').click(function(){
jQuery('#notificationUI').unblock();
});
}
I tried using wrap() and wrapInner() at first with no success also.
My question is How would John Resig do this?
Not sure if this is what you're looking for but I've recently used BlockUI w/ another jQuery plug-in called jConfirm which you can download from here. With the jConfirm (or jAlert or jPrompt) you can fully customize your alert box via CSS. My scenario is probably way different than yours but in my app, user's can make changes to a document. If they choose to click my "cancel" button to erase all of their changes I have a jConfirm alert pop up while using BlockUI to dim out the interface from them. It looks pretty slick. Using jQuery I can catch the click event of my "cancel" button and do something like:
$('.cancel').click(function () {
$.alerts.dialogClass = 'my_css';
$.blockUI({ message: null });
jConfirm('Are you sure you want to cancel?', 'Cancel Changes?',
function (r) {
if (r.toString() == 'false') {
$.unblockUI();
} else {
//close window
}
});
return false;
});
Hope this helps!
I am running a function that needs to close a Dojo dialog if it is loaded. How do I check if a dojo dialog is running? Do I use pure JavaScript and check by id if it is undefined?
if (dijit.byId("blah") !== undefined) {
destroyRecursive dijit;
}
Or do I use a property of the dialog object like:
isFocusable method
isLoaded property
Dialog provides two properties you might want to check: isLoaded and open. By digging the code you'll find the following descriptions:
open: True if Dialog is currently displayed on screen.
isLoaded: True if the ContentPane has data in it, either specified during initialization (via href or inline content), or set via attr('content', ...) / attr('href', ...) False if it doesn't have any content, or if ContentPane is still in the process of downloading href.
So, you could just:
var dialog = dijit.byId("blah");
if( dialog.open ) {
dialog.destroy();
}
Do you want to hide it or destroy it?
If you just want to show/hide it you can do the following:
var dialog = dijit.byId('blah');
if (dialog) {
if (dialog.open) {
dialog.hide();
}
else {
dialog.show();
}
}
If you wanted to destory it to free up memory:
var dialog = dijit.byId('blah');
dialog.destory();
I think destroy is recursive since it calls its parent destroy method and one of its parents is dijit.layout.ContentPane.