OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 cr.define('cloudprint', function() { |
| 6 'use strict'; |
| 7 |
| 8 /** |
| 9 * API to the Google Cloud Print service. |
| 10 * |
| 11 * @param {string} baseUrl Base part of the Google Cloud Print service URL |
| 12 * with no trailing slash. For example, |
| 13 * 'https://www.google.com/cloudprint'. |
| 14 * @constructor |
| 15 * @extends {cr.EventTarget} |
| 16 */ |
| 17 function CloudPrintInterface(baseUrl) { |
| 18 /** |
| 19 * The base URL of the Google Cloud Print API. |
| 20 * @type {string} |
| 21 * @private |
| 22 */ |
| 23 this.baseURL_ = baseUrl; |
| 24 |
| 25 /** |
| 26 * Last received XSRF token. Sent as a parameter in every request. |
| 27 * @type {string} |
| 28 * @private |
| 29 */ |
| 30 this.xsrfToken_ = ''; |
| 31 }; |
| 32 |
| 33 /** |
| 34 * Enumeration of events dispatched. |
| 35 * @enum {string} |
| 36 */ |
| 37 CloudPrintInterface.Event = { |
| 38 ERROR: 'cloudprint.CloudPrintInterface.ERROR', |
| 39 PRINTER_DONE: 'cloudprint.CloudPrintInterface.PRINTER_DONE', |
| 40 SEARCH_DONE: 'cloudprint.CloudPrintInterface.SEARCH_DONE', |
| 41 SUBMIT_DONE: 'cloudprint.CloudPrintInterface.SUBMIT_DONE' |
| 42 }; |
| 43 |
| 44 /** |
| 45 * Content type header value for a URL encoded HTTP request. |
| 46 * @type {string} |
| 47 * @private |
| 48 */ |
| 49 CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_ = |
| 50 'application/x-www-form-urlencoded'; |
| 51 |
| 52 /** |
| 53 * Content type header value for a multipart HTTP request. |
| 54 * @type {string} |
| 55 * @private |
| 56 */ |
| 57 CloudPrintInterface.MULTIPART_CONTENT_TYPE_ = |
| 58 'multipart/form-data; boundary=----CloudPrintFormBoundaryjc9wuprokl8i'; |
| 59 |
| 60 CloudPrintInterface.prototype = { |
| 61 __proto__: cr.EventTarget.prototype, |
| 62 |
| 63 /** |
| 64 * Sends a Google Cloud Print search API request. |
| 65 * @param {boolean} isRecent Whether to search for only recently used |
| 66 * printers. |
| 67 */ |
| 68 search: function(isRecent) { |
| 69 var params = {}; |
| 70 if (isRecent) { |
| 71 params['q'] = '^recent'; |
| 72 } |
| 73 this.sendRequest_('GET', 'search', params, null, this.onSearchDone_); |
| 74 }, |
| 75 |
| 76 /** |
| 77 * Sends a Google Cloud Print submit API request. |
| 78 * @param {string} body Body of the HTTP post request to send. |
| 79 */ |
| 80 submit: function(body) { |
| 81 this.sendRequest_('POST', 'submit', null, body, this.onSubmitDone_); |
| 82 }, |
| 83 |
| 84 /** |
| 85 * Sends a Google Cloud Print printer API request. |
| 86 * @param {string} printerId ID of the printer to lookup. |
| 87 */ |
| 88 printer: function(printerId) { |
| 89 var params = {'printerid': printerId}; |
| 90 this.sendRequest_('GET', 'printer', params, null, this.onPrinterDone_); |
| 91 }, |
| 92 |
| 93 /** |
| 94 * Creates an object that represents a Google Cloud Print print ticket. |
| 95 * @param {print_preview.Destination!} destination Destination to print to. |
| 96 * @param {print_preview.PrintTicketStore!} printTicketStore Used to create |
| 97 * the state of the print ticket. |
| 98 * @return {object} Google Cloud Print print ticket. |
| 99 */ |
| 100 createPrintTicket: function(destination, printTicketStore) { |
| 101 if (destination.isLocal) { |
| 102 throw Error( |
| 103 'Trying to create a Google Cloud Print print ticket for a local ' + |
| 104 'destination'); |
| 105 } |
| 106 if (!destination.capabilities) { |
| 107 throw Error( |
| 108 'Trying to create a Google Cloud Print print ticket for a ' + |
| 109 'destination with no print capabilities'); |
| 110 } |
| 111 |
| 112 var ticketItems = []; |
| 113 |
| 114 if (destination.capabilities.collateCapability) { |
| 115 var collateCap = destination.capabilities.collateCapability; |
| 116 var ticketItem = { |
| 117 'name': collateCap.id, |
| 118 'type': collateCap.type, |
| 119 'options': [{'name': printTicketStore.isCollateEnabled() ? |
| 120 collateCap.collateOption : collateCap.noCollateOption}] |
| 121 }; |
| 122 ticketItems.push(ticketItem); |
| 123 } |
| 124 |
| 125 if (destination.capabilities.colorCapability) { |
| 126 var colorCap = destination.capabilities.colorCapability; |
| 127 var ticketItem = { |
| 128 'name': colorCap.id, |
| 129 'type': colorCap.type, |
| 130 'options': [{'name': printTicketStore.isColorEnabled() ? |
| 131 colorCap.colorOption : colorCap.bwOption}] |
| 132 }; |
| 133 ticketItems.push(ticketItem); |
| 134 } |
| 135 |
| 136 if (destination.capabilities.copiesCapability) { |
| 137 var copiesCap = destination.capabilities.copiesCapability; |
| 138 var ticketItem = { |
| 139 'name': copiesCap.id, |
| 140 'type': copiesCap.type, |
| 141 'value': printTicketStore.getCopies() |
| 142 }; |
| 143 ticketItems.push(ticketItem); |
| 144 } |
| 145 |
| 146 if (destination.capabilities.duplexCapability) { |
| 147 var duplexCap = destination.capabilities.duplexCapability; |
| 148 var ticketItem = { |
| 149 'name': duplexCap.id, |
| 150 'type': duplexCap.type, |
| 151 'options': [{'name': printTicketStore.isDuplexEnabled() ? |
| 152 duplexCap.longEdgeOption : duplexCap.simplexOption}] |
| 153 }; |
| 154 ticketItems.push(ticketItem); |
| 155 } |
| 156 |
| 157 return { |
| 158 'capabilities': ticketItems |
| 159 }; |
| 160 }, |
| 161 |
| 162 /** |
| 163 * Sends a request to the Google Cloud Print API. |
| 164 * @param {string} method HTTP method of the request. |
| 165 * @param {string} action Google Cloud Print action to perform. |
| 166 * @param {!Object} params HTTP parameters to include in the request. |
| 167 * @param {string} body HTTP multi-part encoded body. |
| 168 * @param {function(Object)} successCallback Callback to invoke when request |
| 169 * completes successfully. |
| 170 */ |
| 171 sendRequest_: function(method, action, params, body, successCallback) { |
| 172 if (!this.xsrfToken_) { |
| 173 // TODO Should throw an error if not a read-only action or issue an |
| 174 // xsrf token request. |
| 175 } |
| 176 var url = this.baseURL_ + '/' + action + '?xsrf=' + this.xsrfToken_; |
| 177 |
| 178 if (params) { |
| 179 for (var paramName in params) { |
| 180 url += '&' + paramName + '=' + encodeURIComponent(params[paramName]); |
| 181 } |
| 182 } |
| 183 |
| 184 var headers = {}; |
| 185 headers['X-CloudPrint-Proxy'] = 'ChromePrintPreview'; |
| 186 if (method == 'GET') { |
| 187 headers['Content-Type'] = CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_; |
| 188 } else if (method == 'POST') { |
| 189 headers['Content-Type'] = CloudPrintInterface.MULTIPART_CONTENT_TYPE_; |
| 190 } |
| 191 |
| 192 var xhr = new XMLHttpRequest(); |
| 193 xhr.onreadystatechange = this.onReadyStateChange_.bind( |
| 194 this, xhr, successCallback.bind(this)); |
| 195 xhr.open(method, url, true); |
| 196 xhr.withCredentials = true; |
| 197 for (var header in headers) { |
| 198 xhr.setRequestHeader(header, headers[header]); |
| 199 } |
| 200 xhr.send(body); |
| 201 }, |
| 202 |
| 203 /** |
| 204 * Dispatches an ERROR event with the given error message. |
| 205 * @param {string} message Error message to include in the ERROR event. |
| 206 * @private |
| 207 */ |
| 208 dispatchErrorEvent_: function(message) { |
| 209 var errorEvt = new cr.Event(CloudPrintInterface.Event.ERROR); |
| 210 errorEvt.message = message; |
| 211 this.dispatchEvent(errorEvt); |
| 212 }, |
| 213 |
| 214 /** |
| 215 * Called when the ready-state of a XML http request changes. |
| 216 * Calls the successCallback with the result or dispatches an ERROR event. |
| 217 * @param {XMLHttpRequest} xhr XML http request that changed. |
| 218 * @param {function(Object)} successCallback Callback to call if the request |
| 219 * was successful. |
| 220 * @private |
| 221 */ |
| 222 onReadyStateChange_: function(xhr, successCallback) { |
| 223 if (xhr.readyState == 4) { |
| 224 if (xhr.status == 200) { |
| 225 var result = JSON.parse(xhr.responseText); |
| 226 if (result['success']) { |
| 227 this.xsrfToken_ = result['xsrf_token']; |
| 228 successCallback(result); |
| 229 } else { |
| 230 this.dispatchErrorEvent_(result['message']); |
| 231 } |
| 232 } else { |
| 233 this.dispatchErrorEvent_(xhr.status + ''); |
| 234 } |
| 235 } |
| 236 }, |
| 237 |
| 238 /** |
| 239 * Called when the search request completes successfully. |
| 240 * @param {Object} result JSON response. |
| 241 * @private |
| 242 */ |
| 243 onSearchDone_: function(result) { |
| 244 var printerListJson = result['printers'] || []; |
| 245 var printerList = []; |
| 246 for (var printerJson, i = 0; printerJson = printerListJson[i]; i++) { |
| 247 try { |
| 248 printerList.push(cloudprint.CloudDestinationParser.parse( |
| 249 printerJson)); |
| 250 } catch (err) { |
| 251 // TODO |
| 252 } |
| 253 } |
| 254 var isRecent = result['request']['params']['q'] == '^recent'; |
| 255 var searchDoneEvt = new cr.Event(CloudPrintInterface.Event.SEARCH_DONE); |
| 256 searchDoneEvt.printers = printerList; |
| 257 searchDoneEvt.isRecent = isRecent; |
| 258 searchDoneEvt.email = result['request']['user']; |
| 259 this.dispatchEvent(searchDoneEvt); |
| 260 }, |
| 261 |
| 262 /** |
| 263 * Called when the submit request completes successfully. |
| 264 * @param {Object} result JSON response. |
| 265 * @private |
| 266 */ |
| 267 onSubmitDone_: function(result) { |
| 268 this.dispatchEvent(new cr.Event(CloudPrintInterface.Event.SUBMIT_DONE)); |
| 269 }, |
| 270 |
| 271 /** |
| 272 * Called when the printer request completes successfully. |
| 273 * @param {Object} result JSON response. |
| 274 * @private |
| 275 */ |
| 276 onPrinterDone_: function(result) { |
| 277 // TODO Better error handling here. |
| 278 var printerJson = result['printers'][0]; |
| 279 var printer; |
| 280 try { |
| 281 printer = cloudprint.CloudDestinationParser.parse(printerJson); |
| 282 } catch (err) { |
| 283 // TODO |
| 284 return; |
| 285 } |
| 286 var printerDoneEvt = new cr.Event(CloudPrintInterface.Event.PRINTER_DONE); |
| 287 printerDoneEvt.printer = printer; |
| 288 this.dispatchEvent(printerDoneEvt); |
| 289 } |
| 290 }; |
| 291 |
| 292 // Export |
| 293 return { |
| 294 CloudPrintInterface: CloudPrintInterface |
| 295 }; |
| 296 }); |
OLD | NEW |