I’ve done a lot of research on and off Stackoverflow and I’ve read many posts and tried many suggestions to no avail.
So I am posting a new question since all the answers that I have read haven’t led me to a solution.
Issue: I need to close all tabs that I’ve opened via window.open() function.
My original implementation uses LocalStorage to keep track of tabs that have been open via the parent window.
When a link is clicked (in the parent window), a new tab is open via window.open(“url”, “uniqueId”);
I store the uniqueId in an array in localstorage which in essence is my list of tabs.
To close all the windows that I opened, I loop through the localStorage array (the tablist).
I get the window uniqueId which I use to reference and close the (child) window…
// (localstorage) myTabList': [“window1”,” window2”,” window3”,” window4”]
var arr = JSON.parse(localStorage.getItem(‘myTabList'));
for (var i = 0; i < arr.length; i++) {
newWindowObj = window.open('', arr [i]);
if (newWindowObj != null) {
newWindowObj.close();
}}
This works like a charm as long as the (child) window.name doesn’t change.
Unfortunately, the names of some of the (child) tabs do change.
I have no control over the child tabs.
Think of if as if I open Google or Bing website in a child tab and the name changes.
Parent window (tab)
link A <a href=”#” #click=”window.open(‘http://www.google.ca’,’GOOGLE’) ”>Google</a>
link B <a href=”#” #click=”window.open(‘http://www.bing.com,’BING’)”>Bing</a>
I should point out that the tabs that change names load 3rd party web apps that are cross domain.
My app (parent tab web app) is a Vue 2.x project. Since the implementation described above doesn’t work as desired when a window name changes, I need a different solution.
I thought I could persist the tabs (window object) in an array of windows using the “vuex-presistedstate”.
If I use simple objects with Strings (just for testing purposes) to store data, all works flawlessly. e.g. storing objects containing String properties in an array {“url”:’http;//www.google.com”, “name”: “GOOOGLE”}, {“url”:’http;//www.bing.com”, “name”: “BING”}
But I run into issues when I try to store actual window objects.
var myTabList = [];
var newWinRef = window.open(“url”, “uniqueId”);
myTabList.push(newWinRef);
The storage of the window seems OK… based on the console output.
But it’s followed by this message.
Error in v-on handler: "TypeError: Converting circular structure to JSON
-- starting at bojec with constructor 'Window'
-- propery 'widow' closes the circle
So this solution doesn’t works very well either.
All I am trying to do is to open a window via window.open and persist some info about the newly opened windows / tab so that I can identify the tab(s) and call window.close() to close the child tab.
Any suggestions would be much appreciated.
Thank you!
Related
well google translate extension in chrome, has popup feature, it displays translation of selected word instantly, I wanted to access those translations displayed by popup, but this popup element is shadowRoot("closed"), so javascript cant access its content, I red an article about that subject and author says:
But really there is nothing stopping someone executing the following JavaScript before your component definition.
Element.prototype._attachShadow = Element.prototype.attachShadow; Element.prototype.attachShadow = function () { return this._attachShadow( { mode: "open" } ); };
Is it possible to change attachShadow method of other extension? if so where should it be executed by my extension? background_script or maybe somewhere. I think each extension has its own enviroment and I have no chane to edit their methods. I wish I'm wrong :)
No need to override it.
There's a special method in the content script.
Chrome 88+:
let shadowRoot = chrome.dom.openOrClosedShadowRoot(element);
Firefox 63:
let shadowRoot = element.openOrClosedShadowRoot();
Combined:
let shadowRoot = chrome.dom?.openOrClosedShadowRoot(element)
|| element.openOrClosedShadowRoot();
I have a problem with the chrome extension project I'm working on.
Generally, it has only one purpose - to remove the addresses from browsing history that is included in the array. (later on, I'm going to add some UI for it ). The chrome background console doesn't show any errors - additionally, I did it just like the documentation said.
How to make that chrome extension background script removing array elements from history.
console.log("hi");
// delete URL
const arr = [
"https://www.facebook.com/",
"https://www.messenger.com/",
"https://www.netflix.com/",
"https://www.youtube.com/"
]
arr.forEach( site => {
console.log(site)
chrome.history.deleteUrl({ url: site });
});
Is it possible, using javascript, to control an overlay firefox extension? I've extracted the contents of the extension and have identified what functions/methods I need to run, but they are not accessible within the scope of the console.
Thanks in advance for any ideas.
Yes it possible to interact with other add-ons, given the right circumstances.
My test case here will be com.googlecode.sqlitemanager.openInOwnWindow(), which is part of the SqliteManager addon.
In newer builds (I'm using Nightly), there is the Browser Toolbox. With it is is as simple as opening a toolbox and executing com.googlecode.sqlitemanager.openInOwnWindow() in the Console.
You may instead use the Browser Console (or any chrome enabled WebDev Console for that matter, e.g. the Console of "about:newtab"). But you need some boilerplate code to first find the browser window. So here is the code you can execute there: var bwin = Services.wm.getMostRecentWindow("navigator:browser"); bwin.com.googlecode.sqlitemanager.openInOwnWindow()
Again, enable chrome debugging. Then open a Scratchpad and switch to Chrome in the Environment menu. Now executing com.googlecode.sqlitemanager.openInOwnWindow() in our Scratchpad will work.
You may of course write your own overlay add-on.
As a last resort, patch the add-on itself.
Bootstrapped/SDK add-ons: you can load XPIProvider.jsm (which changed location recently) and get to the bootstrapped scope (run environment of bootstrap.js) via XPIProvider.bootstrapScopes[addonID], and take it from there (use whatever is in the bootstrap scope, e.g. the SDK loader).
Now about the right circumstances: If and how you can interact with a certain add-on depends on the add-on. Add-ons may have global symbols in their overlay and hence browser window, such as in the example I used. Or may use (to some extend) JS code modules. Or have their own custom loader stuff (e.g. AdBlock Plus has their own require()-like stuff and SDK add-ons have their own loader, which isn't exactly easy to infiltate)...
Since your question is rather unspecific, I'll leave it at this.
Edit by question asker: This is correct, however I figured I'd add an example of the code I ended up using in the end, which was in fact taken directly from mozilla's developer network website:
In my chrome js:
var myExtension = {
myListener: function(evt) {
IprPreferences.setFreshIpStatus(true); // replace with whatever you want to 'fire' in the extension
}
}
document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);
// The last value is a Mozilla-specific value to indicate untrusted content is allowed to trigger the event.
In the web content:
var element = document.createElement("MyExtensionDataElement");
element.setAttribute("attribute1", "foobar");
element.setAttribute("attribute2", "hello world");
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent("MyExtensionEvent", true, false);
element.dispatchEvent(evt);
Update for Firefox 47 and up
Things changed drastically in Firefox 47. This is the new way to access it.
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var addonid = 'Profilist#jetpack';
var scope = XPIScope.XPIProvider.activeAddons.get(addonid).bootstrapScope
Old way for < Firefox 47
Update for methods of today
Typically you will do so like this:
If i wanted to get into AdBlocks scope, I check AdBlock id, it is {d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d} so I would go:
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var adblockScope = XPIScope.XPIProvider.bootstrapScopes['{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'];
You can now tap into anything there.
Another example, I have an addon installed with id NativeShot#jetpack
I would tap into it like this:
var XPIScope = Cu.import('resource://gre/modules/addons/XPIProvider.jsm');
var nativeshotScope = XPIScope.XPIProvider.bootstrapScopes['NativeShot#jetpack'];
if you do console.log(nativeshotScope) you will see all that is inside.
I've an extension, and an XUL file inside it (let's call it A). XUL file contains an <iframe>, where is loaded some web page (let's call it B). B is loaded from the different domain.
A is parent to B. I want to send a message from within B to A using window.parent.postMessage().
I'm getting the following exception:
... permission denied to B to call method ChromeWindow.postMessage
How to fix that error? If there is no way to do that, how can I pass message from B to A?
I am using Firefox 16.0.1 under Windows 7.
I had a very similar problem,
it's just I had a html-popup (local) that couldn't send 'postMessage' to my xul-background-task.
I think I got it to work,
strangely enough by initiating a MessageEvent of my own (the very same thing postMessage does)
but with a (I believe obsolete) fallback.. in short: I brewed something together from MDN and other sites ;)
My script in the content:
var Communicator =
{
postMessage: function(data)
{
// We need some element to attach the event to, since "window" wont work
// let's just use a fallback JSON-stringified textnode
var request = document.createTextNode(JSON.stringify(data));
// and as always attach it to the current contentwindow
document.head.appendChild(request);
// Now let's make a MessageEvent of our own, just like window.postMessage would do
var event = document.createEvent("MessageEvent");
event.initMessageEvent ("own_message", true, false, data, window.location, 0, window, null);
// you might want to change "own_message" back to "message" or whatever you like
//and there we go
request.dispatchEvent(event);
}
}
And instead of window.postMessage(data) now use Communicator.postMessage(data)
that's all!
Now in my overlay there's nothing but our good old
addEventListener('own_message', someMessageFunc, false, true);
//or maybe even "message" just like originally
Hopefully this will work for you, too (didn't check that on iframes...)
You should check the type of iframe B
Edit:
Apparently you must flag your chrome as contentaccessible, and take into consideration the security.
Just posting in case someone faced the same problem.
Succeeded in posting message from within B to A using events as described here.
But it is not answer, because window.parent.postMessage() still doesn't work as intended.
This question is also at sharepoint.stackexchange.com but has failed to get views or responses so I'm posting here.
I'm trying to set the zoom level of a Visio document which is shown through the Visio Web Service.
http://mysite/_layouts/VisioWebAccess/VisioWebAccess.aspx?id=/Shared%20Documents/MyDiagram.vdw
I want to use the 'fit to page' zoom level which is achieved by pressing the button on the right of the toolbar. My first thought was click the button via javascript, but didn't get immediate success and also stumbled across MSDN articles on Objects in the Visio Services JavaScript API, the Vwa.VwaControl.getActivePage Method and the Vwa.Page.setZoom Method.
I can successfully construct a VwaControl object
vwaControl = new Vwa.VwaControl("ctl00_PlaceHolderMain_VisioWebAccess");
but I get null when I call getActivePage() on this control.
I've tried constructing other VwaControl using other ids from the page but none of them are valid - I get an error like "VwaControl does not exist for id {0}". I've tried traversing down the tree from vwaControl._control._zoomControl._fitButton._clickDelegate but I don't know how to fire that delegate.
Has anyone implemented an 'auto zoom to fit' feature in the VisioWebAccess.aspx page?
See answer at sharepoint.stackexchange.com - the zoom and positioning is saved within the document, so set it there. I was unable to control the zoom using javascript.
If you follow the example on the getZoom documentation, which is to add a handler to 'diagramComplete', you can get a valid reference to the active page...
I.e.
function zoomVWAControl()
{
vwaControl= new Vwa.VwaControl("WebPartWPQ2");
vwaControl.addHandler("diagramcomplete", onDiagramComplete);
}
function onDiagramComplete()
{
try{
vwaPage = vwaControl.getActivePage();
var zoomLevel = vwaPage.getZoom();
vwaPage.setZoom(Number(200));
}
catch(err){
alert(err);
}
}