Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / notifications_custom_bindings.js
blobfc6b442576bcc335061638e13b54d5c3693b89f3
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.
5 // Custom bindings for the notifications API.
6 //
7 var binding = require('binding').Binding.create('notifications');
9 var sendRequest = require('sendRequest').sendRequest;
10 var exceptionHandler = require('uncaught_exception_handler');
11 var imageUtil = require('imageUtil');
12 var lastError = require('lastError');
13 var notificationsPrivate = requireNative('notifications_private');
15 function imageDataSetter(context, key) {
16   var f = function(val) {
17     this[key] = val;
18   };
19   return $Function.bind(f, context);
22 // A URL Spec is an object with the following keys:
23 //  path: The resource to be downloaded.
24 //  width: (optional) The maximum width of the image to be downloaded in device
25 //         pixels.
26 //  height: (optional) The maximum height of the image to be downloaded in
27 //          device pixels.
28 //  callback: A function to be called when the URL is complete. It
29 //    should accept an ImageData object and set the appropriate
30 //    field in |notificationDetails|.
31 function getUrlSpecs(imageSizes, notificationDetails) {
32   var urlSpecs = [];
34   // |iconUrl| might be optional for notification updates.
35   if (notificationDetails.iconUrl) {
36     $Array.push(urlSpecs, {
37       path: notificationDetails.iconUrl,
38       width: imageSizes.icon.width * imageSizes.scaleFactor,
39       height: imageSizes.icon.height * imageSizes.scaleFactor,
40       callback: imageDataSetter(notificationDetails, 'iconBitmap')
41     });
42   }
44   // |appIconMaskUrl| is optional.
45   if (notificationDetails.appIconMaskUrl) {
46     $Array.push(urlSpecs, {
47       path: notificationDetails.appIconMaskUrl,
48       width: imageSizes.appIconMask.width * imageSizes.scaleFactor,
49       height: imageSizes.appIconMask.height * imageSizes.scaleFactor,
50       callback: imageDataSetter(notificationDetails, 'appIconMaskBitmap')
51     });
52   }
54   // |imageUrl| is optional.
55   if (notificationDetails.imageUrl) {
56     $Array.push(urlSpecs, {
57       path: notificationDetails.imageUrl,
58       width: imageSizes.image.width * imageSizes.scaleFactor,
59       height: imageSizes.image.height * imageSizes.scaleFactor,
60       callback: imageDataSetter(notificationDetails, 'imageBitmap')
61     });
62   }
64   // Each button has an optional icon.
65   var buttonList = notificationDetails.buttons;
66   if (buttonList && typeof buttonList.length === 'number') {
67     var numButtons = buttonList.length;
68     for (var i = 0; i < numButtons; i++) {
69       if (buttonList[i].iconUrl) {
70         $Array.push(urlSpecs, {
71           path: buttonList[i].iconUrl,
72           width: imageSizes.buttonIcon.width * imageSizes.scaleFactor,
73           height: imageSizes.buttonIcon.height * imageSizes.scaleFactor,
74           callback: imageDataSetter(buttonList[i], 'iconBitmap')
75         });
76       }
77     }
78   }
80   return urlSpecs;
83 function replaceNotificationOptionURLs(notification_details, callback) {
84   var imageSizes = notificationsPrivate.GetNotificationImageSizes();
85   var url_specs = getUrlSpecs(imageSizes, notification_details);
86   if (!url_specs.length) {
87     callback(true);
88     return;
89   }
91   var errors = 0;
93   imageUtil.loadAllImages(url_specs, {
94     onerror: function(index) {
95       errors++;
96     },
97     oncomplete: function(imageData) {
98       if (errors > 0) {
99         callback(false);
100         return;
101       }
102       for (var index = 0; index < url_specs.length; index++) {
103         var url_spec = url_specs[index];
104         url_spec.callback(imageData[index]);
105       }
106       callback(true);
107     }
108   });
111 function genHandle(name, failure_function) {
112   return function(id, input_notification_details, callback) {
113     // TODO(dewittj): Remove this hack. This is used as a way to deep
114     // copy a complex JSON object.
115     var notification_details = $JSON.parse(
116         $JSON.stringify(input_notification_details));
117     var that = this;
118     var stack = exceptionHandler.getExtensionStackTrace();
119     replaceNotificationOptionURLs(notification_details, function(success) {
120       if (success) {
121         sendRequest(that.name,
122             [id, notification_details, callback],
123             that.definition.parameters, {stack: stack});
124         return;
125       }
126       lastError.run(name,
127                     'Unable to download all specified images.',
128                     stack,
129                     failure_function, [callback || function() {}, id]);
130     });
131   };
134 var handleCreate = genHandle('notifications.create',
135                              function(callback, id) { callback(id); });
136 var handleUpdate = genHandle('notifications.update',
137                              function(callback, id) { callback(false); });
139 var notificationsCustomHook = function(bindingsAPI, extensionId) {
140   var apiFunctions = bindingsAPI.apiFunctions;
141   apiFunctions.setHandleRequest('create', handleCreate);
142   apiFunctions.setHandleRequest('update', handleUpdate);
145 binding.registerCustomHook(notificationsCustomHook);
147 exports.binding = binding.generate();