1// Copyright 2013 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// Custom bindings for the notifications API. 6var binding = require('binding').Binding.create('notifications'); 7 8var sendRequest = require('sendRequest').sendRequest; 9var imageUtil = require('imageUtil'); 10var lastError = require('lastError'); 11 12function image_data_setter(context, key) { 13 var f = function(val) { 14 this[key] = val; 15 }; 16 return $Function.bind(f, context); 17} 18 19function replaceNotificationOptionURLs(notification_details, callback) { 20 // A URL Spec is an object with the following keys: 21 // path: The resource to be downloaded. 22 // width: (optional) The maximum width of the image to be downloaded. 23 // height: (optional) The maximum height of the image to be downloaded. 24 // callback: A function to be called when the URL is complete. It 25 // should accept an ImageData object and set the appropriate 26 // field in the output of create. 27 28 // TODO(dewittj): Try to remove hard-coding of image sizes. 29 // |iconUrl| might be optional for notification updates. 30 var url_specs = []; 31 if (notification_details.iconUrl) { 32 $Array.push(url_specs, { 33 path: notification_details.iconUrl, 34 width: 80, 35 height: 80, 36 callback: image_data_setter(notification_details, 'iconBitmap') 37 }); 38 } 39 40 // |imageUrl| is optional. 41 if (notification_details.imageUrl) { 42 $Array.push(url_specs, { 43 path: notification_details.imageUrl, 44 width: 360, 45 height: 240, 46 callback: image_data_setter(notification_details, 'imageBitmap') 47 }); 48 } 49 50 // Each button has an optional icon. 51 var button_list = notification_details.buttons; 52 if (button_list && typeof button_list.length === 'number') { 53 var num_buttons = button_list.length; 54 for (var i = 0; i < num_buttons; i++) { 55 if (button_list[i].iconUrl) { 56 $Array.push(url_specs, { 57 path: button_list[i].iconUrl, 58 width: 16, 59 height: 16, 60 callback: image_data_setter(button_list[i], 'iconBitmap') 61 }); 62 } 63 } 64 } 65 66 if (!url_specs.length) { 67 callback(true); 68 return; 69 } 70 71 var errors = 0; 72 73 imageUtil.loadAllImages(url_specs, { 74 onerror: function(index) { 75 errors++; 76 }, 77 oncomplete: function(imageData) { 78 if (errors > 0) { 79 callback(false); 80 return; 81 } 82 for (var index = 0; index < url_specs.length; index++) { 83 var url_spec = url_specs[index]; 84 url_spec.callback(imageData[index]); 85 } 86 callback(true); 87 } 88 }); 89} 90 91function genHandle(name, failure_function) { 92 return function(id, input_notification_details, callback) { 93 // TODO(dewittj): Remove this hack. This is used as a way to deep 94 // copy a complex JSON object. 95 var notification_details = JSON.parse( 96 JSON.stringify(input_notification_details)); 97 var that = this; 98 replaceNotificationOptionURLs(notification_details, function(success) { 99 if (success) { 100 sendRequest(that.name, 101 [id, notification_details, callback], 102 that.definition.parameters); 103 return; 104 } 105 lastError.run(name, 106 'Unable to download all specified images.', 107 null, 108 failure_function, [callback, id]) 109 }); 110 }; 111} 112 113var handleCreate = genHandle('notifications.create', 114 function(callback, id) { callback(id); }); 115var handleUpdate = genHandle('notifications.update', 116 function(callback, id) { callback(false); }); 117 118var notificationsCustomHook = function(bindingsAPI, extensionId) { 119 var apiFunctions = bindingsAPI.apiFunctions; 120 apiFunctions.setHandleRequest('create', handleCreate); 121 apiFunctions.setHandleRequest('update', handleUpdate); 122}; 123 124binding.registerCustomHook(notificationsCustomHook); 125 126exports.binding = binding.generate(); 127