I am trying to create an ad for a website. When someone clicks on the ad, it is supposed to redirect them to a website, and register the click with google analytics.
I have done this with the following script:
import flash.external.ExternalInterface;
movieClip_3.addEventListener(MouseEvent.CLICK, onClick);
function onClick(event:MouseEvent):void {
trace("hi");
ExternalInterface.call("console.log", "test");
//ExternalInterface.call("_gaq._trackPageview", "/vpv/annoncer/[firmanavn.dk]");
navigateToURL(new URLRequest("http://www.google.com"), "_blank");
}
When i run this using preview->flash and i click on the surface, (where there is a big red square called movieClip_3) It opens the webpage. However when i try to publish as html, the big red square shows, but nothing happens on click. Not even console.log. I have tried setting allowscriptaccess = always but that does not change anything.
Can you guys help me? Any help is appreciated.
Security problems?
Developers should validate all URLs before passing them to this
function.
For local content running in a browser, calls to the navigateToURL()
method that specify a "javascript:" pseudo-protocol (via a URLRequest
object passed as the first parameter) are only permitted if the SWF
file and the containing web page (if there is one) are in the
local-trusted security sandbox. Some browsers do not support using the
javascript protocol with the navigateToURL() method. Instead, consider
using the call() method of the ExternalInterface API to invoke
JavaScript methods within the enclosing HTML page.
source: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/package.html#navigateToURL()
EDIT:
Since javascript is not permitted out of the sandbox, you can try with ExternalInterface:
ExternalInterface.call("javascript_functionname", "mypage.html");
In the parameters for publishing:
'allowScriptAccess', 'always',
You can only test this on your server not locally.
I'd suggest double checking the security settings (right click on flash container->Global Settings-> Advanced -> Trusted Location Settings). Also make sure your html file contains the javascript function you're trying to execute and look for blocked pop-up notifications in the browser. Maybe you just don't allow pop-ups to run.
Related
Summary: I need to find a way to accomplish with programmatic injection the same exact behaviour as using content_scripts > matches with "all_frames": true on a manifest. Why? because it is the only way I've found of injecting iframe's content in an extension page without having Cross-Origin errors.
I'm moving to optional_permissions on a Chrome extension and I'm on a dead end.
What I want:
Move this behaviour to optional_permissions in order to be able to add more hosts in the future. With the current code, by adding one new host on content_scripts > matches the extension is disabled by Chrome.
For the move, I removed content_scripts in the manifest and I added "optional_permissions": ["*://*/"],. Then, I successfully implemented a dialog asking new permissions to the user with chrome.permissions.request.
As I said before, the problem is how to inject the iframe's content in an extension page.
What I've tried:
chrome.declarativeContent.RequestContentScript (mentioned here) with allFrames: true. I can only see the script running if I enter the URL directly, nothing happens when that URL is set in an iframe.
chrome.tabs.onUpdated: url is undefined for an extension page. Also, the iframe url is not detected.
Call chrome.tabs.executeScript with allFrames: true as soon as I load the first iframe. By doing this I get an exception Cannot access contents of the page. Extension manifest must request permission to access the respective host. and the "respective host" is chrome-extension://, which is not a valid host if you want to add it to the permissions.
I'm lost. I couldn't find a way to simulate the same behaviour as content_scripts > matches with programmatic injection.
Note: using webNavigation API is not an option since the extension is live and it has thousands of users. Because of this, I can not use the frameId property for executeScript. Thus, my only option with executeScript was to inject all frames but the chrome-extension host issue do not let me continue.
Update: I was able to accomplish what I wanted but only on an HTTP host. I used chrome.tabs.executeScript (option 3).
The question remains on how to make this work on an extension page.
You cannot run content scripts in any extension page, including your own.
If you want to run code in a subframe of your extension page, then you have to use frameId. There are two ways to do this, with and without webNavigation.
I've put all code snippets in this answer together (with some buttons to invoke the individual code snippets) and shared it at https://robwu.nl/s/optional_permissions-script-subframe.zip
To try it out, download and extract the zip file, load the extension at chrome://extensions and click on the extension button to open the test page.
Request optional permissions
Since the goal is to programmatically run scripts with optional permissions, you need to request the permission. My example will use example.com.
If you want to use the webNavigation API too, include its permission in the permission request too.
chrome.permissions.request({
// permissions: ['webNavigation'], // uncomment if you want this.
origins: ['*://*.example.com/*'],
}, function(granted) {
alert('Permission was ' + (granted ? '' : 'not ') + 'granted!');
});
Inject script in subframe
Once you have a tab ID and frameId, injecting scripts in a specific frame is easy. Because of the tabId requirement, this method can only work for frames in tabs, not for frames in your browserAction/pageAction popup or background page!
To demonstrate that code execution succeeds, my examples below will call the next injectInFrame function once the tabId and frameId is known.
function injectInFrame(tabId, frameId) {
chrome.tabs.executeScript(tabId, {
frameId,
code: 'document.body.textContent = "The document content replaced with content at " + new Date().toLocaleString();',
});
}
If you want to run code not just in the specific frame, but all sub frames of that frame, just add allFrames: true to the chrome.tabs.executeScript call.
Option 1: Use webNavigation to find frameId
Use chrome.tabs.getCurrent to find the ID of the tab where the script runs (or chrome.tabs.query with {active:true,currentWindow:true} if you want to know the current tabId from another script (e.g. background script).
After that, use chrome.webNavigation.getAllFrames to query all frames in the tab. The primary way of identifying a frame is by the URL of the page, so you have a problem if the framed page redirects elsewhere, or if there are multiple frames with the same URL. Here is an example:
// Assuming that you already have a frame in your document,
// i.e. <iframe src="https://example.com"></iframe>
chrome.tabs.getCurrent(function(tab) {
chrome.webNavigation.getAllFrames({
tabId: tab.id,
}, function(frames) {
for (var frame of frames) {
if (frame.url === 'https://example.com/') {
injectInFrame(tab.id, frame.frameId);
break;
}
}
});
});
Option 2: Use helper page in the frame to find frameId
The option with webNavigation looks simple but has two main disadvantages:
It requires the webNavigation permission (causing the "Read your browsing history" permission warning)
The identification of the frame can fail if there are multiple frames with the same URL.
An alternative is to first open an extension page that sends an extension message, and find the frameId (and tab ID) in the metadata that is made available in the second parameter of the chrome.runtime.onMessage listener. This code is more complicated than the other option, but it is more reliable and does not require any additional permissions.
framehelper.html
<script src="framehelper.js"></script>
framehelper.js
var parentOrigin = location.ancestorOrigins[location.ancestorOrigins.length - 1];
if (parentOrigin === location.origin) {
// Only send a message if the frame was opened by ourselves.
chrome.runtime.sendMessage(location.hash.slice(1));
}
Code to be run in your extension page:
chrome.runtime.onMessage.addListener(frameMessageListener);
var randomMessage = 'Random message: ' + Math.random();
var f = document.createElement('iframe');
f.src = chrome.runtime.getURL('framehelper.html') + '#' + randomMessage;
document.body.appendChild(f);
function frameMessageListener(msg, sender) {
if (msg !== randomMessage) return;
var tabId = sender.tab.id;
var frameId = sender.frameId;
chrome.runtime.onMessage.removeListener(frameMessageListener);
// Note: This will cause the script to be run on the first load.
// If the frame redirects elsewhere, then the injection can seemingly fail.
f.addEventListener('load', function onload() {
f.removeEventListener('load', onload);
injectInFrame(tabId, frameId);
});
f.src = 'https://example.com';
}
I have a requirement that we should be able to copy an image displayed in our application, to Clipboard and paste it outside (Like on Excel).
I was trying the below code snippet (Inside a button Click).
Clipboard.generalClipboard.clear();
var dataLoaded:Boolean = Clipboard.generalClipboard.setData(ClipboardFormats.RICH_TEXT_FORMAT,
byteArray, false);
The dataLoaded object is true, however it does not paste anything when tried on Excel or MsPaint.
Do we have any way to achieve this?
Thanks.
The code you are showing is not enough in itself to get a successful transfer. Like many other operations within the security sandbox of a FP app (web) this code can only respond to a direct user interaction. So your code without any valid context cannot work of course but if called within a mouse down listener for example (a true user generated mouse event, creating a fake mouseevent would still not work) it should respond correctly:
private function handleMouseClick(event:MouseEvent):void
{
Clipboard.generalClipboard.clear();
var dataLoaded:Boolean = Clipboard.generalClipboard.setData(ClipboardFormats.RICH_TEXT_FORMAT, byteArray, false);
}
I've added the Share Target declaration to my app for the data format WebLink and everything works as expected. However, when I add a JumpListItemBackgroundConverter or JumpListItemForegroundConverter anywhere in the app, the app hangs on the splash screen when you enter the app using the Share from IE. No exception, no crash, the debugger doesn't even stop. All I get is a cryptic error in the output window, "The program '...' has exited with code -1073741819 (0xc0000005) 'Access violation'." The documentation for those converters say they're fine with universal apps, just that they've been moved to a different namespace. Has anyone been able to get these two things to work in the same app? If so, where did I go wrong? Or is there something better than those two converters to get the LongListSelector look and feel?
Steps to reproduce:
Create a new universal app. I chose hub.
Add a share target of format WebLink to the appxmanifest declarations.
Add a new page to point the share contract to.
Add the OnShareTargetActivated code to app.xaml.cs to open the new page. See code below
Add a JumpListItemBackgroundConverter to the resources of the main page of the app. You don't need to apply it to anything, just declaring it is enough to break the sharing.
Go to IE and share a link. It should hang on the splash screen.
Code for app.xaml.cs:
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
// Replace SharePage with the name of the share target page
var rootFrame = new Frame();
rootFrame.Navigate(typeof(SharePage), args.ShareOperation);
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
It turns out this is a bug in the emulator. It works if you test on a physical device.
MSDN Forum - JumpListItemBackgroundConverter and Share Target in Windows Phone 8.1
is there any solution on StageWebView.loadURL(), how I can handle URLs in HTML Pages which have target="_blank"?
It's a mobile Android App. (TabbedViewApplication)
Hope someone can help.
Thx
One option is StageWebViewBridge.
StageWebViewBridge is an extended version of flash.media.StageWebView.
Extends loadString method with AS3 - JS communication.
-Extends Bitmap class, you can modify his x,y,alpha,rotation,visible, etc ( Version 1 Beta )
-Communicates Actionscript with Javascript.
-Communicates Javascript with Actionscript.
-Load local files and resources in a easy way.
-Extends loadString method with AS3 - JS communication.
-Extends loadString method to load local resources.
-Lets you take an SnapShot to use as the bitmapData of the bitmap.
StageWebViewBridge source: https://code.google.com/p/stagewebviewbridge/
I never worked with the StageWebView but I know it's really limited. When using an HTMLLoader, you can set a custom HTMLHost instance that specifies to use current HTMLLoader when opening to _blank. However, I don't think it's possible with StageWebView.
public class MyHTMLHost extends HTMLHost
{
public function MyHTMLHost(defaultBehaviors:Boolean=false)
{
super(defaultBehaviors);
}
override public function createWindow(windowCreateOptions:HTMLWindowCreateOptions):HTMLLoader
{
// all JS calls and HREFs to open a new window should use the existing window
return htmlLoader;
}
}
OK, so the only solution for this problem i could found is to load the page (containing the links) as String with the URLLoader and replace its specified parts. Finally loading it via StageWebView.loadString() method.
Problems occur when the Site is dynamic and contains JavaScript. I had also replace some relative links with absolute pathes.
That's it... but I really hope that adobe makes it possible to load those "_blank" links with the StageWebView.loadURL() method.
If you want to capture when a user clicks on a link inside your StageWebView add an an event listener for location changing event (LocationChangeEvent).
This LocationChangeEvent will include the URL they are going to and target. Then you can prevent the URL from loading, let it continue (by doing nothing) or handle it any other way including loading another URL.
If you want to load another URL first stop the loading with stageWebView.stop(). You should also call event.preventDefault(). You can then attempt to
Note: There is another event called locationChange that may be helpful.
As it was declared as an official bug, adobe QA Owner Sanjay C. added a comment: "Able to reproduce the issue with the attached project. Sending to IRB."
So, hope the next Build will come up with the fix wit it.
Best regards
In Google Chrome's extension developer section, it says
The HTML pages inside an extension
have complete access to each other's
DOMs, and they can invoke functions on
each other. ... The popup's contents
are a web page defined by an HTML file
(popup.html). The popup doesn't need
to duplicate code that's in the
background page (background.html)
because the popup can invoke functions
on the background page
I've loaded and tested jQuery, and can access DOM elements in background.html with jQuery, but I cannot figure out how to get access to DOM elements in popup.html from background.html.
can you discuss why you would want to do that? A background page is a page that lives forever for the life time of your extension. While the popup page only lives when you click on the popup.
In my opinion, it should be refactored the other way around, your popup should request something from the background page. You just do this in the popup to access the background page:
chrome.extension.getBackgroundPage()
But if you insist, you can use simple communication with extension pages with sendRequest() and onRequest. Perhaps you can use chrome.extension.getViews
I understand why you want to do this as I have run into the problem myself.
The easiest thing I could think of was using Google's method of a callback - the sendRequest and onRequest methods work as well, but I find them to be clunky and less straightforward.
Popup.js
chrome.extension.getBackgroundPage().doMethod(function(params)
{
// Work with modified params
// Use local variables
});
Background.html
function doMethod(callback)
{
if(callback)
{
// Create/modify params if needed
var params;
// Invoke the callback
callback(params);
}
}
As other answers mention, you can call background.js functions from popup.js like so:
var _background = chrome.extension.getBackgroundPage();
_background.backgroundJsFunction();
But to access popup.js or popup.html from background.js, you're supposed to use the messages architecture like so:
// in background.js
chrome.runtime.sendMessage( { property: value } );
// in popup.js
chrome.runtime.onMessage.addListener(handleBackgroundMessages);
function handleBackgroundMessages(message)
{
if (message.property === value)
// do stuff
}
However, it seems that you can synchronously access popup.js from background.js, just like you can synchronously access the other way around. chrome.extension.getViews can get you the popup window object, and you can use that to call functions, access variables, and access the DOM.
var _popup = chrome.extension.getViews( { type: 'popup' } )[0];
_popup.popupJsFunction();
_popup.document.getElementById('element');
_popup.document.title = 'poop'
Note that getViews() will return [] if the popup is not open, so you have to handle that.
I'm not sure why no one else mentioned this. Perhaps there's some pitfalls or bad practices to this that I've overlooked? But in my limited testing in my own extension, it seems to work.