i'm pulling my hair out. need to print html generated invoices from a distant server, using
the print class, event if bitmap is set as false, will render the invoice a bitmap. at least the text is blurry and not usable. alivepdf could be a solution but i need to print straight, not save the pdf locally. i don't even understand, giving the fact this print class sucks badly, flex won't allow a simple javascript print function from the remote page.
i beg for some help here !
thank you
Why don't you use the browser to print?
Here's an example:
Put this in your index.html template:
<script language="JavaScript">
function printPage(htmlPage)
{
var w = window.open("about:blank");
w.document.write(htmlPage);
w.print();
w.close();
}
</script>
Put this in your Flex Project. What you're doing is checking to see if you have access to ExternalInterface to have access to the browser. Then you're going to use the ExternalInterface static method of "call" to call the javascript:
import mx.controls.Alert;
import flash.external.ExternalInterface;
public static function PrintHtmlPage(pHtmlPage:String):void
{
if (ExternalInterface.available)
{
try
{
ExternalInterface.call("printPage",pHtmlPage);
}
catch (error:SecurityError) { Alert.show("Security Error"); }
catch (error:Error) { Alert.show("Error");}
}
else { Alert.show("ExternalInterface not avalible");}
}
Now the user can print clean html from their browser!
http://cookbooks.adobe.com/post_How_to_print_in_Flex_using_browser_capabilities-11468.html
EDIT:
If you are using AIR and need to do this, you can try using AlivePDF and following this tutorial:
use alivepdf (http://alivepdf.bytearray.org/), and look at this tutorial for printing from AIR (http://murrayhopkins.wordpress.com/2011/01/07/using-alivepdf-to-print-from-air-javascript-via-actionscript3-part-1/)
parse the HTML into Spark components, and then add them as a Sprite, then use printAsBitmap = true in your option, and FlexPrintJob
Related
In my AIR application in Flex 4, I use mx:HTML, and when I navigate to a location like this
html.location = 'http://www.somesite.com';
But, some websites have "alert" function in javascript like this :
alert('hello world!');
and AIR show the message in a box...
I just want to remove, or ignore these messages, but I don't know how...
I think the solution is to extend the HTMLLoader class, but my experience in Flex is too poor..
Someone can help me ?
Thank in advance :)
This is the best thing I could find:
http://help.adobe.com/en_US/AIR/1.5/devappshtml/WS5b3ccc516d4fbf351e63e3d118666ade46-7e74.html#WS5b3ccc516d4fbf351e63e3d118666ade46-7e72
It looks like you can extend the HTMLLoader as you suggested and override javascript callbacks. I haven't tried this so I'm not sure but it's worth giving it a whirl.
After debug and test, I found that the HTMLLoader has a property window. This window is like javascript DOM window.
You can use following code to disable alert.
public class MyHTMLLoader extends HTMLLoader
{
override public function MyHTMLLoader()
{
super();
this.addEventListener(Event.HTML_DOM_INITIALIZE, htmlDomInitializedHandler);
}
protected function htmlDomInitializedHandler(event:Event):void
{
window.alert = function(){};
}
}
And modify your HTML component property htmlLoaderFactory to ...
<mx:HTML htmlLoaderFactory="{new ClassFactory(MyHTMLLoader)}" ...
Hope this will help you.
I have the following AS code.I have noticed that if an Application i s using the webcamera then it cannot be used by any secondary applications until unless the primary application is closed.
My question is that from the following code 1.can we capture that condition
2.If no camera is detected how to give the alert since it is an AS code
EDIT:
Filename is cldAS.as
Now how to call cldAS() from any.mxml file .Some example would be appreciated
package org.com
{
import flash.display.Sprite;
import flash.media.*;
import flash.net.*;
public class cldAS extends Sprite
{
public function cldAS()
{
var cam:Camera = Camera.getCamera();
if(cam != null)
{
cam.setMode(640, 480, 30);
var video:Video = new Video(300, 450);
video.attachCamera(cam);
addChild(video);
}
else
{
trace("No Camera Detected");
//How to give an alert here
}
}
}
}
Alert.show("You don't seem to have a webcam.");
instead of
trace(...) ?
Alert is available in Flex only , in AS3 you should really implement your own solution, on the other hand , since Alert is a Javascript function , you could also use ExternalInterface to call it.
As far as implementing your own solution is concerned, at the minimum you need a TextField to display your message, which text you could provide by sending a CustomEvent with a message property that will simply take a String. It wouldn't take too much work to create your own Alert class.It would sit on top of your App , you could toggle visibility when receiving a CustomEvent and have a Close button to hide it.
You should be able to call your AS3 class within script tags , other than that I'll leave a more detailed answer to Flex experts. I'm not sure if you can add a Sprite directly into Flex , for all I remember an object in Flex must inherit from UIComponent in order to be added to the stage but check with the other guys here, I haven't used Flex in quite some time...
<mx:Script>
import org.com.cldAS;
public cld:cldAS = new cldAS();
</mx:Script>
I'm using AlivePDF to create a PDF file, then save it to the desktop. I can then use an HTMLLoader to display my lovely PDF file.
Now, the print button in Adobe Reader works fine. However, there will be young children using the app, so I'd like to have a big "Print" button right above it.
I figured I could just start up a print job and feed it my HTMLLoader. This won't work because the HTML loader rasterizes the content.
Any suggestions?
One answer I have found in order to solve this problem is called Cross-scripting PDF content. The idea is that a PDF can have embedded JavaScript, which can be called from the JavaScript within the HTML page "housing" said PDF (object tag only, no embed).
This site was of particular help. I had to simplify the JavaScript from that page down quite a bit. I kept getting syntax errors.
I also need my program to generate the PDF and the HTML content. I cannot ship a single PDF with embedded JS and an HTML file pointing to it. They need to be dynamically generated by the user. Here is a basic rundown:
private function printText(text:String):void
{
var p:PDF=new PDF(Orientation.PORTRAIT, Unit.MM, Size.LETTER);
p.addPage();
p.addText(text, 100, 100);
p.addJavaScript(this.getJavascript());
var f:FileStream=new FileStream();
var html:File=File.desktopDirectory.resolvePath("exported.html");
f.open(html, FileMode.WRITE);
f.writeUTF(this.getHtml());
f.close();
var file:File=File.desktopDirectory.resolvePath("exported.pdf");
f.open(file, FileMode.WRITE);
var bytes:ByteArray=p.save(Method.LOCAL);
f.writeBytes(bytes);
f.close();
Now that we have our two files, HTML and PDF, we can view the PDF, and create a giant purple print button for our younger / sight-impared users.
if (HTMLLoader.pdfCapability == HTMLPDFCapability.STATUS_OK)
{
var win:PrintTitleWindow; //the window w/giant button
var htmlLoader:HTMLLoader=new HTMLLoader();
var url:URLRequest=new URLRequest(html.url);
htmlLoader.width=880;
htmlLoader.height=(appHeight - 150); //i figure out the height elsewhere
htmlLoader.load(url);
var holder:UIComponent=new UIComponent();
holder.addChild(htmlLoader);
win=PrintTitleWindow(PopUpManager.createPopUp(mainWindow, PrintTitleWindow, true));
win.width=900;
win.height=(appHeight - 50);
win.addChild(holder);
win.addContent(htmlLoader);
PopUpManager.centerPopUp(win);
}
}
Here is the JS and HTML I used. I'm adding these in here for laughs. I'm sure there is a better way to do this, but I'm tired and it is late.
private function getJavascript():String
{
return 'function myOnMessage(aMessage) { print({ bUI: true, bSilent: false, bShrinkToFit: true }); } function myOnDisclose(cURL,cDocumentURL) { return true; } function myOnError(error, aMessage) { app.alert(error); } var msgHandlerObject = new Object(); msgHandlerObject.onMessage = myOnMessage; msgHandlerObject.onError = myOnError; msgHandlerObject.onDisclose = myOnDisclose; this.hostContainer.messageHandler = msgHandlerObject;';
}
private function getHtml():String
{
return '<html><head><script>function callPdfFunctionFromJavascript(arg) { pdfObject = document.getElementById("PDFObj");pdfObject.postMessage([arg]);}</script></head><body><object id="PDFObj" data="exported.pdf" type="application/pdf" width="100%" height="100%"></object></body></html>';
}
The PrintTitleWindow is a simple title window with the print button on it. The code to print is simple.
myHtmlLoader.window.callPdfFunctionFromJavascript('Print');
Eh Voila! I have a gigantor-print-button like so:
(source: cetola.net)
Hitting that big purple print button is the same as hitting the print icon in the PDF toolbar. The difference for me is that my users, who could be elementary or middle-school kids, won't have to look around for the stupid button.
So, it's a long way around the block. Still, if you need to print and can't rely on that adobe toolbar button, here's your answer :) .
Is there a way for the Flex app to get any information about the HTML document via the ExternalInterface? Can Flex find out if a particular DIV exists, for example?
ExternalInterface is a Javascript interface with the containing page, so anything that is possible in javascript is possible through ExternalInterface, either directly or through functions on the hoast page.
AnnonymousFunctionCall from ExternalInterface
Is there a way for the Flex app to get any information about the HTML document via the ExternalInterface?
Check out JSInterface - JavaScript API for ActionScript 3. Two front page examples are called:
JavaScript'ing Inside Flash
ActionScript'ing Inside HTML
I use this library currently and it is extremely powerful. I asked him (Oleg Galaburda) once whether or not I should use this for simply being able to resize the swf. He said something like "if you only need to do a few in javascript, just stick with ExternalInterface. If you need access to the DOM in ActionScript, use this".
There are hundreds of examples in the svn repository. He's done an awesome job with this thing. It converts JavaScript Objects to ActionScript and back, so you can use full-on classes. It would take a ton of work to rebuild that so it's cross browser and everything. He's done that!
Everything in JSInterface is basically a dynamic class, so you can drill down the DOM easily. Here's some sample methods (in ActionScript):
protected function testCSS():void
{
var styleTag:JSHTMLElement = JSInterface.pushCSS('.text{font-weight:bold;color:#ff00ff;font-size:90;text-decoration:underline;}');
var font:JSHTMLElement = JSInterface.document.createElement('font');
font.innerHTML = 'Hello world!';
font.setAttribute('class', 'text');
font.className = 'text';
JSInterface.document.body.appendChild(font);
trace(styleTag);
}
protected function insertIFrame():void
{
var body:JSDynamic = JSInterface.document.getElementsByTagName('body')[0];
var frame:JSDynamic = JSInterface.document.createElement("iframe");
frame.width = 300;
frame.height = 300;
if (JSInterface.navigator.appName.indexOf('Microsoft')>=0)
{
frame.onreadystatechange = function():void
{
trace(frame.readyState);
};
}
else
{
frame.onload = function():void
{
trace('iFrame loaded');
};
}
frame.src = 'http://actualwave.com';
body.appendChild(frame);
}
The library internally uses ExternalInterface to handle everything. But to serialize/deserialize the DOM to/from ActionScript, that's a ton of work. This library should do the trick.
Hope this helps,
Lance
Responding to another question I explained how ExternalInterface actually works. What you can take from that is a simple "yes".
[edit] some sample code:
var jsFunc:String = 'function () { return document.getElementById("test") != null; }';
var divExists:Boolean = ExternalInterface.call(jsFunc);
should clarify things ...
I'm using a Flash TextField control to display some HTML content inside a Flash presentation to be shown on a large touch-screen kiosk. Unfortunately, if any image tag in the displayed HTML content points to a non-existent image, a dialogue is shown with the error message
Error #2044: Unhandled IOErrorEvent:. text=Error #2035: URL Not Found.
I am trying to avoid having that dialogue pop up. The solution for loading content through a loader class is to catch IOErrorEvent.IO_ERROR, but I've tried listening for that on the TextField, on stage, Main and loaderInfo to no avail. I've tried wrapping the whole thing in a try-catch, and that also doesn't work.
Here's the simplified code I'm using to find solutions:
package {
import flash.display.Sprite;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
var html:TextField = new TextField();
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img src=\"foo.jpg\" />";
addChild(html);
}
}
}
Edit: And here's the entire working code.
For dynamic content and so forth, of course, you would need a list of images and a function to generate handlers, etc.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
var html:TextField = new TextField();
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img id=\"image\" src=\"foo.jpg\" />";
var loader:Loader = html.getImageReference("image") as Loader;
if(loader){
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void {
trace("Error loading foo.jpg!");
});
}
addChild(html);
}
}
}
You can add ID's to images
html.htmlText = "Bogus image: <img src=\"foo.jpg\" id="image" />";
And then setup IOErrorEvent handler to each image in HTML
var loader:Loader = html.getImageReference("image") as Loader;
if(loader){
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void{});
}
This is a cool problem.
I have two suggestions.
1) Don't use TextField. I'm guessing that you developed in Flash before Flex, like me. You may already know this, but it took me awhile to find out: The TextField object isn't meant to be used for regular use in Flex. Check this out from the Flex3 language ref:
The TextField class is used to create
display objects for text display and
input. All dynamic and input text
fields in a SWF file are instances of
the TextField class. You can use the
TextField class to perform low-level
text rendering. However, in Flex, you
typically use the Label, Text,
TextArea, and TextInput controls to
process text.
Obviously, there's nothing wrong with using TextField, but I've found that when I'm trying to figure out tricky problems, it's really helpful to do as much 'by the book' as I can to remove unknowns (as much as possible, at least).
2) I think I'd try either extending the Text component, or else creating a new component based on Text. In this component I'd add logic to load and insert images into the TextField object. That way, you could easily build and validate the string to insert into the TextField object prior to inserting it into the TextField.
If you get this working, please post - I could use it myself. :)
If there's a way for you to use the new FTE/TLF components, do so. Adobe is basically turning its back on the old TextField API, and this same error is a reason that I had to abandon many projects and components in the past. This error is thrown and basically cannot be caught. One of the worst aspects of Flash work in my opinion.
TLF addresses these problems and is SO much easier to work with. What would take days of experimentation in the old API now takes only a few hours. I've built a few rich text editors on the new API and it is SO very nice to use. You'll be glad you did :)
I was able to detect when an image has loaded, but I think I'll follow the TLF advice. anyways if you need to know, you have to implement an enter_frame event listener on the Loader and check for the contentInfo on the bytes property the Lenght, if the image hasn't load the length is 0xffffffff, if the image has loaded the length is the size of the file, and if there is an error the bytes properties es NULL.
var html:TextField = new TextField();
html.width=388.95;
html.height=400;
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img id='image' src='foo.jpg'/>";
var loader:Loader = html.getImageReference("image") as Loader;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHan);
function completeHan(e:Event){
addChild(html);
}
This will work..
This is a problem I'm also dealing with: it's a real annoyance. I'd really like to be able to catch all the errors. I assumed you could say...
stage.addEventListener(IOError.IO_ERROR, myErrorHandler);
...but that doesn't seem to work, as you've pointed out.
Perhaps you can check to make sure the kiosk's flash player isn't the debug version. I don't think that the release version throws the dialogs (could be wrong).
Impossible! Same problem if you use the Loader to load images that doesnt exists! Flex is a framework and the Image class uses this flash Loader object but with plenty of lines of code (check out the source of SwfLoader...).
You can check your image URL before set the htmlText property or you can create your own component to display Text and Images..
I can't believe this simple & stupid bug is not still fixed by Adobe!