showModalDialog alternative? - javascript

I'm managing an old site that's riddled with popup windows. They're quite annoying because they keep getting lost behind the main window. I'm slowly moving them over to over to a modern 'lightbox' but it's a slow and tedious process because all these popups contain forms and the validation is done server-side, which means I need to be able to submit the form and then re-render it if there's an error without breaking the whole page.
I just discovered there's a window.showDialogBox which works perfectly in Firefox (prevents you from clicking the main page until you close the dialog), but Chrome has already deprecated it, and IE only half supports it.
So, is there anything I can replace window.open with in the mean time to provide a better user experience, without re-writing every form to send and receive JSON via XHR?

You can use my showModalDialog polyfill using the brand new modal <dialog> element, which works in the latest Google Chrome. A <dialog> polyfill for older browsers is here.

You can use different codes for different browsers, like this:
if(navigator.userAgent.indexOf("MSIE") != -1){ //If the browser is IE
//Code for IE
}
else if(navigator.vendor == "Firefox"){ //If the browser is Firefox
//Code for Firefox
}
else if(navigator.vendor == "Google Inc."){ //If the browser is Chrome
//Code for Chrome
}
For IE, showModalDialog works just fine and it prevents you from clicking the main page until you close the dialog.
For Firefox, you can use, as you said, showDialogBox.
For Chrome, you can use the thing that niutech suggests.
Otherwise, if you use window.open, all the popup windows will be in the task bar so if they are hidden behind the window, just click on them in the task bar to make them visible.

here's my code:
/**
* May 2015: showModalDialog will not be supported any longer, so, if not available, we need to make a pure
* window.open and a catch which callbacks.
*
* In contradiction to other solutions, this "emulator" is capable of loading
* cross-origin urls such as oAuth2 redirect cascades, which can not be put in to iframes or dialogs due to
* their CSSP settings!
*
* Flow control of the caller needs to take care whether a window is returned or false
*
* #constructor showModalDialogHandler(callback) - callback is called, if window is closed.
*
*/
var showModalDialogHandler = function(callback)
{
this.modalDialogEmulator = null;
this.callBack = callback;
this.returnImmediately = false;
this.modalDialog = false;
this.maxRuns = 180;
this.intervall = 750;
this.force = false; // if set to true, emulate always.
this.chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
/**
* make the call, open a dialog, load etc.
*
* #param url - URL to load
* #param arg - args to pass to the window
* #param feature - featurelist as of window.open
* #return - erturns a window object (if modal dialogs are supported) or false otherwise
*
*/
this.callModalDialog = function(url, arg, feature) {
var self = this;
if ( !this.force && window.showModalDialog )
this.modalDialog = window.showModalDialog(url, arg, feature );
else
{
this.modalDialog = this.modalDialogEmulator(url, arg, feature );
window.setTimeout(function () {
self.modalDialog.focus();
}, 20);
/*
* Catch lose focus on main window. Modal dialog should at least
* stay in front of the opener. If the opener gets focus,
* window is either shuffled up or closed and reopend (chrome).
*
*/
jQuery(window).bind("focus", function() {
//console.log("opener focus");
if ( self.chrome )
{
// brute force: close and reopen, hope it will cope with that !!!
if( !self.modalDialog.closed )
{
self.modalDialog.close();
self.modalDialog = self.modalDialogEmulator(url, arg, feature );
}
}
else
{
if( !self.modalDialog.closed )
{
window.setTimeout(function () {
self.modalDialog.blur();
self.modalDialog.focus();
}, 30);
}
else
{
jQuery(window).unbind("focus"); // remove that listener, cpu-sucker.
}
}
});
}
if ( this.returnImmediately )
{
var runs = this.maxRuns;
var loop = setInterval(function() {
if(self.modalDialog.closed)
{
//console.log("close catched, callback:");
clearInterval(loop);
self.callBack();
}
if ( runs-- <= 0 )
clearInterval(loop); // infinitystopper
}, this.intervall );
return false;
}
else
return this.modalDialog;
};
/*
* showModalDialog is not longer supported, emulate with popup and
* a catcher with returnImmediately
*/
if ( this.force || !window.showModalDialog)
{
var self = this;
this.modalDialogEmulator = function(url, arg, feature) {
// console.log("window.ShowModalDialog not supported");
self.returnImmediately = true;
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 + ",center=" + c
+ ",dependent=yes,dialog=yes,modal=yes,close=0"
+ ",status=" + s;
var model = window.open(url, "modal", modelFeature, null);
return model;
};
}
}
needs jQuery, at least.

you can check this link for jQuery Modal, to use this code, you need to include jquery-ui javascript and css files

Related

No published solution seems to fix "Uncaught Error: Extension context invalidated. " Chrome extension manifest v3 [duplicate]

This question already has answers here:
Chrome extension content script re-injection after upgrade or install
(6 answers)
Chrome extension: How to remove orphaned script after chrom extension update
(2 answers)
Closed 4 months ago.
I've been building my first Chrome extension. It has been fun however I've run into a problem I've yet to solve.
I get the error in the devtools extentions Developer mode:
Uncaught Error: Extension context invalidated.
I pretty sure that upon update of my extension and hard refresh on my test https:// page that the contentScript.js gets injected multiple times. The older injected scripts are still trying to the dom injections but the ports are not open so it throws the error?
I have tried the solutions in both of these threads as well going through google groups:
Recursive "Extension context invalidated" error in console
Extension context invalidated. Chrome Extension
I am using manifest v3.
Can you please suggest a way that I can update my code to protect against this error?
Here is my manifest:
{
"name": "Focuser",
"description": "Focuses on a page during a specified time frame",
"version": "0.1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": [
"storage",
"scripting",
"alarms"
],
"host_permissions": [
"<all_urls>"
]
}
My background script:
try {
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if ('undefined' !== typeof tab.url) {
// skip urls like "chrome://" to avoid extension error
if (tab.url?.startsWith("chrome://")) return undefined;
if(changeInfo.status == 'complete') {
chrome.scripting.executeScript({
files: ['contentScript.js'],
target: {tabId: tab.id}
})
}
}
})
} catch(e) {
console.log(e)
}
My conentScript (with classes removed)
/**
* Foozle Focuser - a class that injects a temporary DOM element
* into the site and then focus and click on it.
*
* The idea is that by maintaining the focus while running in the background a
* Chrome tab can stream radio stations and other media content. This could be used
* for anything a user wants to click.
*/
class FoozleFocuser {
/**
* private {string} target
* the dom element used as the target for the inject DOM
*/
#target = null;
/**
* private {string} injectElement
* the DOM element used as the target for the injected DOM
*/
#injectElement = '';
/**
* private {string} injectElementClassName
* the CSS class to be added to the injected DOM element
*/
#injectElementClassName = '';
/**
* Constructor - set the target and injectElementClass - optionally no params passed
* will set a target as document.body and the injectClassName will be foozle-focuser
* #param {string} target - the passed target DOM element that will be used as the target for the injected DOM
* #param {string} injectElementClassName - the CSS class to be added to the injected DOM element
* #return Void
*/
constructor(target=null, injectElementClassName = 'foozle-focuser') {
this.#target = this.#getTarget(target);
this.#injectElementClassName = injectElementClassName;
}
/**
* private SetInjectedElement
* Creates the injected DOM element with a class that will be used as a target for the focus
* #param {string} domElement
* #return Void
*/
#setInjectedElement(domElement = 'div') {
this.#injectElement = document.createElement(domElement);
this.#injectElement.className = this.#injectElementClassName;
}
/**
* private getTarget - queries the passed dom string. If null set the document.body as target
* #param {string || null} target - The dom target element where the injection will be done
* #return string - the target
*/
#getTarget(target=null) {
if ( target == null ) {
target = document.body;
} else {
target = document.querySelector(target);
if ( target == null || 'undefined' == typeof target ) {
target = document.body;
}
}
return target;
}
/**
* private focus - appends, focuses on, and clicks the injected DOM Element
* #return Void
*/
#focus() {
if (this.#target) {
this.#target.appendChild(this.#injectElement);
this.#target.focus();
this.#target.click();
let newDiv = document.querySelector('.' + this.#injectElementClassName)
newDiv.parentNode.removeChild(newDiv);
}
}
/**
* private run - runs the setup for the target and injected element and then focuses on the target
* #return Void
*/
run() {
this.#setInjectedElement();
this.#focus();
}
}
class FoozleTypes {
typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (Object.prototype.toString.call(value) == '[object Array]') {
s = 'array';
}
} else {
s = 'null';
}
}
return s;
}
checkTypes(argList, typeList) {
for (var i = 0; i < typeList.length; i++) {
if (typeOf(argList[i]) !== typeList[i]) {
throw 'wrong type: expecting ' + typeList[i] + ", found " + typeOf(argList[i]);
}
}
}
}
class FoozleCounter {
getStoredCount(key='focuserCount') {
this.item = localStorage.getItem(key);
if ( null == this.item || 'undefined' == this.item ) {
localStorage.setItem(key, 0);
}
this.item = parseInt(this.item)
let count = this.item;
count++;
localStorage.setItem(key, count);
return count;
}
}
let FC = new FoozleCounter();
let FF = new FoozleFocuser();
if ('undefined' == typeof intervalId) {
var intervalId = setInterval(() => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(intervalId);
return;
}
FF.run();
// Get the updated count
let count = FC.getStoredCount();
// Store and report the count
// #TODO - change the console log to the popup page
chrome.storage.local.set({key: count}, function() {
console.log('Count is set to ' + count);
});
}, 45000);
}
if('undefined' == typeof init ) {
var init = () => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(init);
return;
}
FF.run();
console.log('count', FC.getStoredCount())
}
init();
}
When the extension is auto-updated or reloaded on chrome://extensions page, its old content scripts are "orphaned" and can't use the chrome API anymore.
A universal solution is to re-inject the new content script in the above scenarios and send a DOM message to the orphaned content script so it can unregister its listeners and timers.
In your case, judging by the posted code, there's only setInterval, so the solution is simple:
var intervalId = setInterval(() => {
if (!chrome.runtime?.id) {
// The extension was reloaded and this script is orphaned
clearInterval(intervalId);
return;
}
//....................
//....................
//....................
}, 45000);
And of course you can re-inject the new content script if necessary.

Complex Javascript for performing a basic job

I came across a website that was using a very strange piece of code with a lot of variables and recursive functions just to forward the user to the main website. The code was obfuscated. After deobfuscation, it is as follows. Note that the go() function is executed upon click of a button named 'Enter Site':
(function (paetynn, jaquez) {
var lyons = quetzali, payzli = paetynn();
while (!![]) {
try {
var kyona = parseInt(lyons(295)) / 1 + -parseInt(lyons(300)) / 2 + parseInt(lyons(299)) / 3 + -parseInt(lyons(301)) / 4 * (parseInt(lyons(304)) / 5) + -parseInt(lyons(294)) / 6 * (parseInt(lyons(298)) / 7) + parseInt(lyons(297)) / 8 * (-parseInt(lyons(303)) / 9) + parseInt(lyons(305)) / 10;
if (kyona === jaquez) break; else payzli.push(payzli.shift());
} catch (zulekha) {
payzli.push(payzli.shift());
}
}
}(niree, 850584));
function quetzali(winston, ikeshia) {
var hongan = niree();
return quetzali = function (khole, kysin) {
khole = khole - 294;
var zebulan = hongan[khole];
return zebulan;
}, quetzali(winston, ikeshia);
}
function go() {
var amey = quetzali, gracelee = amey(296);
document[amey(302)] = gracelee, window.location = "/";
}
function niree() {
var saana = ["604264sauqJi", "10214183nDqKAH", "2078325AmAiPo", "1206860TDYYcJ", "4VhIfuJ", "cookie", "45pazGrL", "380390DQkmbn", "12476230senONL", "6bRFHSG", "1426528LpTiXE", "session_keys=mycheck;"];
niree = function () {
return saana;
};
return niree();
}
I don't fully understand what the code does. Could some JS expert clarify on the piece?
Seems like the code is manipulating window.location.
Also it was used inside a script tag inside the head tag of the page.
This code sets cookie session_keys=mycheck; and then redirects to /. The rest of code make permutation in the array of strings saana so analizyng code would be more difficult.

Getting Compile error in Microsoft JScript (expected)

I tested a code with my friend and the code worked and now I wanted to test this again and got a Compile error in Microsoft JScript
Everything worked before
var iTest = 0;
if (iTest) {
let sText = "This is a template string which can contain variables like ${iTest}";
console.log(sText);
} else if (!iTest) {
let fnc = (iRadius, iPi = 3.14) => {
console.log("The area of the circle with the radius ${iRadius}cm is ${Math.round(iPi * iRadius * iRadius)}cm²");
}
fnc(3.14);
} else {
/* This is never going to be called since else if is already handling the only option besides the if */
}
var fnc = (iAlpha, iBravo, cb) => {
cb(iAlpha + iBravo);
}
fnc(84,255,(iResult) => {
console.log(iResult);
});
Template literals and arrow functions are not available in JScript. The latest version of JScript is based on ES5, and those two features are only available in ES2015. And console is not available in JScript if you are using the Windows Script Host; instead, use WScript.Echo().
var iTest = 0;
if (iTest) {
var sText = "This is a template string which can contain variables like " + iTest;
WScript.Echo(sText);
} else {
var fnc = function(iRadius, iPi) {
iPi = 3.14;
WScript.Echo("The area of the circle with the radius " + iRadius + "cm is " + Math.round(iPi * iRadius * iRadius) + "cm²");
}
fnc(3.14);
}
var fnc = function(iAlpha, iBravo, cb) {
cb(iAlpha + iBravo);
}
fnc(84, 255, function(iResult) {
WScript.Echo(iResult);
});
It would also be nice if you could provide more information about the particular error you are getting. This should fix it, but it would make it easier for us to help if we know exactly what the problem is.

In Graphiti, how to put an editor on a label attached to a Figure

I was trying to create an editable label like the one in the example connection_labeledit_inplace.
The problem I have is that I want to attach the label to a custom VectorFigure in place of a Connection. When doing that the label is just part of the figure and don't launch the editor.
ivr.shape.menu.MenuItem = graphiti.VectorFigure.extend({
NAME:"ivr.shape.menu.MenuItem",
MyOutputPortLocator : graphiti.layout.locator.Locator.extend({
init: function(parent)
{
this._super(parent);
},
relocate:function(index, figure){
var w = figure.getParent().getWidth();
var h = figure.getParent().getHeight();
figure.setPosition(w, h/2);
}
}),
/**
* #constructor
* Creates a new figure element which are not assigned to any canvas.
*
*/
init: function( width, height) {
this._super();
this.setBackgroundColor( new graphiti.util.Color(200,200,200));
this.setColor(new graphiti.util.Color(50,50,50));
// set some good defaults
//
if(typeof width === "undefined"){
this.setDimension(100, 15);
}
else{
this.setDimension(width, height);
}
// add port
var outputLocator = new this.MyOutputPortLocator(this);
this.createPort("output",outputLocator);
this.label = new graphiti.shape.basic.Label("I'm a Label");
this.label.setColor("#0d0d0d");
this.label.setFontColor("#0d0d0d");
this.addFigure(this.label, new graphiti.layout.locator.LeftLocator(this));
this.label.installEditor(new graphiti.ui.LabelInplaceEditor());
},
repaint : function(attributes)
{
if(this.repaintBlocked===true || this.shape===null){
return;
}
if (typeof attributes === "undefined") {
attributes = {};
}
var box = this.getBoundingBox();
var center = box.getCenter();
var path = ["M",box.x,",",box.y];
path.push("l", box.w-10, ",0");
path.push("l10,", box.h/2);
path.push("l-10,", box.h/2);
path.push("L",box.x,",", box.getBottomLeft().y);
path.push("Z");
var strPath = path.join("");
attributes.path = strPath;
this._super(attributes);
},
/**
* #method
* Called by the framework. Don't call them manually.
*
* #private
**/
createShapeElement:function()
{
// create dummy line
return this.canvas.paper.path("M0 0L1 1");
}
});
For this example I put the label on the left of the Figure but obviously I'll make a Locator that puts the label ON the figure (just in case it changes something)
Up to me the issue is coming from the way the 'graphiti.Canvas.getBestFigure()' works. The function check only over elements directly attached to the 'graphity.Canvas' Also, the function is missing some recursion to propagates the event on the children.
Graphiti provides a CenterLocator.
All events like dblClick can be catched by the figure.
....did youuse thelatest version?

Using new Image().src for click tracking

I am attempting to figure out why this click tracker isn't working. The code was written by another developer so I am not entirely sure if this ever did work.
function trackSponsor(o, p) {
(new Image()).src = PATH_BASE + 'click/' + p + '/' + o + "?_cache=" + (+(new Date()));
return false;
}
From what I can gather is that when this function is called it 'creates a new image' to fire a php script asynchronously. According to Firebug, the request is made however it is 'aborted' ~30ms in. The odd thing is that it will 'sometimes' work as in 1 in every 10+ regardless of the browser.
I would much rather fix this so that it works instead of re-writing it as an ajax request.
Any help is appreciated.
Thanks in advance.
EDIT
Because of tvanfosson's post that got me thinking. I have included the line which calls the click tracker below.
<a onclick="trackSponsor(60, 15077); goToNextStep(1988, 15077, 0); return false;" href="#">view</a>
the goToNextStep() actually changes the page. I am under the impression that it would only be executed after trackSponsor() had finished.
It's actually pretty trivial to rewrite as a get request using jQuery. Rewriting it will certainly help the next developer understand what's happening and might fix your problem. I'd need to know more about the contents of the variables -- perhaps they need to be urlEncoded? -- before I could help you any more on it. You might try urlEncoding them and see what happens.
function trackSponsor(o, p) {
var url = PATH_BASE + 'click/' + p + '/' + o + "?_cache=" + (+(new Date()));
$.get(url);
return false;
}
EDIT: you might want to check that another handler isn't redirecting the browser to a new location when the event triggering the tracking is invoked. This would abort any pending requests on the page -- and might allow a few to succeed based on the timing of the requests and if the results are delivered before the page is unloaded.
"(new Image()).src = url;" just asks for browser to hit the url.
You should delay for a 50-100ms in order to be sure that tracking info were sent to the server.
function delay(a) {
for (var b = +new Date, c = 1; 0 < c; c++) {
if (0 == c % 1E3) {
var e = +new Date;
if (b > e) break;
if (e - b > a) break;
}
}
}
function trackSponsor(o, p) {
(new Image()).src = PATH_BASE + 'click/' + p + '/' + o + "?_cache=" + (+(new Date()));
delay(100);
return false;
}
I poked around Google Analytics’ ga.js, which does use the new Image() method similar to your script.
The only difference that I could see was in how the object is created. Google's script assigns the object to a variable.
var d=new Image(1,1);d.src=f;
Maybe give that a shot?
function trackSponsor(o, p) {
var i = new Image(1,1);
i.src = PATH_BASE + 'click/' + p + '/' + o + "?_cache=" + (+(new Date()));
return false;
}
It shouldn't make a difference, but is worth a shot.
Maybe try this, for avoiding Garbage Collection to make your log not be lost.
var sendLog = (function () {
var _unique = (function () { /* 产生唯一标识*/
var time = (new Date()).getTime() + '_',
i = 0;
return function () {
return time + (i++);
}
}());
var run = function (url) {
var data = window['imgLogData'] || (window['imgLogData'] = {}),
img = new Image(),
uid = _unique();
data[uid] = img; /* 防止img被垃圾处理*/
img.onload = img.onerror = function () { /* 成功或失败后销毁对象*/
img.onload = img.onerror = null;
img = null;
delete data[uid];
};
img.src = url + '&_cache=' + uid; /* 发送统计内容*/
};
return run;
}());
sendLog('http://log_');

Categories

Resources