Index: chrome/browser/resources/print_preview/print_preview_cloud.js |
diff --git a/chrome/browser/resources/print_preview/print_preview_cloud.js b/chrome/browser/resources/print_preview/print_preview_cloud.js |
index 7c8b7c02aa6f1993e377fa60292fccfe664e09f1..035782de5a8b6bfd020d505edd46f8f8f1060f9c 100644 |
--- a/chrome/browser/resources/print_preview/print_preview_cloud.js |
+++ b/chrome/browser/resources/print_preview/print_preview_cloud.js |
@@ -3,198 +3,230 @@ |
// found in the LICENSE file. |
cr.define('cloudprint', function() { |
- |
- // The URL to use to access the cloud print servers. |
- // Set by a call to setBaseURL. |
- var cloudPrintBaseURL = ''; |
- |
- // Headers to set for most cloud print API calls. |
- var xCloudPrintURLHeader = {'Content-Type': |
- 'application/x-www-form-urlencoded', |
- 'X-CloudPrint-Proxy': 'ChromePrintPreview'}; |
- |
- // Headers to set when sending multipart data to cloud print APIs. |
- // Currently only used when submitting a job. |
- var xCloudPrintFormHeader = {'Content-Type': |
- 'multipart/form-data; boundary=----CloudPrintFormBoundaryjc9wuprokl8i', |
- 'X-CloudPrint-Proxy': 'ChromePrintPreview'}; |
- |
- // The last received XSRF token. This should be sent with each request |
- // to prevent XSRF. |
- var lastXSRFToken = ''; |
+ 'use strict'; |
/** |
- * Sets the base URL to be used for communicating with cloud print |
- * servers. |
- * @param {string} cloudPrintURL The URL to use. |
+ * API to the Google Cloud Print service. |
+ * |
+ * @param {string} baseUrl Base part of the Google Cloud Print service URL |
+ * with no trailing slash. For example, |
+ * 'https://www.google.com/cloudprint'. |
+ * @constructor |
+ * @extends {cr.EventTarget} |
*/ |
- function setBaseURL(cloudPrintURL) { |
- cloudPrintBaseURL = cloudPrintURL; |
- } |
+ function CloudPrintInterface(baseUrl) { |
+ /** |
+ * The base URL of the Google Cloud Print API. |
+ * @type {string} |
+ * @private |
+ */ |
+ this.baseURL_ = baseUrl; |
+ |
+ /** |
+ * Last received XSRF token. Sent as a parameter in every request. |
+ * @type {string} |
+ * @private |
+ */ |
+ this.xsrfToken_ = ''; |
+ }; |
/** |
- * Gets the base URL to be used for communicating with cloud print |
- * servers. |
- * @return {string} The URL. |
+ * Enumeration of events dispatched. |
+ * @enum {string} |
*/ |
- function getBaseURL() { |
- return cloudPrintBaseURL; |
- } |
+ CloudPrintInterface.Event = { |
+ ERROR: 'cloudprint.CloudPrintInterface.ERROR', |
+ PRINTER_DONE: 'cloudprint.CloudPrintInterface.PRINTER_DONE', |
+ SEARCH_DONE: 'cloudprint.CloudPrintInterface.SEARCH_DONE', |
+ SUBMIT_DONE: 'cloudprint.CloudPrintInterface.SUBMIT_DONE' |
+ }; |
/** |
- * Extracts the XSRF token from each response to be used in the next |
- * request. |
- * @param {XMLHttpRequest} xhr The object used to make the request. |
- * @return {string} The extracted XSRF token. |
+ * Content type header value for a URL encoded HTTP request. |
+ * @type {string} |
+ * @private |
*/ |
- function extractXSRFtoken(xhr) { |
- if (xhr.status == 200) { |
- var result = JSON.parse(xhr.responseText); |
- return result['xsrf_token']; |
- } else { |
- return null; |
- } |
- } |
+ CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_ = |
+ 'application/x-www-form-urlencoded'; |
/** |
- * Makes a request to cloud print servers. |
- * @param {string} method The HTTP method to be used. |
- * @param {string} action The cloud print API to call. |
- * @param {Array} headers Headers to send with the request. |
- * @param {string} body Body to be sent with POST requests. |
- * @param {function} callback Function to be called to process response. |
- * @param {boolean} async True if we want the request made asyncronously. |
+ * Content type header value for a multipart HTTP request. |
+ * @type {string} |
+ * @private |
*/ |
- function sendCloudPrintRequest(method, |
- action, |
- headers, |
- params, |
- body, |
- callback) { |
- var xhr = new XMLHttpRequest(); |
- if (callback != null) { |
- xhr.onreadystatechange = function() { |
- if (xhr.readyState == 4) { |
- var updatedXSRFToken = extractXSRFtoken(xhr); |
- if (updatedXSRFToken != null) { |
- lastXSRFToken = updatedXSRFToken; |
- } |
- callback.call(this, xhr); |
- } |
- }; |
- } |
- var url = cloudPrintBaseURL + '/' + action; |
- if (params == null) { |
- params = new Array; |
- } |
- if (lastXSRFToken.length != 0) { |
- params.push('xsrf=' + lastXSRFToken); |
- } |
- if (params.length != 0) { |
- url = url + '?'; |
- for (param in params) { |
- url = url + params[param] + '&'; |
+ CloudPrintInterface.MULTIPART_CONTENT_TYPE_ = |
+ 'multipart/form-data; boundary=----CloudPrintFormBoundaryjc9wuprokl8i'; |
+ |
+ CloudPrintInterface.prototype = { |
+ __proto__: cr.EventTarget.prototype, |
+ |
+ /** |
+ * Sends a Google Cloud Print search API request. |
+ * @param {boolean} isRecent Whether to search for only recently used |
+ * printers. |
+ */ |
+ search: function(isRecent) { |
+ var params = {}; |
+ if (isRecent) { |
+ params['q'] = '^recent'; |
} |
- } |
- xhr.open(method, url, true); |
- xhr.withCredentials = true; |
- if (headers) { |
- for (var header in headers) { |
- if (headers.hasOwnProperty(header)) { |
- xhr.setRequestHeader(header, headers[header]); |
+ this.sendRequest_('GET', 'search', params, null, this.onSearchDone_); |
+ }, |
+ |
+ /** |
+ * Sends a Google Cloud Print submit API request. |
+ * @param {string} body Body of the HTTP post request to send. |
+ */ |
+ submit: function(body) { |
+ this.sendRequest_('POST', 'submit', null, body, this.onSubmitDone_); |
+ }, |
+ |
+ /** |
+ * Sends a Google Cloud Print printer API request. |
+ * @param {string} printerId ID of the printer to lookup. |
+ */ |
+ printer: function(printerId) { |
+ var params = {'printerid': printerId}; |
+ this.sendRequest_('GET', 'printer', params, null, this.onPrinterDone_); |
+ }, |
+ |
+ /** |
+ * Sends a request to the Google Cloud Print API. |
+ * @param {string} method HTTP method of the request. |
+ * @param {string} action Google Cloud Print action to perform. |
+ * @param {!Object} params HTTP parameters to include in the request. |
+ * @param {string} body HTTP multi-part encoded body. |
+ * @param {function(Object)} successCallback Callback to invoke when request |
+ * completes successfully. |
+ */ |
+ sendRequest_: function(method, action, params, body, successCallback) { |
+ if (!this.xsrfToken_) { |
+ // TODO Should throw an error if not a read-only action or issue an |
+ // xsrf token request. |
+ } |
+ var url = this.baseURL_ + '/' + action + '?xsrf=' + this.xsrfToken_; |
+ |
+ if (params) { |
+ for (var paramName in params) { |
+ url += '&' + paramName + '=' + encodeURIComponent(params[paramName]); |
} |
} |
- } |
- xhr.send(body); |
- return xhr; |
- } |
- /** |
- * Parse the response from the fetchPrinters call. |
- * @param {function} callback Function to be called to process response. |
- * @param {XMLHttpRequest} xhr The object used to make the request. |
- */ |
- function fetchPrintersResponse(callback, xhr) { |
- if (xhr.status == 200) { |
- var searchResult = JSON.parse(xhr.responseText); |
- if (searchResult['success']) { |
- var printerList = searchResult['printers']; |
- addCloudPrinters(printerList, callback); |
- return; |
+ var headers = {}; |
+ headers['X-CloudPrint-Proxy'] = 'ChromePrintPreview'; |
+ if (method == 'GET') { |
+ headers['Content-Type'] = CloudPrintInterface.URL_ENCODED_CONTENT_TYPE_; |
+ } else if (method == 'POST') { |
+ headers['Content-Type'] = CloudPrintInterface.MULTIPART_CONTENT_TYPE_; |
} |
- } |
- addCloudPrinters(null, callback); |
- } |
- /** |
- * Retrieve the list of printers available via cloud print. |
- * @param {function} callback Function to be called to process response. |
- */ |
- function fetchPrinters(callback, all) { |
- var query = 'q=^recent'; |
- if (all) { |
- query = ''; |
- } |
- sendCloudPrintRequest('GET', |
- 'search', |
- xCloudPrintURLHeader, |
- [query], |
- null, |
- fetchPrintersResponse.bind(this, callback)); |
- } |
+ var xhr = new XMLHttpRequest(); |
+ xhr.onreadystatechange = this.onReadyStateChange_.bind( |
+ this, xhr, successCallback.bind(this)); |
+ xhr.open(method, url, true); |
+ xhr.withCredentials = true; |
+ for (var header in headers) { |
+ xhr.setRequestHeader(header, headers[header]); |
+ } |
+ xhr.send(body); |
+ }, |
- /** |
- * Handle the response from printing to cloud print. |
- * @param {function} callback Function to be called to process response. |
- * @param {XMLHttpRequest} xhr The object used to make the request. |
- */ |
- function printToCloudResponse(callback, xhr) { |
- if (xhr.status == 200) { |
- var printResult = JSON.parse(xhr.responseText); |
- if (printResult['success']) { |
- callback.call(); |
+ /** |
+ * Dispatches an ERROR event with the given error message. |
+ * @param {string} message Error message to include in the ERROR event. |
+ * @private |
+ */ |
+ dispatchErrorEvent_: function(message) { |
+ var errorEvt = new cr.Event(CloudPrintInterface.Event.ERROR); |
+ errorEvt.message = message; |
+ this.dispatchEvent(errorEvt); |
+ }, |
+ |
+ /** |
+ * Called when the ready-state of a XML http request changes. |
+ * Calls the successCallback with the result or dispatches an ERROR event. |
+ * @param {XMLHttpRequest} xhr XML http request that changed. |
+ * @param {function(Object)} successCallback Callback to call if the request |
+ * was successful. |
+ * @private |
+ */ |
+ onReadyStateChange_: function(xhr, successCallback) { |
+ if (xhr.readyState == 4) { |
+ if (xhr.status == 200) { |
+ var result = JSON.parse(xhr.responseText); |
+ if (result['success']) { |
+ this.xsrfToken_ = result['xsrf_token']; |
+ successCallback(result); |
+ } else { |
+ this.dispatchErrorEvent_(result['message']); |
+ } |
+ } else { |
+ this.dispatchErrorEvent_(xhr.status + ''); |
+ } |
} |
- } |
- // TODO(abodenha@chromium.org) Catch and handle failures. |
- } |
+ }, |
- /** |
- * Send the current document to cloud print. |
- * @param {string} data The document to be printed. |
- * @param {function} callback Function to be called to process response. |
- */ |
- function printToCloud(data, callback) { |
- // TODO(abodenha@chromium.org) Make sure we have an XSRF token before |
- // sending a submit. Right now if the user clicks print before we |
- // complete any request we wont have an XSRF and the submit will fail. |
- sendCloudPrintRequest('POST', |
- 'submit', |
- xCloudPrintFormHeader, |
- null, |
- data, |
- printToCloudResponse.bind(this, callback)); |
- } |
+ /** |
+ * Called when the search request completes successfully. |
+ * @param {Object} result JSON response. |
+ * @private |
+ */ |
+ onSearchDone_: function(result) { |
+ var printerListJson = result['printers'] || []; |
+ var printerList = []; |
+ for (var printerJson, i = 0; printerJson = printerListJson[i]; i++) { |
+ try { |
+ printerList.push(cloudprint.CloudDestinationParser.parse( |
+ printerJson)); |
+ } catch (err) { |
+ // TODO Handle error case |
+ } |
+ } |
+ var isRecent = result['request']['params']['q'] == '^recent'; |
+ var searchDoneEvt = new cr.Event(CloudPrintInterface.Event.SEARCH_DONE); |
+ searchDoneEvt.printers = printerList; |
+ searchDoneEvt.isRecent = isRecent; |
+ searchDoneEvt.email = result['request']['user']; |
+ this.dispatchEvent(searchDoneEvt); |
+ }, |
- /** |
- * Gets the JSON string used to control the behavior of the current |
- * print job. |
- * @param {Object} printer The printer object to get the ticket for. |
- * @return {string} The print ticket or null if not a cloud printer. |
- */ |
- function getPrintTicketJSON(printer) { |
- if (isCloudPrint(printer)) { |
- return JSON.stringify({'capabilities': |
- [printer.cloudPrintOptions.colorOption]}); |
- } else { |
- return null; |
+ /** |
+ * Called when the submit request completes successfully. |
+ * @param {Object} result JSON response. |
+ * @private |
+ */ |
+ onSubmitDone_: function(result) { |
+ this.dispatchEvent(new cr.Event(CloudPrintInterface.Event.SUBMIT_DONE)); |
+ }, |
+ |
+ /** |
+ * Called when the printer request completes successfully. |
+ * @param {Object} result JSON response. |
+ * @private |
+ */ |
+ onPrinterDone_: function(result) { |
+ // TODO Better error handling here. |
+ var printerJson = result['printers'][0]; |
+ var printer; |
+ try { |
+ printer = cloudprint.CloudDestinationParser.parse(printerJson); |
+ printer.capabilities = cloudprint.CloudCapabilitiesParser.parse( |
+ printerJson['capabilities']); |
+ } catch (err) { |
+ // TODO Handle error case |
+ return; |
+ } |
+ var printerDoneEvt = new cr.Event(CloudPrintInterface.Event.PRINTER_DONE); |
+ printerDoneEvt.printer = printer; |
+ this.dispatchEvent(printerDoneEvt); |
} |
- } |
+ }; |
/** |
* Process the response from cloud print containing the capabilities |
* for the printer. |
* @param {function} callback Function to be called to process response. |
- * @param {Object} printer The printer object to get the capabilites for. |
+ * @param {Object} printer The printer object to get the capabilities for. |
* @param {XMLHttpRequest} xhr The object used to make the request. |
*/ |
function updatePrinterCapsResponse(callback, printer, xhr) { |
@@ -232,224 +264,10 @@ cr.define('cloudprint', function() { |
callback.call(this, printer); |
} |
} |
- } |
- |
- /** |
- * Retrieve capabilities for a printer. |
- * @param {Object} printer The printer object to get the capabilities for. |
- * @param {function} callback Function to be called to process response. |
- */ |
- function updatePrinterCaps(printer, callback) { |
- if (isCloudPrint(printer) && !printer.cloudPrintOptions.capsDownloaded) { |
- sendCloudPrintRequest('GET', |
- 'printer?printerid=' + |
- printer.value + |
- '&output=json', |
- xCloudPrintURLHeader, |
- null, |
- null, |
- updatePrinterCapsResponse.bind(this, |
- callback, |
- printer)); |
- } else { |
- callback.call(this, printer); |
- } |
- } |
- |
- /** |
- * @param {Object} printer The printer object to get the data for. |
- * @return {boolean} true if the printer supports color. |
- */ |
- function supportsColor(printer) { |
- return isCloudPrint(printer) && |
- printer.cloudPrintOptions.colorOption != null; |
- } |
- |
- /** |
- * @param {Object} printer The printer object to get the data for. |
- * @return {boolean} true if the printer defaults to color. |
- */ |
- function colorIsDefault(printer) { |
- // For now assume that unsupported color means we just don't know |
- // and assume color. |
- return !supportsColor(printer) || |
- (isCloudPrint(printer) && printer.cloudPrintOptions.colorIsDefault); |
- } |
- |
- /** |
- * Turn color on or off for the specified printer. |
- * @param {Object} printer The printer object to turn color on/off for. |
- * @param {boolean} color True to turn color on. |
- */ |
- function setColor(printer, color) { |
- if (isCloudPrint(printer) && supportsColor(printer)) { |
- if (color) { |
- printer.cloudPrintOptions.colorOption.options = |
- [printer.cloudPrintOptions.colorOnOption]; |
- } else { |
- printer.cloudPrintOptions.colorOption.options = |
- [printer.cloudPrintOptions.colorOffOption]; |
- } |
- } |
- } |
- |
- /** |
- * Creates a cloud print printer and sets it as the default printer. |
- * @param {string} printer_name The name of the printer to create. |
- * @param {Object} cloud_print_data Data to be stored in cloudPrintOptions. |
- * @param {function} add_callback The callback to be called to add the new |
- * printer to the print preview UI. |
- * @param {function} update_caps_callback The callback to be called to update |
- * capabilities on the new printer. |
- */ |
- function setDefaultPrinter(printer_name, |
- cloud_print_data, |
- add_callback, |
- update_caps_callback) { |
- var printer = addCloudPrinters([JSON.parse(cloud_print_data)], |
- add_callback); |
- if (printer) |
- update_caps_callback(printer); |
- } |
- |
- /** |
- * Returns the data necessary to serialize a cloud print printer. |
- * @param {Object} printer The printer object to get data for. |
- * @return {string} A JSON string that can be used to recreate the |
- * cloud print portion of the printer object, or and empty string if |
- * there is no data to save. |
- */ |
- function getData(printer) { |
- if (isCloudPrint(printer)) { |
- return JSON.stringify(printer.cloudPrintOptions); |
- } else { |
- return ''; |
- } |
- } |
- |
- /** |
- * Test if a printer is a cloud print printer. |
- * @param {Object} printer The printer to test. |
- * @return {boolean} true iff the printer is a cloud print printer. |
- */ |
- function isCloudPrint(printer) { |
- return printer && printer.cloudPrintOptions != null; |
- } |
- |
- /** |
- * Mark a printer as a cloud print printer and record its name and id. |
- * @param {Object} printer The printer to mark. |
- * @param {string} name The user visible name of the printer. |
- * @param {string} id The id of the printer used by cloud print to |
- * identify it. |
- */ |
- function setCloudPrint(printer, name, id) { |
- if (!printer.cloudPrintOptions) { |
- printer.cloudPrintOptions = new Object; |
- } |
- printer.cloudPrintOptions.name = name; |
- printer.cloudPrintOptions.id = id; |
- } |
- |
- /** |
- * Test if a particular cloud printer has already been added to the |
- * printer dropdown. |
- * @param {string} id A unique value to track this printer. |
- * @return {boolean} True if |id| has previously been passed to |
- * trackCloudPrinterAdded. |
- */ |
- function cloudPrinterAlreadyAdded(id) { |
- return addedCloudPrinters[id]; |
- } |
- |
- /** |
- * Test if a particular printer has already been added to the printers |
- * dropdown. Records it if not. |
- * @param {string} id A unique value to track this printer. |
- * @return {boolean} False if adding this printer would exceed |
- * |maxCloudPrinters|. |
- */ |
- function trackCloudPrinterAdded(id) { |
- if (Object.keys(addedCloudPrinters).length < maxCloudPrinters) { |
- addedCloudPrinters[id] = true; |
- return true; |
- } else { |
- return false; |
- } |
- } |
- |
- /** |
- * Add cloud printers to the list drop down. |
- * Called from the cloudprint object on receipt of printer information from |
- * the cloud print server. |
- * @param {Array} printers Array of printer info objects. |
- * @return {Object} The currently selected printer. |
- */ |
- function addCloudPrinters(printers, addDestinationListOptionAtPosition) { |
- var isFirstPass = false; |
- var printerList = $('printer-list'); |
- |
- if (firstCloudPrintOptionPos == lastCloudPrintOptionPos) { |
- isFirstPass = true; |
- // Remove empty entry added by setDefaultPrinter. |
- if (printerList[0] && printerList[0].textContent == '') |
- printerList.remove(0); |
- } |
- if (printers != null) { |
- for (var i = 0; i < printers.length; i++) { |
- if (!cloudPrinterAlreadyAdded(printers[i]['id'])) { |
- if (!trackCloudPrinterAdded(printers[i]['id'])) { |
- break; |
- } |
- if (printers[i]['displayName'] && printers[i]['displayName'] != '') |
- var name = printers[i]['displayName']; |
- else |
- var name = printers[i]['name']; |
- |
- var option = addDestinationListOptionAtPosition( |
- lastCloudPrintOptionPos++, |
- name, |
- printers[i]['id'], |
- name == defaultOrLastUsedPrinterName, |
- false, |
- false); |
- cloudprint.setCloudPrint(option, |
- name, |
- printers[i]['id']); |
- } |
- } |
- } else { |
- if (!cloudPrinterAlreadyAdded(SIGN_IN)) { |
- addDestinationListOptionAtPosition(lastCloudPrintOptionPos++, |
- localStrings.getString('signIn'), |
- SIGN_IN, |
- false, |
- false, |
- false); |
- trackCloudPrinterAdded(SIGN_IN); |
- chrome.send('signIn'); |
- } |
- } |
- var selectedPrinter = printerList.selectedIndex; |
- if (selectedPrinter < 0) |
- return null; |
- return printerList.options[selectedPrinter]; |
- } |
+ }; |
+ // Export |
return { |
- addCloudPrinters: addCloudPrinters, |
- colorIsDefault: colorIsDefault, |
- fetchPrinters: fetchPrinters, |
- getBaseURL: getBaseURL, |
- getData: getData, |
- getPrintTicketJSON: getPrintTicketJSON, |
- isCloudPrint: isCloudPrint, |
- printToCloud: printToCloud, |
- setBaseURL: setBaseURL, |
- setCloudPrint: setCloudPrint, |
- setColor: setColor, |
- setDefaultPrinter: setDefaultPrinter, |
- supportsColor: supportsColor, |
- updatePrinterCaps: updatePrinterCaps |
+ CloudPrintInterface: CloudPrintInterface |
}; |
}); |