flex open url from HTML component in external browser - html

I am trying to open url links from within the HTML component into the system browser.
I am using this method to create several HTML component child and all of them are added in a Vgroup.
public function addHtmlText(htmlValue:String):void {
var htmlData:HTML = new HTML();
htmlData.percentWidth = 95;
htmlData.htmlText = htmlValue
htmlData.horizontalScrollPolicy="false"
htmlData.verticalScrollPolicy="false"
chatCanvas.addElement(htmlData);
}
this is how I render the strait text link into a real link ( )
public function emoUrl(emoValue:String):String {
var urlRegex:RegExp = /(((http|ftp|https):\/\/){1}([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+)+([\S,:\/\.\?=a-zA-Z0-9_-]+))/igs
var emoValue1:Array = emoValue.match(urlRegex);
if (urlRegex.test(emoValue)) {
emoValue = emoValue.split(emoValue.match(urlRegex)).join(''+emoValue1.toString()+'')
}
return emoValue;
}
the problem is that since these are all individual HTML component elements and that a user can click on any one of them to open in the system browser.
currently, the link will open, but within the html component. I need it to be external.
I have found this on the internet that might help but I have no idea on hot to implement it for my needs.
htmlData.htmlLoader.navigateInSystemBrowser = true
thanks !

Create a URLRequest to the web page, and open it with navigateToURL :
var urlRequest:URLRequest = new URLRequest("http://www.adobe.com/");
navigateToURL(urlRequest);
Example loading a page upon click of a button with Flex MXML:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import flash.net.navigateToURL;
protected function clickHandler(event:MouseEvent):void
{
navigateToURL(new URLRequest("http://www.adobe.com"), "_blank");
}
]]>
</fx:Script>
<s:Button label="Open page"
click="clickHandler(event)" />
</s:Application>
navigateToURL():
Opens or replaces a window in the application that contains the Flash Player container (usually a browser). In Adobe AIR, the function opens a URL in the default system web browser.
Parameters
request:URLRequest — A URLRequest object that specifies the URL to navigate to. For content running in Adobe AIR, when using the navigateToURL() function, the runtime treats a URLRequest that uses the POST method (one that has its method property set to URLRequestMethod.POST) as using the GET method.
window:String (default = null) — The browser window or HTML frame in which to display the document indicated by the request parameter. You can enter the name of a specific window or use one of the following values:
"_self" specifies the current frame in the current window.
"_blank" specifies a new window.
"_parent" specifies the parent of the current frame.
"_top" specifies the top-level frame in the current window.
urlRequest():
Creates a URLRequest object. If System.useCodePage is true, the request is encoded using the system code page, rather than Unicode. If System.useCodePage is false, the request is encoded using Unicode, rather than the system code page.
Parameters
url:String (default = null) — The URL to be requested. You can set the URL later by using the url property.

Related

actionscript 3 contentHeight not updating properly

I am using Adobe Flash Builder with actionscript to make a desktop application.
I am getting some html code from a webpage and putting it into an mx:html element, then attempting to get the content height in order to determine if I should hide the vertical scrollbar or not. However, when using contentHeight it seems to return the height of the previous state of the element, rather than the one just set.
This is the code to fetch the html page
var htmlPageRequest:URLRequest = new URLRequest(url);
htmlPageRequest.method = URLRequestMethod.GET; //set request's html request method to GET
htmlPageLoader.addEventListener(Event.COMPLETE, onHtmlLoaded); //listen for page load
htmlPageLoader.load(htmlPageRequest);//when loaded continue logic in new function
This is the function that is run when the page request is complete
private function onHtmlLoaded(e:Event):void { //logic after html page has loaded
HtmlElement.data = htmlPageLoader.data; //set content
//determine if vscroll bar should be visible
if(HtmlElement.contentHeight > HtmlElement.height) {
scrollbar.visible = true;
}
else {
scrollbar.visible = false;
}
trace(HtmlElement.height);
trace(HTMLELEMENT.contentHeight);
}
I have realised the solution to the problem:
htmlElement.data = htmlPageLoader.data;
Rendering the HTML takes a certain amount of time - the contentHeight is being accessed before the page has actually rendered, causing the previous value to be returned.
In order to fix this, I added an event listener for (htmlRender) in order to not access contentHeight until the rendering is complete.
private function onHtmlLoaded(e:Event):void { //logic after html page has loaded
htmlElement.addEventListener(Event.HTML_RENDER, onHtmlRendered); //once the html has rendered, move on
htmlElement.data = htmlPageLoader.data; //render content
}
private function onHtmlRendered(e:Event):void { //logic for after the page has rendered
//if the content of the HTML element is bigger than the box, show the scrollbar
if(htmlElement.contentHeight > htmlElement.height) {
scrollbar.visible = true;
}
else {
scrollbar.visible = false;
}
}
I am assuming that you are using a URLLoader (htmlPageLoader) instance here to load the webpage into the mx:HTML element, which may not be actually required.
The mx:HTML component actually provides an inbuilt way to load an webpage into itself. This can be done using the location property of the mx:HTML class. It expects a simple string which could be the URL of your webpage you are trying to load.
Once the webpage is loaded, the Event.COMPLETE method is fired, within which you should be able to get your content height properly. So please try the following code:
htmlElement.addEventListener(Event.COMPLETE, onHtmlLoaded);
htmlElement.location = "your URL goes here";
private function onHtmlLoaded(e:Event):void
{
htmlElement.removeEventListener(Event.COMPLETE, onHtmlLoaded);
trace(htmlElement.contentHeight);
}
I've tried the above with a couple of URL's and it seems to be working fine. Also, I took the liberty of using camel case naming convention for htmlElement. It's just best practice.
Hope this helps. Cheers.

How can I import opening component at default package?

There is a button in opening component(welcome page) and it is invisible at the beginning. When user pass to another component, the button is supposed to be visible. However I cannot reach the property.
What is the way of importing opening component at (default package)?
this is the button:
<s:SWFLoader id="btnRepr" x="1790" y="1008.45" source="#Embed('Components/Starter/Assets/Buttons/ButtonReport.swf')" click="ShowReportPage" visible="false"/>
and this is the part I change visible to true:
btnRepr.visible = true;//Access of undefined property 'btnRepr'
Supposed that in your SWFComponent you have your SWFLoader :
<s:SWFLoader id="btnRepr" source="#Embed('ButtonReport.swf')" visible="false"/>
and you have another component called BTNComponent where you have a simple button which will show the SWF loaded in the SWFComponent's instance called swf_component, so you can do like this :
<s:Button click="button_clickHandler(event)"/>
and
protected function button_clickHandler(event:MouseEvent):void
{
mx.core.FlexGlobals.topLevelApplication.swf_component.btnRepr.visible = true;
}
Of course this is just a very simple and limited example if how you can do what you are looking for, you should improve it according to your specific needs ...
Edit :
Supposed that my two components are in MyComponents package, then to create their instances I did :
import MyComponents.*;
public var swf_component:SWFComponent;
public var btn_component:BTNComponent;
then inside the application's creation complete event handler, for example, I added :
swf_component = new SWFComponent();
addElement(swf_component);
btn_component = new BTNComponent();
addElement(btn_component);
then when the button inside the btn_component is clicked, the SWF inside the swf_component` is set visible.
Hope that can help.

AS3Eval library is complaining about "Variable compile is not defined"

I'm working with FlashBuilder 4.6 and using AS3Eval v0.3 library from: http://eval.hurlant.com/
The library is fully working in one of my Flex 4.6.0 projects but not in the other (same library linkage "Merge into code" of EvalES4.swc library).
In the first project following code works:
private var compiler:CompiledESC = new CompiledESC;
public function compile(code: String) : ByteArray {
return compiler.eval(code);
}
In the other project, it fails with:
ReferenceError: Error #1065: Variable compile is not defined.
The error is referring to following line in the AS3Eval library (that EvalES4.swc file)
var compile:Function = getDefinitionByName("ESC::compile") as Function;
Looks like the library has problem to fully load Tamarin ESC in the other project.
I've checked that both projects (they are using the same library... but still checked) load the Tamarin ESC successfully via
// inside CompiledESC.as
private function loadESC():void {
var a:Array = [
new debug_abc as ByteArray,
new util_abc as ByteArray,
new bytes_tamarin_abc as ByteArray,
new util_tamarin_abc as ByteArray,
new lex_char_abc as ByteArray,
new lex_scan_abc as ByteArray,
new lex_token_abc as ByteArray,
new ast_abc as ByteArray,
new parse_abc as ByteArray,
new asm_abc as ByteArray,
new abc_abc as ByteArray,
new emit_abc as ByteArray,
new cogen_abc as ByteArray,
new cogen_stmt_abc as ByteArray,
new cogen_expr_abc as ByteArray,
new esc_core_abc as ByteArray,
new eval_support_abc as ByteArray,
new esc_env_abc as ByteArray,
]
ByteLoader.loadBytes(a, true);
}
These ByteArray classes are embedded inside the SWC using [Embed] (looking through the library code) and all ByteArrays are in both cases initialized and loaded via ByteLoader.
So far, I have not found any clue why compiling is working for my first project but not for the other. Does anybody has similar experiences or some hints what may cause the problem?
Best,
Jakub
Ha!
I was too desperate, solution found.
It appears, that CompiledESC cannot be used in the same frame where it was created.
So in the other words, something like this won't work:
public function compile(code: String) : ByteArray {
var compiler:CompiledESC = new CompiledESC();
return compiler.eval(code);
}
But following code will work (application loads, initializes CompileESC and then user clicks the RUN! button, which happens in different frame from the one where CompileESC was created):
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
>
<fx:Script>
<![CDATA[
import com.hurlant.eval.CompiledESC;
import mx.events.FlexEvent;
private var compiler:CompiledESC = new CompiledESC();
protected function button1_clickHandler(event:MouseEvent):void
{
compiler.eval("trace(\"hello!\")");
}
]]>
</fx:Script>
<mx:Button label="RUN!" click="button1_clickHandler(event)" />
</s:Application>
I do not know exactly why, but I suspect it has something to do with the way Flash is loading its bytecode. When you try to insert some code into VM and use it in the same frame you're asking for troubles because your code has just not been loaded yet. You have to "yield" the thread and wait for another frame, somewhere in-between Tamarin ESC code gets loaded.
Note that the same applies for compiled code being loaded via ByteBuffer by you! Whenever you do something like
ByteLoader.load(compiler.eval(myAS3Code));
Do not expect that myAS3Code will be executed right away. Again, the code will be loaded whenever you "yield" the thread and let VM to truly load your code.
Hope this helps someone in the same situation.
Best,
Jakub
You should check if the permissions are the same of first project. You're merging (if I understood right) a library from outside, is this allowed?

How to access variables of the 'main' SWF from a loaded SWF by SWFLoader?

I'm working on a website built in Flex, but the SWF file after compiling is very large. The websites has multiple pages.
So I thought to create a new MXML project for every new page and load it with SWFLoader.
I've found this example:
public function extSwfLoaded(evt:Event):void {
var sysmgr:SystemManager = (extSwf.content as SystemManager);
sysmgr.addEventListener(FlexEvent.APPLICATION_COMPLETE, function(event:FlexEvent):void {
var sysmgr:SystemManager = (event.currentTarget as SystemManager);
var swfApp:Application = (sysmgr.application as Application);
}
});
public function gotoPage(page:String):void {
extSwf.addEventListener(Event.INIT, extSwfLoaded);
var now:Date = new Date();
switch(page) {
case "register":
openedPage = "register";
extSwf.load('modules/register.swf?anticache=' + now.getTime());
break;
}
}
And in the MXML:
<mx:SWFLoader id="extSwf" complete="extSwfLoaded(event)" width="100%" />
<s:Label text="Register" useHandCursor="true" buttonMode="true" click="gotoPage('register')" />
This works perfect. The content of modules/register.swf is showed at the place of the extSwf SWFLoader.
But: I've no idea how to interact with the 'main' SWF and the loaded SWF file.
I have some global variables that I want to send to every loaded SWF file
(and some variables that I want to send from the loaded SWF file to the 'main' SWF file).
A website said that I can send these variables by loading modules/register.swf?var1=hi&var2=hello, but someone who can see the HTTP headers (for example with Live HTTP Headers in Firefox) can see all these variables.
So, is it possible to load a SWF file and send them some variables? And when I have a new global variable, I don't have to open and edit and recompile every MXML project?
Thank you very much!
It looks like this can show the variables of my 'main' MXML.
import mx.controls.Alert;
import mx.core.FlexGlobals;
Alert.show(FlexGlobals.topLevelApplication.myvar);
And for using public functions:
FlexGlobals.topLevelApplication.myFunction();
I just needed the right keywords (top level application) to search for it on the internet.

How to run an external SWF inside a Flex Application?

EDIT: Due to the answer I change the code posted. I've added the Security.allowDomain("*") line and that line throws me an error. So, how can that be made?
I want to run an Action Script 3.0 Application into a Flex Application. To do this I've done the following:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication windowComplete="loadSwfApplication()" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function loadSwfApplication()
{
// The next line throws me an error.
Security.allowDomain("*");
var urlRequest:URLRequest = new URLRequest("path/to/the/application.swf");
swfLoader.addEventListener(Event.COMPLETE, loadComplete);
swfLoader.load(urlRequest);
}
private function loadComplete(completeEvent:Event)
{
var swfApplication:* = completeEvent.target.content;
swfApplication.init(); // this is a Function that I made it in the Root class of swfApplication
}
]]>
</mx:Script>
<mx:SWFLoader id="sfwLoader"/>
</mx:WindowedApplication>
The problem is that in the calling of swfApplication.init(); the AIR Player throws me an exception:
Security sandbox violation: caller file:///path/to/the/application.swf cannot access Stage owned by app:/SWFApplicationLoader.swf.
This is because somewhere in application.swf I use the stage like this:
if (root.stage != null)
root.stage.addEventListener(Event.REMOVED, someFunction);
root.stage.stageFocusRect = false;
How can I load this swf application and USE the stage without any problems?
You can try to load your SWF temporarily into a ByteArray and then load it with your SWFLoader.
Don't forget to set allowCodeImport to true since your SWF has as code inside.
Of course be sure that your loaded swf is secure enough for your application since it will have access at all your property.
private function loadSwfApplication():void {
// load the file with URLLoader into a bytearray
var loader:URLLoader=new URLLoader();
// binary format since it a SWF
loader.dataFormat=URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, onSWFLoaded);
//load the file
loader.load(new URLRequest("path/to/the/application.swf"));
}
private function onSWFLoaded(e:Event):void {
// remove the event
var loader:URLLoader=URLLoader(e.target);
loader.removeEventListener(Event.COMPLETE, onSWFLoaded);
// add an Application context and allow bytecode execution
var context:LoaderContext=new LoaderContext();
context.allowCodeImport=true;
// set the new context on SWFLoader
sfwLoader.loaderContext = context;
sfwLoader.addEventListener(Event.COMPLETE, loadComplete);
// load the data from the bytearray
sfwLoader.load(loader.data);
}
// your load complete function
private function loadComplete(completeEvent:Event):void {
var swfApplication:* = completeEvent.target.content;
swfApplication.init(); // this is a Function that I made it in the Root
// class of swfApplication
}
If they are being loaded from different domains you are going to have to add a security exception - http://livedocs.adobe.com/flex/3/html/help.html?content=05B_Security_08.html
if its being run locally youre probably going to have to add them to the list of trusted files or folders in the settings manager - http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html#117502
Assuming that the external SWF is also in the application directory, you could try loading it using the app:/ scheme:
var urlRequest:URLRequest = new URLRequest("app:/path/application.swf");
That may put it into the same security context as the main application.
One thing you may want to consider is that if you are trying to run a SWF from inside your application directory in AIR, AIR restricts execution of files. If you copy the file to a temp file and the run it (along with allowLoadBytesCodeExecution set to true) then it works.
var file:File = File.applicationDirectory.resolvePath("myFile.swf");
this.tmpFile = File.createTempDirectory().resolvePath("myFile.swf");
file.copyTo(this.tmpFile);
imagePreview.loaderContext = lc;
imagePreview.source = tmpFile.url;
it won't work for Flex Projectors.
Only we use SWFLoader and LocalConnection because they can communicate between external swf and main swf. Thanks for support!
Can you read my tutorial from Adobe's Forum
It is very better than MovieClip or Object-Callers
Thank for resolved solution :)
Best regards, Jens