Accessing javascript library in iframe in greasemonkey script - dojo

I'm trying to access Dojo within my webapp, and having issues getting what I need. Specifically, I have a webapp in an iframe with different versions of Dojo loaded:
In Firebug, I can do this:
window.dojo.version; // 1.7
window.frames[0].window.dojo.version; // 1.0
(Note iframe is in same domain as parent)
In GreaseMonkey, I can't find either version of Dojo:
dojo // undefined
window.dojo // undefined
window.frames[0].window.dojo // undefined
I started looking into unsafeWindow which supposedly I shouldn't use. It gives me access to the window'd Dojo, but not the iframe'd dojo I actually want.
unsafeWindow.dojo.version // 1.7 (wrong version)
unsafeWindow.frames[0].dojo // undefined
unsafeWindow.frames[0].window.dojo // undefined
window.frames[0].window.dojo // undefined
window.frames[0].unsafeWindow // undefined
window.frames[0].window.unsafeWindow // undefined
I've tried withDoc but I suspect I'm using it incorrectly:
unsafeWindow.dojo.withDoc(window.frames[0].window, function(){
var dijit = unsafeWindow.dijit; // seems wrong; doesn't work
var widget = dijit.byId('someWidgetInsideIframe');
console.log(widget); // undefined
}, this);
Any suggestions on other things I can try to get access to Dojo 1.0 in the iframe? Or if not that, at least figure out how to get access to dojo widgets defined in the iframe using the Dojo I do have access to?

I would expect unsafeWindow.frames[0].window.dojo.version; to work when GM is running on the main page (see below). The fact that it doesn't is a bug in my opinion, but the lead GM dev might not agree. Consider filing a bug report.
However, Greasemonkey normally processes frames/iframes as though they were standalone pages (with some exceptions). This means that the script will fire once for the main page and once for each frame whose src matches the #include/#exclude/#match directives. This also means that things like window.frames[0] will not be defined in every pass.
You can tell you are in the right frame with code like this:
if (window.self == window.top.frames[0]) {
//-- Currently running in the target frame
unsafeWindow.console.log ("dojo.version:", unsafeWindow.dojo.version);
}
else
unsafeWindow.console.log ("These are not droids... Or, er something.");

Related

Cannot read properties of undefined (reading 'find') in Vue.js Meteor

Im following the tutorial here...
https://vue-tutorial.meteor.com/simple-todos/
But I get an error even just when installing the default vue meteor app.
meteor: {
$subscribe: {
'experiments': [],
},
experiments () {
return Experiments.find({}).fetch();
},
},
gives me an error
TypeError: Cannot read properties of undefined (reading 'find')"
If I console log Experiments, its there and I get the Meteor collection object. Any idea why this might be occuring??
import Experiments from '../../api/collections/Experiments'
console.log(Experiments)
Gives me
So its obviously an available object.
Just the find({}).fetch() method on it doesnt seem to be available??
UPDATE:
THE ANSWER BELOW WORKED (kind of)
experiments() {
let experimentsData = Experiments.find({}).fetch();
if (this.$subReady.experiments) {
console.log(experimentsData);
return experimentsData;
}
},
This now returns the experiments in the console log. So they are available. However rendering them to the template doesnt.
<h2>Experiments</h2>
<div v-for="exp in experiments" :key="exp.id">
{{exp.name}}
</div>
Any idea why??
Does it have to be put into a vue data object? Computed??
I thought the meteor:{} object acted kinda like computed, but it appears not??
How do I get the data onto the screen??
The answer is actually not correct.
I am experiencing the same issue from an out of the box meteor vue app created with: meteor create vanillaVueMeteor --vue
The error occurs if you define ANY function in the meteor: section of the default export (and bizarrely the first function defined is always being called regardless of whether it is actually referenced anywhere). This is obviously a bug either in the meteor vue creator or some combination of the default versions of meteor and vue libraries.
Additionally with respect to providing data to your template: you should not call fetch, just pass the result of the find which then means you won't need to wait for the subs to be ready because reactivity will update the view when the data is available. Obviously the underlying issue is preventing this all from working correctly.
UPDATE:
It seems to be an issue with 2.7.x Downgrading to the latest 2.6 worked for me:
meteor npm remove vue
meteor npm i vue#2.6 --save
It looks like you need to just use this.$subReady in your 'experiments` function to handle the timing of how the data comes in over DDP in Meteor.
I use something like this in all my subscriptions.
When the subscription starts up, the data won't be delivered from the publication the very 1st time, so that is what causes your undefined error that you are getting.
I love the Vue + Meteor combo. You can also come join the community Slack or Forum if you have questions, there are a bunch of us to help you there.
Happy Coding!
Bob
experiments () {
let experimentsData = Experiments.find({}).fetch();
if(this.$subReady.experiments){
return experimentsData;
}
},
This should resolve your issue in the UI. The HTML data will load and run before all the data from Meteor is ready, so you just use something like this:
<h2>Experiments</h2>
<div v-if="subReady.experiments" v-for="exp in experiments" :key="exp.id">
{{exp.name}}
</div>

How to save url and use out of chrome api in Vue.js for chrome extension?

I am currently facing a weird issue with developing a simple chrome extension.
Basically, I want to build an extension that saves the currently focused URL. However, seems like URL is not saved in variables that I defined.
I have tried to use an array to store it, and also a variable.
consoleClick() {
var urlss = []
var getTab = function(tab){
urlss.push(tab)
alert(tab)
};
chrome.tabs.query({'active':true}, function(tabs){
getTab(tabs[0].url)
});
console.log(urlss)
this.$store.commit('addUrl',urlss[0])
console.log(this.$store.state.urls[0])
}
Here, once button is clicked, with "chrome.tabs.query()" I was able to get currently focused url. and I saved it to "urlss", and checked it with console.log(urlss).
I could see the url in console log, however, when I tried to access to url with urlss[0], it says urlss[0] is "undefined" even though I can see that
[]
0: "https://stackoverflow.com/posts/57089954/edit"
length: 1
__proto__: Array(0)
in log. This leads to push "undefined" to my vuex storage.
I also tried to push it to vuex storage right away in chrome.tabs.query(), however it gives me that $store is not defined.
I know that my explanation is pretty messy but I need help from the community! Thanks in advance

CoffeeScript function can not be found

I have a Rails 3.2.8 application that I have recently upgraded from 3.1, and I have converted all of the original application.js code to CoffeeScript. Most of it is working fine. However, I have a breadcrumb function that I call in several views that is not being found. For right now, I'm just throwing up an alert to see if it is working:
product_breadcrumb = (attr) ->
alert attr
That's in a file called product_search.js.coffee. It is being successfully compiled, and ends up looking like this:
(function() {
var product_breadcrumb;
product_breadcrumb = function(attr) {
return alert(attr);
};
}).call(this);
I guess that's right, I don't know. Anyway, in Firebug I'm getting:
ReferenceError: product_breadcrumb is not defined
Please note that this is after an Ajax call. I don't know why the function wouldn't be available though. It's just a function definition after all. Shouldn't it still be available to the rendered HTML from the Ajax call? I can't understand why the function can't be found.
This needs to be on the global scope, and then you need to call it that way.
You should write:
root = exports ? this
and name your function
root.product_breadcrumb
then you can call it elsewhere as expected.
See this answer for a much lengthier explanation.

How do I tell a Dojo custom build about external libraries?

In my Dojo build, I'm pulling in some third party libraries.
As I go through the build process, I'm getting errors due to ReferenceErrors.
This is fine. This makes sense.
However, I'd like to tell the Dojo build process about the things that are being referenced. In essence, this would be akin to passing externs to the Closure Compliler.
Thus, my question: How do I tell the Dojo build process about references that it cannot infer from my code base?
This is using Dojo 1.8
I just ran into this myself. Now I'm assuming that the ReferenceErrors you referred to are for browser objects like navigator, window, document, and the like. If so, then this is a problem introduced by the Dojo build process itself, because the build is performed by dojo.js running inside of Rhino where browser global objects are not defined. It's a dojo/Rhino error, not a closure compiler error, so there's nothing you can pass to closure to change this. For example, a script like
(function(){
window.alert("hello");
})();
will break your dojo build if it is included in a dojo layer. When the dojo AMD loader resolves the dependency of a script like the above, it will run the body of the function, resulting in a ReferenceError because window does not exist in Rhino.
To get around this, wrap the script as an AMD module
define([], function(){
window.alert("hello");
});
and then the function body will NOT be executed by the AMD loader during dojo build.

Reliably getting favicons in Chrome extensions, chrome://favicon?

I'm using the chrome://favicon/ in my Google Chrome extension to get the favicon for RSS feeds. What I do is get the base path of linked page, and append it to chrome://favicon/http://<domainpath>.
It's working really unreliably. A lot of the time it's reporting the standard "no-favicon"-icon, even when the page really has a favicon. There is almost 0 documentation regarding the chrome://favicon mechanism, so it's difficult to understand how it actually works. Is it just a cache of links that have been visited? Is it possible to detect if there was an icon or not?
From some simple testing it's just a cache of favicons for pages you have visited. So if I subscribe to dribbble.com's RSS feed, it won't show a favicon in my extension. Then if I visit chrome://favicon/http://dribbble.com/ it won't return right icon. Then I open dribbble.com in another tab, it shows its icon in the tab, then when I reload the chrome://favicon/http://dribbble.com/-tab, it will return the correct favicon. Then I open my extensions popup and it still shows the standard icon. But if I then restart Chrome it will get the correct icon everywhere.
Now that's just from some basic research, and doesn't get me any closer to a solution. So my question is: Is the chrome://favicon/ a correct use-case for what I'm doing. Is there any documentation for it? And what is this its intended behavior?
I've seen this problem as well and it's really obnoxious.
From what I can tell, Chrome populates the chrome://favicon/ cache after you visit a URL (omitting the #hash part of the URL if any). It appears to usually populate this cache sometime after a page is completely loaded. If you try to access chrome://favicon/http://yoururl.com before the associated page is completely loaded you will often get back the default 'globe icon'. Subsequently refreshing the page you're displaying the icon(s) on will then fix them.
So, if you can, possibly just refreshing the page you're displaying the icons on just prior to displaying it to the user may serve as a fix.
In my use case, I am actually opening tabs which I want to obtain the favicons from. So far the most reliable approach I have found to obtain them looks roughly like this:
chrome.webNavigation.onCompleted.addListener(onCompleted);
function onCompleted(details)
{
if (details.frameId > 0)
{
// we don't care about activity occurring within a subframe of a tab
return;
}
chrome.tabs.get(details.tabId, function(tab) {
var url = tab.url ? tab.url.replace(/#.*$/, '') : ''; // drop #hash
var favicon;
var delay;
if (tab.favIconUrl && tab.favIconUrl != ''
&& tab.favIconUrl.indexOf('chrome://favicon/') == -1) {
// favicon appears to be a normal url
favicon = tab.favIconUrl;
delay = 0;
}
else {
// couldn't obtain favicon as a normal url, try chrome://favicon/url
favicon = 'chrome://favicon/' + url;
delay = 100; // larger values will probably be more reliable
}
setTimeout(function() {
/// set favicon wherever it needs to be set here
console.log('delay', delay, 'tabId', tab.id, 'favicon', favicon);
}, delay);
});
}
This approach returns the correct favicon about 95% of the time for new URLs, using delay=100. Increasing the delay if you can accept it will increase the reliability (I'm using 1500ms for my use case and it misses <1% of the time on new URLs; this reliability worsens when many tabs are being opened simultaneously). Obviously this is a pretty imprecise way of making it work but it is the best method I've figured out so far.
Another possible approach is to instead pull favicons from http://www.google.com/s2/favicons?domain=somedomain.com. I don't like this approach very much as it requires accessing the external network, relies on a service that has no guarantee of being up, and is itself somewhat unreliable; I have seen it inconsistently return the "globe" icon for a www.domain.com URL yet return the proper icon for just domain.com.
Hope this helps in some way.
As of Oct 2020, it appears chrome extensions using manifest version 3 are no longer able to access chrome://favicon/* urls. I haven't found the 'dedicated API' the message refers to.
Manifest v3 and higher extensions will not have access to the
chrome://favicon host; instead, we'll provide a dedicated API
permission and different URL. This results in being able to
tighten our permissions around the chrome:-scheme.
In order to use chrome://favicon/some-site in extension. manifest.json need to be updated:
"permissions": ["chrome://favicon/"],
"content_security_policy": "img-src chrome://favicon;"
Test on Version 63.0.3239.132 (Official Build) (64-bit)
chrome://favicon url is deprecated in favor of new favicon API with manifest v3.
// manifest.json
{
"permissions": ["favicon"]
}
// utils.js
function getFaviconUrl(url) {
return `chrome-extension://${chrome.runtime.id}/_favicon/?pageUrl=${encodeURIComponent(url)}&size=32`;
}
Source: https://groups.google.com/a/chromium.org/g/chromium-extensions/c/qS1rVpQVl8o/m/qmg1M13wBAAJ
I inspected the website-icon in Chrome history page and found this simpler method.
You can get the favicon url by --
favIconURL = "chrome://favicon/size/16#1x/" + tab.url;
Don't forget to add "permissions" and "content_security_policy" to Chrome. (https://stackoverflow.com/a/48304708/9586876)
In the latest version of Chrome, Version 78.0.3904.87 (Official Build) (64-bit)) when tested, adding just img-src chrome://favicon; as content_security_policy will still show 2 warnings:
'content_security_policy': CSP directive 'script-src' must be specified (either explicitly, or implicitly via 'default-src') and must whitelist only secure resources.
And:
'content_security_policy': CSP directive 'object-src' must be specified (either explicitly, or implicitly via 'default-src') and must whitelist only secure resources.
To get rid of them use:
"permissions": ["chrome://favicon/"],
"content_security_policy": "script-src 'self'; object-src 'self'; img-src chrome://favicon;"
Now you can use chrome://favicon/http://example.com without getting any errors or warnings.