From 68221a38daa30266d6d0373c875ece8552541754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Katzer?= Date: Fri, 9 Aug 2013 18:58:47 +0200 Subject: [PATCH] Print from iOS devices to AirPrint compatible printers --- plugin.xml | 31 +++++++++ src/ios/CDVPrinter.h | 38 +++++++++++ src/ios/CDVPrinter.m | 153 +++++++++++++++++++++++++++++++++++++++++++ www/printer.js | 86 ++++++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 plugin.xml create mode 100755 src/ios/CDVPrinter.h create mode 100755 src/ios/CDVPrinter.m create mode 100755 www/printer.js diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..8c3063f --- /dev/null +++ b/plugin.xml @@ -0,0 +1,31 @@ + + + + + Printer + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ios/CDVPrinter.h b/src/ios/CDVPrinter.h new file mode 100755 index 0000000..0b67ee6 --- /dev/null +++ b/src/ios/CDVPrinter.h @@ -0,0 +1,38 @@ +// +// PrintPlugin.h +// Print Plugin +// +// Created by Ian Tipton (github.com/itip) on 02/07/2011. +// Copyright 2011 Ian Tipton. All rights reserved. +// MIT licensed +// + +#import +#import + + +@interface CDVPrinter : CDVPlugin { + NSString* successCallback; + NSString* failCallback; + NSString* printHTML; + + //Options + NSInteger dialogLeftPos; + NSInteger dialogTopPos; +} + +@property (nonatomic, copy) NSString* successCallback; +@property (nonatomic, copy) NSString* failCallback; +@property (nonatomic, copy) NSString* printHTML; + +//Print Settings +@property NSInteger dialogLeftPos; +@property NSInteger dialogTopPos; + +//Print HTML +- (void) print:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; + +//Find out whether printing is supported on this platform. +- (void) isPrintingAvailable:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; + +@end diff --git a/src/ios/CDVPrinter.m b/src/ios/CDVPrinter.m new file mode 100755 index 0000000..10f46a7 --- /dev/null +++ b/src/ios/CDVPrinter.m @@ -0,0 +1,153 @@ +// +// PrintPlugin.m +// Print Plugin +// +// Created by Ian Tipton (github.com/itip) on 02/07/2011. +// Copyright 2011 Ian Tipton. All rights reserved. +// MIT licensed +// + +#import "CDVPrinter.h" + +@interface CDVPrinter (Private) +-(void) doPrint; +-(void) callbackWithFuntion:(NSString *)function withData:(NSString *)value; +- (BOOL) isPrintServiceAvailable; +@end + +@implementation CDVPrinter + +@synthesize successCallback, failCallback, printHTML, dialogTopPos, dialogLeftPos; + +/* + Is printing available. Callback returns true/false if printing is available/unavailable. + */ +- (void) isPrintingAvailable:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options{ + NSUInteger argc = [arguments count]; + + if (argc < 1) { + return; + } + + + NSString *callBackFunction = [arguments objectAtIndex:0]; + [self callbackWithFuntion:callBackFunction withData: + [NSString stringWithFormat:@"{available: %@}", ([self isPrintServiceAvailable] ? @"true" : @"false")]]; + +} + +- (void) print:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options{ + NSUInteger argc = [arguments count]; + + if (argc < 1) { + return; + } + self.printHTML = [arguments objectAtIndex:0]; + + if (argc >= 2){ + self.successCallback = [arguments objectAtIndex:1]; + } + + if (argc >= 3){ + self.failCallback = [arguments objectAtIndex:2]; + } + + if (argc >= 4){ + self.dialogLeftPos = [[arguments objectAtIndex:3] intValue]; + } + + if (argc >= 5){ + self.dialogTopPos = [[arguments objectAtIndex:4] intValue]; + } + + + + + [self doPrint]; + +} + +- (void) doPrint{ + if (![self isPrintServiceAvailable]){ + [self callbackWithFuntion:self.failCallback withData: @"{success: false, available: false}"]; + + return; + } + + UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController]; + + if (!controller){ + return; + } + + if ([UIPrintInteractionController isPrintingAvailable]){ + //Set the priner settings + UIPrintInfo *printInfo = [UIPrintInfo printInfo]; + printInfo.outputType = UIPrintInfoOutputGeneral; + controller.printInfo = printInfo; + controller.showsPageRange = YES; + + + //Set the base URL to be the www directory. + NSString *dbFilePath = [[NSBundle mainBundle] pathForResource:@"www" ofType:nil ]; + NSURL *baseURL = [NSURL fileURLWithPath:dbFilePath]; + + //Load page into a webview and use its formatter to print the page + UIWebView *webViewPrint = [[UIWebView alloc] init]; + [webViewPrint loadHTMLString:printHTML baseURL:baseURL]; + + //Get formatter for web (note: margin not required - done in web page) + UIViewPrintFormatter *viewFormatter = [webViewPrint viewPrintFormatter]; + controller.printFormatter = viewFormatter; + controller.showsPageRange = YES; + + + void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) = + ^(UIPrintInteractionController *printController, BOOL completed, NSError *error) { + if (!completed || error) { + [self callbackWithFuntion:self.failCallback withData: + [NSString stringWithFormat:@"{success: false, available: true, error: \"%@\"}", error.localizedDescription]]; + + } + else{ + [self callbackWithFuntion:self.successCallback withData: @"{success: true, available: true}"]; + } + }; + + /* + If iPad, and if button offsets passed, then show dilalog originating from offset + */ + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && + dialogTopPos != 0 && dialogLeftPos != 0) { + [controller presentFromRect:CGRectMake(self.dialogLeftPos, self.dialogTopPos, 0, 0) inView:self.webView animated:YES completionHandler:completionHandler]; + } else { + [controller presentAnimated:YES completionHandler:completionHandler]; + } + } +} + +-(BOOL) isPrintServiceAvailable{ + + Class myClass = NSClassFromString(@"UIPrintInteractionController"); + if (myClass) { + UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController]; + return (controller != nil) && [UIPrintInteractionController isPrintingAvailable]; + } + + + return NO; +} + +#pragma mark - +#pragma mark Return messages + +-(void) callbackWithFuntion:(NSString *)function withData:(NSString *)value{ + if (!function || [@"" isEqualToString:function]){ + return; + } + + NSString* jsCallBack = [NSString stringWithFormat:@"%@(%@);", function, value]; + [self writeJavascript: jsCallBack]; +} + +@end diff --git a/www/printer.js b/www/printer.js new file mode 100755 index 0000000..41005a5 --- /dev/null +++ b/www/printer.js @@ -0,0 +1,86 @@ + +/** + * Printer Plugin + * Copyright (c) 2011 Ian Tipton (github.com/itip) + * MIT licensed + */ + +var PrintPlugin = function() { + +} + +PrintPlugin.prototype.callbackMap = {}; +PrintPlugin.prototype.callbackIdx = 0; + +/* + print - html string or DOM node (if latter, innerHTML is used to get the contents). REQUIRED. + success - callback function called if print successful. {success: true} + fail - callback function called if print unsuccessful. If print fails, {error: reason}. If printing not available: {available: false} + options - {dialogOffset:{left: 0, right: 0}}. Position of popup dialog (iPad only). + */ +PrintPlugin.prototype.print = function(printHTML, success, fail, options) { + if (typeof printHTML != 'string'){ + console.log("Print function requires an HTML string. Not an object"); + return; + } + + + //var printHTML = ""; + + var dialogLeftPos = 0; + var dialogTopPos = 0; + + + if (options){ + if (options.dialogOffset){ + if (options.dialogOffset.left){ + dialogLeftPos = options.dialogOffset.left; + if (isNaN(dialogLeftPos)){ + dialogLeftPos = 0; + } + } + if (options.dialogOffset.top){ + dialogTopPos = options.dialogOffset.top; + if (isNaN(dialogTopPos)){ + dialogTopPos = 0; + } + } + } + } + + var key = 'print' + this.callbackIdx++; + window.plugins.printPlugin.callbackMap[key] = { + success: function(result) { + delete window.plugins.printPlugin.callbackMap[key]; + success(result); + }, + fail: function(result) { + delete window.plugins.printPlugin.callbackMap[key]; + fail(result); + } + }; + + var callbackPrefix = 'window.plugins.printPlugin.callbackMap.' + key; + return cordova.exec("PrintPlugin.print", printHTML, callbackPrefix + '.success', callbackPrefix + '.fail', dialogLeftPos, dialogTopPos); +}; + +/* + * Callback function returns {available: true/false} + */ +PrintPlugin.prototype.isPrintingAvailable = function(callback) { + var key = 'isPrintingAvailable' + this.callbackIdx++; + window.plugins.printPlugin.callbackMap[key] = function(result) { + delete window.plugins.printPlugin.callbackMap[key]; + callback(result); + }; + + var callbackName = 'window.plugins.printPlugin.callbackMap.' + key; + cordova.exec("PrintPlugin.isPrintingAvailable", callbackName); +}; + +cordova.addConstructor(function() { + if(!window.plugins){ + window.plugins = {}; + } + window.plugins.printPlugin = new PrintPlugin(); +}); \ No newline at end of file