How to show multiple dialog polyfill? - javascript

I have script to open dialog polyfill :
window.modalDialog = function (url, arg, opt) {
url = url || ''; //URL of a dialog
arg = arg || null; //arguments to a dialog
opt = opt || 'dialogWidth:300px;dialogHeight:200px'; //options: dialogTop;dialogLeft;dialogWidth;dialogHeight or CSS styles
var caller = modalDialog.caller.toString();
var dialog = document.body.appendChild(document.createElement('dialog'));
var splitter = opt.split(",");
dialog.setAttribute('style', splitter[0].replace(/dialog/gi, ''));
dialog.innerHTML = '×<iframe id="dialog-body" src="' + url + '" style="border: 0; width: 100%; height: 100%;"></iframe>';
document.getElementById('dialog-body').contentWindow.dialogArguments = arg;
document.getElementById('dialog-close').addEventListener('click', function (e) {
e.preventDefault();
dialog.close();
});
dialog = document.querySelector('dialog');
dialogPolyfill.registerDialog(dialog);
function addListeners() {
document.querySelector('dialog').addEventListener('mousedown', mouseDown, false);
window.addEventListener('mouseup', mouseUp, false);
}
function mouseUp()
{
window.removeEventListener('mousemove', divMove, true);
}
function mouseDown(e) {
window.addEventListener('mousemove', divMove, true);
}
function divMove(e) {
var div = document.querySelector('dialog');
div.style.position = 'absolute';
div.style.top = e.clientY + 'px';
div.style.left = e.clientX + 'px';
}
addListeners();
dialog.showModal();
dialog.addEventListener('close', function () {
var returnValue = document.getElementById('dialog-body').contentWindow.returnValue;
document.body.removeChild(dialog);
nextStmts[0] = nextStmts[0].replace(/(window\.)?modalDialog\(.*\)/g, JSON.stringify(returnValue));
eval('{\n' + nextStmts.join('\n'));
});
throw 'Execution stopped until modalDialog is closed';
};
when I call this script, dialog-body got replaced with new url instead create new dialog. How can i create multiple dialog?
EDIT
My biggest problem is that my dialogs has the same parent (caller), so in dialog polyfill js library, there's script to check if there are dialogs or not in parent document, if yes, then throw warning Failed to execute showModal on dialog: The element is already open, and therefore cannot be opened modally.
EDIT
I have created the jsfiddle, but i dont know how to call external source website from jsfiddle.
https://jsfiddle.net/godofrayer/gvLpLjkq/

I modified your example a little bit and now you can open multiple dialogs.
The problem was the getElementById. An id has to be unique in a document. So I have organized the dialogs in an array, and the ID-elements now contain the index of the array at the the end of the id: id="dialog-close'+dlgIndex+'".
My modification is here
Here you can see the main changes:
var dlgs = [];
window.showModalDialog = window.showModalDialog || function(url, arg, opt) {
url = url || ''; //URL of a dialog
arg = arg || null; //arguments to a dialog
opt = opt || 'dialogWidth:300px;dialogHeight:200px'; //options: dialogTop;dialogLeft;dialogWidth;dialogHeight or CSS styles
var caller = showModalDialog.caller.toString();
var dialog = document.body.appendChild(document.createElement('dialog'));
// Adds the Dialog to an Array of Dialogs
var dlgIndex = dlgs.length;
dlgs[dlgIndex] = dialog;
dialog.setAttribute('style', opt.replace(/dialog/gi, ''));
dialog.innerHTML = '×<iframe id="dialog-body'+dlgIndex+'" src="' + url + '" style="border: 0; width: 100%; height: 100%;"></iframe>';
document.getElementById('dialog-body'+dlgIndex).contentWindow.dialogArguments = arg;
document.getElementById('dialog-close'+dlgIndex).addEventListener('click', function(e) {
e.preventDefault();
dialog.close();
});
dialog.showModal();
//if using yield
if(caller.indexOf('yield') >= 0) {
return new Promise(function(resolve, reject) {
dialog.addEventListener('close', function() {
var returnValue = document.getElementById('dialog-body'+dlgIndex).contentWindow.returnValue;
document.body.removeChild(dialog);
resolve(returnValue);
});
});
}
//if using eval
var isNext = false;
var nextStmts = caller.split('\n').filter(function(stmt) {
if(isNext || stmt.indexOf('showModalDialog(') >= 0)
return isNext = true;
return false;
});
dialog.addEventListener('close', function() {
var returnValue = document.getElementById('dialog-body'+dlgIndex).contentWindow.returnValue;
document.body.removeChild(dialog);
nextStmts[0] = nextStmts[0].replace(/(window\.)?showModalDialog\(.*\)/g, JSON.stringify(returnValue));
eval('{\n' + nextStmts.join('\n'));
});
//throw 'Execution stopped until showModalDialog is closed';
};
})();
var showDialog = function() {
window.showModalDialog("https://heise.de/");
console.log("ShowSecond!!!")
window.showModalDialog("https://www.heise.de/newsticker/meldung/Einstweilige-Verfuegung-Vodafone-muss-Kinox-to-sperren-3966023.html");
};
Hope this helps.

Related

Can't resolve a problem with closing my tooltip by onclick function

I am trying to make a function which will close my tooltip by 'click' on the parent element which returns me this tooltip by first click on it. Need to get the closing function exclusively for tooltip parent element. Right now everything is working, but i can also close my tooltip by clicking anywhere on body element.
`(function () {
function Tooltip(options) {
if (!options) options = {};
var self = this;
this.tooltips;
this.offset = 5;
this.beforeTooltip = options.beforeTooltip;
this.afterTooltip = options.afterTooltip;
this.tooltipWrapper = document.createElement('div');
this.status = false;
this.tooltip = function (elem) {
if (!elem.classList.contains('active')){
if (this.status) this.remElemActive();
if (this.beforeTooltip) this.beforeTooltip(elem);
elem.classList.add('active');
var coords = this.getCoords(elem);
this.tooltipWrapper.textContent = elem.dataset.tooltip;
this.tooltipWrapper.classList.add('active');
this.tooltipWrapper.style.top = coords.top - (this.tooltipWrapper.offsetHeight + this.offset) + 'px';
this.tooltipWrapper.style.left = (coords.left + coords.width / 2) - (this.tooltipWrapper.offsetWidth / 2) + 'px';
this.status = true;
if (this.status){
setTimeout(function () {
document.addEventListener('click', self.closeTipsBody, false);
}, 100)
}
if (this.afterTooltip) this.afterTooltip(elem)
}else {
elem.classList.remove('active');
}
};
this.closeTipsBody = function (e) {
if (self.tooltipWrapper === e.target || e.target.classList.contains('active')){
return false
}
self.closeTips();
};
this.closeTips = function () {
this.tooltipWrapper.classList.remove('active');
this.remElemActive();
this.status = false;
document.removeEventListener('click', self.closeTipsBody, false)
};
this.remElemActive = function () {
document.querySelector('.tooltip-js').classList.remove('active')
};
this.getCoords = function (elem) {
elem = elem.getBoundingClientRect();
return{
top: elem.top + window.pageYOffset,
left: elem.left + window.pageXOffset,
width: elem.width
}
};
this.init = function () {
document.addEventListener('DOMContentLoaded', function () {
this.tooltips = document.querySelectorAll('.tooltip-js');
this.tooltipWrapper.classList.add('tooltip-box');
document.querySelector('body').appendChild(this.tooltipWrapper);
for (var i = 0; i < this.tooltips.length; i++ ){
this.tooltips[i].addEventListener('click', function (e) {
e.preventDefault();
self.tooltip(this);
})
}
}.bind(this))
};
this.init();
}
window.Tooltip = Tooltip;
})();`
if you need any additional info, about what do i want to get to, text me.

Event Listener on images ignored within modal window

I'm stuck as to why I can't get an AddEventListener click event to work on a set of images that appear in a modal. I had them working before before the modal aspect was involve, but I'm not sure that the modal broke the image click event either.
Here is the function in question, which is called within a massive document.addEventListener("DOMContentLoaded", function (event) function:
var attachClick = function () {
Array.prototype.forEach.call(containers, function (n, i) {
n.addEventListener('click', function (e) {
// populate
cleanDrawer();
var mediaFilterSelected = document.querySelector('.media-tags .tag-container .selected');
var selectedFilters = "";
if (mediaFilterSelected != "" && mediaFilterSelected != null) {
selectedFilters = mediaFilterSelected.innerHTML;
}
var portfolioItemName = '';
var selectedID = this.getAttribute('data-portfolio-item-id');
var data = portfolioItems.filter(function (item) {
portfolioItemName = item.name;
return item.id === selectedID;
})[0];
clientNameContainer.innerHTML = data.name;
descriptionContainer.innerHTML = data.description;
var childItems = data.child_items;
//We will group the child items by media tag and target the unique instance from each group to get the right main banner
Array.prototype.groupBy = function (prop) {
return this.reduce(function (groups, item) {
var val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
var byTag = childItems.groupBy('media_tags');
if (childItems.length > 0) {
handleBannerItem(childItems[0]);
var byTagValues = Object.values(byTag);
byTagValues.forEach(function (tagValue) {
for (var t = 0; t < tagValue.length; t++) {
if (tagValue[t].media_tags == selectedFilters) {
handleBannerItem(tagValue[0]);
}
}
});
childItems.forEach(function (item, i) {
// console.log("childItems.forEach"); we get into here
var img = document.createElement('img'),
container = document.createElement('div'),
label = document.createElement('p');
container.appendChild(img);
var mediaTags = item.media_tags;
container.className = "thumb";
label.className = "childLabelInactive thumbLbl";
thumbsContainer.appendChild(container);
if (selectedFilters.length > 0 && mediaTags.length > 0) {
for (var x = 0; x < mediaTags.length; x++) {
if (mediaTags[x] == selectedFilters) {
container.className = "thumb active";
label.className = "childLabel thumbLbl";
}
}
}
else {
container.className = i == 0 ? "thumb active" : "thumb";
// console.log("no tags selected"); we get to here
}
img.src = item.thumb;
if (item.media_tags != 0 && item.media_tags != null) {
childMediaTags = item.media_tags;
childMediaTags.forEach(function (cMTag) {
varLabelTxt = document.createTextNode(cMTag);
container.appendChild(label);
label.appendChild(varLabelTxt);
});
}
//console.log("before adding click to images"); we get here
console.log(img.src);
img.addEventListener("click", function () {
console.log("thumbnail clicked"); //this is never reached
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
});
}
attachClick();
//open a modal to show off the portfolio pieces for the selected client
var tingleModal = document.querySelector('.tingle-modal');
drawer.className = 'drawer';
var portfolioModal = new tingle.modal({
onOpen: function() {
if(tingleModal){
tingleModal.remove();
}
console.log('modal open');
},
onClose: function() {
console.log('modal closed');
//tingleModal.remove();
}
});
e.preventDefault();
portfolioModal.open();
portfolioModal.setContent(document.querySelector('.drawer-content').innerHTML);
});
});
};
And the specific bit that I'm having trouble with:
console.log(img.src);
img.addEventListener("click", function () {
console.log("thumbnail clicked"); //this is never reached
resetThumbs();
handleBannerItem(item);
container.className = "thumb active";
});
I tried removing the e.PreventDefault() bit but that didn't solve the issue. I know the images are being created, so the img variable isn't empty. I feel like the addEventListener is setup correctly. I also tried moving that bit up just under the img.src = item.thumb line, but no luck. For Some reason, the click event just will not trigger for the images.
So if I understand correctly, you have a modal that lies above the images (it has a higher z-index)? Well in this case the clicks are not reaching the images as they will hit the modal. You can pass clicks through elements that lie above by applying the css property pointer-events: none; to the modal, but thats somehow controversial to what a modal is intended to do.
Are the images present in the modal on DOMContentLoaded? You may be able to try delegating the handling of clicks to a parent element if that's the case.
You can try the delegation approach shown here: Vanilla JavaScript Event Delegation

Refactoring repeated code in javascript prototype constructor

I have a open function that once triggered, simply plays video in a dedicated panel.
This function can be triggered in two ways - one with a click and another one with a page load (window load) with url that contains a valid anchor tag.
They all work fine but some codes of the window load handler are repetitive and I'm not too sure how I can keep this DRY.
Please take a look and point me in some directions on how I can write this better.
I commented in open function which is for which.
$.videoWatch.prototype = {
init: function() {
this.$openLinks = this.$element.find(".open");
this.$closeLinks = this.$element.find(".close");
this.open();
this.close();
},
_getContent: function(element) {
var $parent = element.parent(),
id = element.attr('href').substring(1),
title = $parent.data('title'),
desc = $parent.data('desc');
return {
title: title,
desc: desc,
id: id
}
},
open: function() {
var self = this;
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li"),
$theatreVideo = $(".playing"),
$theatreTitle = $(".theatre-title"),
$theatreText = $(".theatre-text");
$(".theatre").attr('id', content.id);
$theatreTitle.text(content.title);
$theatreText.text(content.desc);
if ($theatreText.text().length >= 90) {
$(".theatre-text").css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter($theatreText);
}
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
$a.parent().addClass("active");
$(".theatre").insertAfter($li);
$(".theatre").slideDown('fast', scrollToTheatre);
oldIndex = $li.index();
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
...
Simplified and refactored open method:
open: function() {
var self = this;
var serviceObj = {
theatreVideo : $(".playing"),
theatre: $(".theatre"),
theatreTitle : $(".theatre-title"),
theatreText : $(".theatre-text"),
setTheatreContent: function(content){
this.theatre.attr('id', content.id);
this.theatreTitle.text(content.title);
this.theatreText.text(content.desc);
if (this.theatreText.text().length >= 90) {
this.theatreText.css({
'overflow': 'hidden',
'max-height': '90px',
});
$moreButton.insertAfter(this.theatreText);
}
},
activateTeatre: function(a, li){
a.parent().addClass("active");
this.theatre.insertAfter(li);
this.theatre.slideDown('fast', scrollToTheatre);
oldIndex = li.index();
}
};
//open theatre with window load with #hash id
window.onload = function() {
var hash = location.hash;
var $a = $('a[href="' + hash + '"]'),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
serviceObj.activateTeatre($a, $li);
}
//open theatre with click event
self.$openLinks.on("click", function(e) {
// e.preventDefault();
if (curID == $(this).parent().attr("id")) {
$("figure").removeClass("active");
$("button.more").remove();
$(".theatre").slideUp('fast');
$('.playing').attr("src", "");
removeHash();
oldIndex = -1;
curID = "";
return false
} else {
curID = $(this).parent().attr("id");
}
var $a = $(this),
content = self._getContent($a),
$li = $a.parents("li");
serviceObj.setTheatreContent(content);
if (!($li.index() == oldIndex)) {
$("figure").removeClass("active");
$(".theatre").hide(function(){
serviceObj.activateTeatre($a, $li);
});
} else {
$(".theatre").insertAfter($li);
scrollToTheatre();
$("figure").removeClass("active");
$a.parent().addClass("active");
}
});
},
1st of all there are variables that don't depend on the input, you could pull them to the class (I'll show just one example, as you asked for directions):
init: function() {
this.$theatreVideo = $(".playing");
All the variables that do depend on the input, like $li could be moved to a function:
var $a = $(this),
$dependsOnA = self.dependsOnA($a);
self.actionDependsOnA($dependsOnA); // see below
function dependsOnA($a) {
return {
a: $a,
li: $a.parents("li"),
content: self._getContent($a)
}
}
Also the code that "repeats" can be moved to a function:
function actionDependsOnA($dependsOnA)
$(".theatre").attr('id', $dependsOnA.content.id);
$theatreTitle.text($dependsOnA.content.title);
$theatreText.text($dependsOnA.content.desc);
}

How can I make window.showmodaldialog work in chrome 37?

We have a huge web application where we use window.showmodaldialog for alerts, confirmations and popups. Since Chrome version 37 this call has been disabled.
Is there any quick workaround to make window.showmodaldialog work in the latest version of Chrome?
I am adding here a workaround for window.showmodaldialog, although this is not a perfect workaround because this will not break the code execution as showmodaldialog was doing, instead this will open the popups.
window.showModalDialog = function (url, arg, feature) {
var opFeature = feature.split(";");
var featuresArray = new Array()
if (document.all) {
for (var i = 0; i < opFeature.length - 1; i++) {
var f = opFeature[i].split("=");
featuresArray[f[0]] = f[1];
}
}
else {
for (var i = 0; i < opFeature.length - 1; i++) {
var f = opFeature[i].split(":");
featuresArray[f[0].toString().trim().toLowerCase()] = f[1].toString().trim();
}
}
var h = "200px", w = "400px", l = "100px", t = "100px", r = "yes", c = "yes", s = "no";
if (featuresArray["dialogheight"]) h = featuresArray["dialogheight"];
if (featuresArray["dialogwidth"]) w = featuresArray["dialogwidth"];
if (featuresArray["dialogleft"]) l = featuresArray["dialogleft"];
if (featuresArray["dialogtop"]) t = featuresArray["dialogtop"];
if (featuresArray["resizable"]) r = featuresArray["resizable"];
if (featuresArray["center"]) c = featuresArray["center"];
if (featuresArray["status"]) s = featuresArray["status"];
var modelFeature = "height = " + h + ",width = " + w + ",left=" + l + ",top=" + t + ",model=yes,alwaysRaised=yes" + ",resizable= " + r + ",celter=" + c + ",status=" + s;
var model = window.open(url, "", modelFeature, null);
model.dialogArguments = arg;
}
Just put this code in the head section of page.
I put the following javascript in the page header and it seems to work. It detects when the browser does not support showModalDialog and attaches a custom method that uses window.open, parses the dialog specs (height, width, scroll, etc.), centers on opener and sets focus back to the window (if focus is lost). Also, it uses the URL as the window name so that a new window is not opened each time. If you are passing window args to the modal you will need to write some additional code to fix that. The popup is not modal but at least you don't have to change a lot of code. Might need some work for your circumstances.
<script type="text/javascript">
// fix for deprecated method in Chrome 37
if (!window.showModalDialog) {
window.showModalDialog = function (arg1, arg2, arg3) {
var w;
var h;
var resizable = "no";
var scroll = "no";
var status = "no";
// get the modal specs
var mdattrs = arg3.split(";");
for (i = 0; i < mdattrs.length; i++) {
var mdattr = mdattrs[i].split(":");
var n = mdattr[0];
var v = mdattr[1];
if (n) { n = n.trim().toLowerCase(); }
if (v) { v = v.trim().toLowerCase(); }
if (n == "dialogheight") {
h = v.replace("px", "");
} else if (n == "dialogwidth") {
w = v.replace("px", "");
} else if (n == "resizable") {
resizable = v;
} else if (n == "scroll") {
scroll = v;
} else if (n == "status") {
status = v;
}
}
var left = window.screenX + (window.outerWidth / 2) - (w / 2);
var top = window.screenY + (window.outerHeight / 2) - (h / 2);
var targetWin = window.open(arg1, arg1, 'toolbar=no, location=no, directories=no, status=' + status + ', menubar=no, scrollbars=' + scroll + ', resizable=' + resizable + ', copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
targetWin.focus();
};
}
</script>
From http://codecorner.galanter.net/2014/09/02/reenable-showmodaldialog-in-chrome/
It's deprecated by design. You can re-enable showModalDialog support, but only temporarily – until May of 2015. Use this time to create alternative solutions.
Here’s how to do it in Chrome for Windows. Open Registry Editor (regedit) and create following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\EnableDeprecatedWebPlatformFeatures
Under the EnableDeprecatedWebPlatformFeatures key create a string value with name 1 and value of ShowModalDialog_EffectiveUntil20150430. To verify that the policy is enabled, visit chrome://policy URL.
UPDATE: If the above didn’t work for you here’s another method to try.
Download Chrome ADM templates from http://www.chromium.org/administrators/policy-templates
Extract and import policy relevant to your locale (e.g. windows\adm\en-US\chrome.adm. You can import either via gpedit.mscor using these utilities on Home editions of windows: http://blogs.technet.com/b/fdcc/archive/2008/05/07/lgpo-utilities.aspx)
Under “Adminstrative Templates” locate Google Chrome template and enable “Enable Deprecated Web Platform Feautes”.
Open the feature and add “ShowModalDialog_EffectiveUntil20150430″ key.
A very good, and working, javascript solution is provided here :
https://github.com/niutech/showModalDialog
I personnally used it, works like before for other browser and it creates a new dialog for chrome browser.
Here is an example on how to use it :
function handleReturnValue(returnValue) {
if (returnValue !== undefined) {
// do what you want
}
}
var myCallback = function (returnValue) { // callback for chrome usage
handleReturnValue(returnValue);
};
var returnValue = window.showModalDialog('someUrl', 'someDialogTitle', 'someDialogParams', myCallback);
handleReturnValue(returnValue); // for other browsers except Chrome
This article (Why is window.showModalDialog deprecated? What to use instead?) seems to suggest that showModalDialog has been deprecated.
The window.returnValue property does not work directly when you are opening a window using window.open() while it does work when you are using window.showModalDialog()
So in your case you have two options to achieve what you are trying to do.
Option 1 - Using window.showModalDialog()
In your parent page
var answer = window.showModalDialog(<your page and other arguments>)
if (answer == 1)
{ do some thing with answer }
and inside your child page you can make use of the window.returnValue directly like
window.returnValue = 'value that you want to return';
showModalDialog halts the executions of the JavaScript until the dialog box is closed and can get a return value from the opened dialog box when its closing.But the problem with showModalDialog is that it is not supported on many modern browsers. In contrast window.open just opens a window asynchronously (User can access both the parent window and the opened window). And the JavaScript execution will continue immediately. Which bring us to Option 2
Option 2 - Using window.open()
In your parent page write a function that deals with opening of your dialog.
function openDialog(url, width, height, callback){
if(window.showModalDialog){
options = 'dialogHeight: '+ height + '; dialogWidth: '+ width + '; scroll=no'
var returnValue = window.showModalDialog(url,this,options);
callback(returnValue)
}
else {
options ='toolbar=no, directories=no, location=no, status=yes, menubar=no, resizable=yes, scrollbars=no, width=' + width + ', height=' + height;
var childWindow = window.open(url,"",options);
$(childWindow).on('unload',function(){
if (childWindow.isOpened == null) {
childWindow.isOpened = 1;
}
else {
if(callback){
callback(childWindow.returnValue);
}
}
});
}
}
And whenever you want to use open a dialog. Write a callback that deals with the return value and pass it as a parameter to openDialog function
function callback(returnValue){
if(returnValue){
do something nice with the returnValue
}}
And when calling the function
openDialog(<your page>, 'width px', 'height px', callbak);
Check out an article on how to replace window.showModalDialog with window.open
I wouldn't try to temporarily enable a deprecated feature. According to the MDN documentation for showModalDialog, there's already a polyfill available on Github.
I just used that to add windows.showModalDialog to a legacy enterprise application as a userscript, but you can obviously also add it in the head of the HTML if you have access to the source.
I use a polyfill that seem to do a good job.
https://github.com/niutech/showModalDialog
http://niutech.github.io/showModalDialog/demo.html
Create a cross browser ModalDialog
function _showModalDialog(url, width, height, closeCallback) {
var modalDiv,
dialogPrefix = window.showModalDialog ? 'dialog' : '',
unit = 'px',
maximized = width === true || height === true,
w = width || 600,
h = height || 500,
border = 5,
taskbar = 40, // windows taskbar
header = 20,
x,
y;
if (maximized) {
x = 0;
y = 0;
w = screen.width;
h = screen.height;
} else {
x = window.screenX + (screen.width / 2) - (w / 2) - (border * 2);
y = window.screenY + (screen.height / 2) - (h / 2) - taskbar - border;
}
var features = [
'toolbar=no',
'location=no',
'directories=no',
'status=no',
'menubar=no',
'scrollbars=no',
'resizable=no',
'copyhistory=no',
'center=yes',
dialogPrefix + 'width=' + w + unit,
dialogPrefix + 'height=' + h + unit,
dialogPrefix + 'top=' + y + unit,
dialogPrefix + 'left=' + x + unit
],
showModal = function (context) {
if (context) {
modalDiv = context.document.createElement('div');
modalDiv.style.cssText = 'top:0;right:0;bottom:0;left:0;position:absolute;z-index:50000;';
modalDiv.onclick = function () {
if (context.focus) {
context.focus();
}
return false;
}
window.top.document.body.appendChild(modalDiv);
}
},
removeModal = function () {
if (modalDiv) {
modalDiv.onclick = null;
modalDiv.parentNode.removeChild(modalDiv);
modalDiv = null;
}
};
// IE
if (window.showModalDialog) {
window.showModalDialog(url, null, features.join(';') + ';');
if (closeCallback) {
closeCallback();
}
// Other browsers
} else {
var win = window.open(url, '', features.join(','));
if (maximized) {
win.moveTo(0, 0);
}
// When charging the window.
var onLoadFn = function () {
showModal(this);
},
// When you close the window.
unLoadFn = function () {
window.clearInterval(interval);
if (closeCallback) {
closeCallback();
}
removeModal();
},
// When you refresh the context that caught the window.
beforeUnloadAndCloseFn = function () {
try {
unLoadFn();
}
finally {
win.close();
}
};
if (win) {
// Create a task to check if the window was closed.
var interval = window.setInterval(function () {
try {
if (win == null || win.closed) {
unLoadFn();
}
} catch (e) { }
}, 500);
if (win.addEventListener) {
win.addEventListener('load', onLoadFn, false);
} else {
win.attachEvent('load', onLoadFn);
}
window.addEventListener('beforeunload', beforeUnloadAndCloseFn, false);
}
}
}
(function() {
window.spawn = window.spawn || function(gen) {
function continuer(verb, arg) {
var result;
try {
result = generator[verb](arg);
} catch (err) {
return Promise.reject(err);
}
if (result.done) {
return result.value;
} else {
return Promise.resolve(result.value).then(onFulfilled, onRejected);
}
}
var generator = gen();
var onFulfilled = continuer.bind(continuer, 'next');
var onRejected = continuer.bind(continuer, 'throw');
return onFulfilled();
};
window.showModalDialog = window.showModalDialog || function(url, arg, opt) {
url = url || ''; //URL of a dialog
arg = arg || null; //arguments to a dialog
opt = opt || 'dialogWidth:300px;dialogHeight:200px'; //options: dialogTop;dialogLeft;dialogWidth;dialogHeight or CSS styles
var caller = showModalDialog.caller.toString();
var dialog = document.body.appendChild(document.createElement('dialog'));
dialog.setAttribute('style', opt.replace(/dialog/gi, ''));
dialog.innerHTML = '×<iframe id="dialog-body" src="' + url + '" style="border: 0; width: 100%; height: 100%;"></iframe>';
document.getElementById('dialog-body').contentWindow.dialogArguments = arg;
document.getElementById('dialog-close').addEventListener('click', function(e) {
e.preventDefault();
dialog.close();
});
dialog.showModal();
//if using yield
if(caller.indexOf('yield') >= 0) {
return new Promise(function(resolve, reject) {
dialog.addEventListener('close', function() {
var returnValue = document.getElementById('dialog-body').contentWindow.returnValue;
document.body.removeChild(dialog);
resolve(returnValue);
});
});
}
//if using eval
var isNext = false;
var nextStmts = caller.split('\n').filter(function(stmt) {
if(isNext || stmt.indexOf('showModalDialog(') >= 0)
return isNext = true;
return false;
});
dialog.addEventListener('close', function() {
var returnValue = document.getElementById('dialog-body').contentWindow.returnValue;
document.body.removeChild(dialog);
nextStmts[0] = nextStmts[0].replace(/(window\.)?showModalDialog\(.*\)/g, JSON.stringify(returnValue));
eval('{\n' + nextStmts.join('\n'));
});
throw 'Execution stopped until showModalDialog is closed';
};
})()
;
**Explanation:
------------**
The best way to deal with showModalDialog for older application conversions is use to `https://github.com/niutech/showModalDialog` inorder to work with show modal dialogs and if modal dailog has ajax calls you need to create object and set the parameters of function to object and pass below...before that check for browser and set the useragent...example: agentStr = navigator.userAgent; and then check for chrome
var objAcceptReject={}; // create empty object and set the parameters to object and send to the other functions as dialog when opened in chrome breaks the functionality
function rejectClick(index, transferId) {
objAcceptReject.index=index;
objAcceptReject.transferId=transferId;
agentStr = navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0) // If Internet Explorer, return version number
{
var ret = window.showModalDialog("/abc.jsp?accept=false",window,"dialogHeight:175px;dialogWidth:475px;scroll:no;status:no;help:no");
if (ret=="true") {
doSomeClick(index);
}
} else if ((agentStr.indexOf("Chrome")) >- 1){
spawn(function() {
var ret = window.showModalDialog("/abcd.jsp?accept=false",window,"dialogHeight:175px;dialogWidth:475px;scroll:no;status:no;help:no");
if (ret=="true") {// create an object and store values in objects and send as parameters
doSomeClick(objAcceptReject.index);
}
});
}
else {
var ret = window.showModalDialog("/xtz.jsp?accept=false",window,"dialogHeight:175px;dialogWidth:475px;scroll:no;status:no;help:no");
if (ret=="true") {
doSomeClick(index);
}
}
The window.showModalDialog is deprecated (Intent to Remove:
window.showModalDialog(), Removing showModalDialog from the Web
platform). [...]The latest plan is to land the showModalDialog removal
in Chromium 37. This means the feature will be gone in Opera 24 and
Chrome 37, both of which should be released in September.[...]
Yes, It's deprecated. Spent yesterday rewriting code to use Window.open and PostMessage instead.

Can two bookmarklets and a Greasemonkey script be combined into one bookmarklet? If so, how?

If this question is totally unsuitable, please forgive me. I don't know anything about programming. I should learn Javascript, I know, but it is a bit difficult for a total layman.
I have two bookmarklets and one userscript that, together, do what I need; but I need to click, wait, and click. Could they all be combined into a single bookmarklet? This is for Firefox 5, on Windows XP.
The first bookmarklet takes all links on a page that point to images and displays all these images in a single page in a new tab:
javascript:(function(){function%20I(u){var%20t=u.split('.'),e=t[t.length-1].toLowerCase();return%20{gif:1,jpg:1,jpeg:1,png:1,mng:1}[e]}function%20hE(s){return%20s.replace(/&/g,'&').replace(/>/g,'>').replace(/</g,'<').replace(/"/g,'"');}var%20q,h,i,z=open().document;z.write('<p>Images%20linked%20to%20by%20'+hE(location.href)+':</p><hr>');for(i=0;q=document.links[i];++i){h=q.href;if(h&&I(h))z.write('<p>'+q.innerHTML+'%20('+hE(h)+')<br><img%20src="'+hE(h)+'">');}z.close();})()
Then the userscript kicks in, which changes the title of the page to include [Page loaded]:
// ==UserScript==
// #name Add "loaded" to title if page is loaded
// #namespace my
// #description Indicate if a page is loaded
// #include *
// ==/UserScript==
window.addEventListener(
'load',
function (e) {
document.title += " - [Page loaded]";
},
false);
Lastly, I click the second bookmarklet, which removes all text and all images smaller than a certain size from the page, and gives it a black background. It'd like this part to kick in only after all images have been loaded (hence the "loaded" title from the userscript).
I have to put this in in-line code, because the other methods seemed to fail (neither the code button nor blockquote did anything). It would be awesome if someone could help me out! I couldn't write a single line of Javascript myself and have no idea what to do.
function wrap(image, href) {
var img = document.createElement('img');
var div = document.createElement('div');
img.src = image.src;
var node = image.parentNode;
if (!href) {
div.appendChild(img);
} else {
var a = document.createElement('a');
a.href = href;
a.appendChild(img);
div.appendChild(a);
}
return div;
}
function findNext(document) {
var res = document.evaluate('//a[#rel='
next ']', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (res.singleNodeValue) {
return res.singleNodeValue.href;
} else {
return null;
}
}
if ('scrollMaxY' in window) {
function getScrollMaxY() {
return window.scrollMaxY;
}
} else {
function getScrollMaxY() {
return document.body.scrollHeight - window.innerHeight;
}
}
function streamify() {
var contentDiv = document.createElement('div');
var imageDiv = document.createElement('div');
var moreButton = document.createElement('input');
var style = document.createElement('style');
var iframe = document.createElement('iframe');
var errorSpan = document.createElement('span');
var retryButton = document.createElement('input');
var currentPageDiv = document.createElement('div');
var currentPageLink = document.createElement('a');
var nextUrl = findNext(document);
var occured = {};
var images = [];
var loadTimer = null;
var scrolledToBottom = false;
function extract(elem, href, images) {
switch (elem.localName) {
case 'a':
href = elem.href;
break;
case 'img':
if (!(elem.src in occured) && elem.offsetWidth > 250 && elem.offsetHeight > 300) {
images.push(wrap(elem));
occured[elem.src] = true;
}
}
var child = elem.firstElementChild;
while (child) {
extract(child, href, images);
child = child.nextElementSibling;
}
}
function loadNext() {
if (loadTimer !== null) {
window.clearTimeout(loadTimer);
}
if (nextUrl) {
loadTimer = window.setTimeout(function () {
errorSpan.style.display = '';
loadTimer = null;
}, 30000);
iframe.src = nextUrl;
}
}
style.type = 'text/css';
style.appendChild(document.createTextNode('body {background-color: black;color: white;}a {color: white;font-weight: bold;text-decoration: none;}a:hover {text-decoration: underline;}#greasemonkey-image-stream-content {text-align: center;}#greasemonkey-image-stream-content > div > div {margin-top: 2em;margin-bottom: 2em;}#greasemonkey-image-stream-content input {padding: 0.5em;font-weight: bold;}'));
contentDiv.id = 'greasemonkey-image-stream-content';
currentPageLink.appendChild(document.createTextNode('current page'));
currentPageLink.href = window.location.href;
currentPageDiv.appendChild(currentPageLink);
moreButton.type = 'button';
moreButton.value = 'More';
moreButton.disabled = true;
function handleMore() {
currentPageLink.href = iframe.src;
scrolledToBottom = false;
errorSpan.style.display = 'none';
moreButton.disabled = true;
for (var i = 0; i < images.length; ++i) {
imageDiv.appendChild(images[i]);
}
images = [];
loadNext();
}
moreButton.addEventListener('click', handleMore, false);
retryButton.type = 'button';
retryButton.value = 'Retry';
retryButton.addEventListener('click', function (event) {
loadNext();
errorSpan.style.display = 'none';
}, false);
errorSpan.style.fontWeight = 'bold';
errorSpan.style.color = 'red';
errorSpan.style.display = 'none';
errorSpan.appendChild(document.createTextNode(' Load Error '));
errorSpan.appendChild(retryButton);
iframe.style.width = '0px';
iframe.style.height = '0px';
iframe.style.visibility = 'hidden';
iframe.addEventListener('load', function (event) {
if (loadTimer !== null) {
window.clearTimeout(loadTimer);
}
errorSpan.style.display = 'none';
nextUrl = findNext(iframe.contentDocument);
extract(iframe.contentDocument.body, null, images);
if (images.length == 0 && nextUrl) {
loadNext();
moreButton.disabled = true;
} else {
moreButton.disabled = !nextUrl && images.length == 0;
if (scrolledToBottom && (nextUrl || images.length > 0)) {
handleMore();
}
}
}, false);
extract(document.body, null, images);
for (var i = 0; i < images.length; ++i) {
imageDiv.appendChild(images[i]);
}
images = [];
contentDiv.appendChild(style);
contentDiv.appendChild(currentPageDiv);
contentDiv.appendChild(imageDiv);
contentDiv.appendChild(moreButton);
contentDiv.appendChild(errorSpan);
contentDiv.appendChild(iframe);
var elem = document.documentElement.firstElementChild;
while (elem) {
switch (elem.localName) {
case 'head':
var child = elem.firstElementChild;
while (child) {
var next = child.nextElementSibling;
if (child.localName != 'title') {
elem.removeChild(child);
}
child = next;
}
break;
case 'body':
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
}
elem = elem.nextElementSibling;
}
window.addEventListener('scroll', function (event) {
if (window.scrollY >= getScrollMaxY()) {
scrolledToBottom = true;
moreButton.click();
}
}, false);
document.body.appendChild(contentDiv);
loadNext();
}
streamify();
void(0)
(function(){
var a=Array.filter(document.getElementsByTagName('a'),function(e){
var h=e.href.split('.').pop().toLowerCase();
return {gif:1,jpg:1,jpeg:1,png:1,mng:1}[h];
}),b=document.getElementsByTagName('body')[0],i=0,l=a.length;
b.innerHTML='';
b.style.background='#000';
b.style.color='#ddd'
for(i;i<l;i++){
var t=a[i].href,p=document.createElement('img'),s=document.createElement('div');
s.innerHTML=t;
p.src=t;
b.appendChild(p);
b.appendChild(s);
}
})()
Here it is compressed
javascript:(function(){var c=Array.filter(document.getElementsByTagName("a"),function(a){return{gif:1,jpg:1,jpeg:1,png:1,mng:1}[a.href.split(".").pop().toLowerCase()]}),a=document.getElementsByTagName("body")[0],b=0,g=c.length;a.innerHTML="";a.style.background="#000";a.style.color="#ddd";for(b;b<g;b++){var d=c[b].href,e=document.createElement("img"),f=document.createElement("div");f.innerHTML=d;e.src=d;a.appendChild(e);a.appendChild(f)}})();
One that waits for each image to load. Added error detection.
(function(){
var a=Array.filter(document.getElementsByTagName('a'),function(e){
return {gif:1,jpg:1,jpeg:1,png:1,mng:1}[e.href.split('.').pop().toLowerCase()];
}),b=document.getElementsByTagName('body')[0],i=0,l=a.length;
b.innerHTML='';
b.style.background='#000';
b.style.color='#ddd'
add(0);
function add(i){
var img=new Image(),t=a[i].href,p=document.createElement('img'),s=document.createElement('div');
img.src=t;
img.onload=function(){
s.innerHTML=t;
p.src=t;
b.appendChild(p);
b.appendChild(s);
++i<a.length?add(i):'';
};
img.onerror=function(){
++i<a.length?add(i):'';
};
}
})()
And the minified version.
javascript:(function(){function d(b){var e=new Image,c=f[b].href,g=document.createElement("img"),h=document.createElement("div");e.src=c;e.onerror=function(){++b<f.length&&d(b)};e.onload=function(){h.innerHTML=c;g.src=c;a.appendChild(g);a.appendChild(h);++b<f.length&&d(b)}}var f=Array.filter(document.getElementsByTagName("a"),function(a){return{gif:1,jpg:1,jpeg:1,png:1,mng:1}[a.href.split(".").pop().toLowerCase()]}),a=document.getElementsByTagName("body")[0];a.innerHTML="";a.style.background="#000";a.style.color="#ddd";d(0)})();
Here is some test HTML
<a href='http://mozcom-cdn.mozilla.net/img/covehead/about/logo/download/logo-only-preview.png'>Firefox</a>
<a href='http://ie.microsoft.com/testdrive/Graphics/IEBeatz/assets/ie-logo-small.png'>IE</a>
<a href='http://code.google.com/tv/images/chrome-logo.png'>Chrome</a>
I did not add limiter on size of images because I was not sure if it was necessary and I wasn't sure what size limit you wanted.

Categories