context_menus_handlers.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Copyright 2015 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. // Implementation of custom bindings for the contextMenus API.
  5. // This is used to implement the contextMenus API for extensions and for the
  6. // <webview> tag (see chrome_web_view_experimental.js).
  7. var contextMenuNatives = requireNative('context_menus');
  8. // Add the bindings to the contextMenus API.
  9. function createContextMenusHandlers(isWebview) {
  10. var eventName = isWebview ? 'webViewInternal.contextMenus' : 'contextMenus';
  11. // Some dummy value for chrome.contextMenus instances.
  12. // Webviews use positive integers, and 0 to denote an invalid webview ID.
  13. // The following constant is -1 to avoid any conflicts between webview IDs and
  14. // extensions.
  15. var INSTANCEID_NON_WEBVIEW = -1;
  16. // Generates a customCallback for a given method. |handleCallback| will be
  17. // invoked with the same arguments this function is called with.
  18. function getCallback(handleCallback) {
  19. return function() {
  20. var extensionCallback = arguments[arguments.length - 1];
  21. if (bindingUtil.hasLastError()) {
  22. if (extensionCallback)
  23. extensionCallback();
  24. return;
  25. }
  26. $Function.apply(handleCallback, null, arguments);
  27. if (extensionCallback)
  28. extensionCallback();
  29. };
  30. }
  31. // Shift off the instanceId from the arguments for webviews.
  32. function getInstanceId(args) {
  33. if (isWebview)
  34. return $Array.shift(args); // This modifies the array in-place.
  35. return INSTANCEID_NON_WEBVIEW;
  36. }
  37. var contextMenus = { __proto__: null };
  38. contextMenus.handlers = { __proto__: null };
  39. var supportsLazyListeners = !isWebview;
  40. var supportsFilters = false;
  41. contextMenus.event = bindingUtil.createCustomEvent(
  42. eventName, supportsFilters, supportsLazyListeners);
  43. contextMenus.getIdFromCreateProperties = function(createProperties) {
  44. if (typeof createProperties.id !== 'undefined')
  45. return createProperties.id;
  46. return createProperties.generatedId;
  47. };
  48. contextMenus.handlersForId = function(instanceId, id) {
  49. if (!contextMenus.handlers[instanceId]) {
  50. contextMenus.handlers[instanceId] = {
  51. generated: {},
  52. string: {}
  53. };
  54. }
  55. if (typeof id === 'number')
  56. return contextMenus.handlers[instanceId].generated;
  57. return contextMenus.handlers[instanceId].string;
  58. };
  59. contextMenus.ensureListenerSetup = function() {
  60. if (contextMenus.listening) {
  61. return;
  62. }
  63. contextMenus.listening = true;
  64. contextMenus.event.addListener(function(info) {
  65. var instanceId = INSTANCEID_NON_WEBVIEW;
  66. if (isWebview) {
  67. instanceId = info.webviewInstanceId;
  68. // Don't expose |webviewInstanceId| via the public API.
  69. delete info.webviewInstanceId;
  70. }
  71. var id = info.menuItemId;
  72. var onclick = contextMenus.handlersForId(instanceId, id)[id];
  73. if (onclick) {
  74. $Function.apply(onclick, null, arguments);
  75. }
  76. });
  77. };
  78. // To be used with apiFunctions.setHandleRequest
  79. var requestHandlers = { __proto__: null };
  80. function createCallback(instanceId, id, onclick) {
  81. if (onclick) {
  82. contextMenus.ensureListenerSetup();
  83. contextMenus.handlersForId(instanceId, id)[id] = onclick;
  84. }
  85. }
  86. requestHandlers.create = function() {
  87. var args = $Array.from(arguments);
  88. var instanceId = getInstanceId(args);
  89. var createProperties = args[0];
  90. var callback = args[1];
  91. createProperties.generatedId = contextMenuNatives.GetNextContextMenuId();
  92. var id = contextMenus.getIdFromCreateProperties(createProperties);
  93. var onclick = createProperties.onclick;
  94. var optArgs = {
  95. __proto__: null,
  96. customCallback: getCallback($Function.bind(createCallback, null,
  97. instanceId, id, onclick)),
  98. };
  99. if (isWebview) {
  100. bindingUtil.sendRequest(
  101. 'chromeWebViewInternal.contextMenusCreate',
  102. [instanceId, createProperties, callback], optArgs);
  103. } else {
  104. bindingUtil.sendRequest(
  105. 'contextMenus.create', [createProperties, callback], optArgs);
  106. }
  107. return id;
  108. };
  109. function removeCallback(instanceId, id) {
  110. delete contextMenus.handlersForId(instanceId, id)[id];
  111. }
  112. requestHandlers.remove = function() {
  113. var args = $Array.from(arguments);
  114. var instanceId = getInstanceId(args);
  115. var id = args[0];
  116. var callback = args[1];
  117. var optArgs = {
  118. __proto__: null,
  119. customCallback: getCallback($Function.bind(removeCallback, null,
  120. instanceId, id)),
  121. };
  122. if (isWebview) {
  123. bindingUtil.sendRequest(
  124. 'chromeWebViewInternal.contextMenusRemove',
  125. [instanceId, id, callback], optArgs);
  126. } else {
  127. bindingUtil.sendRequest('contextMenus.remove', [id, callback], optArgs);
  128. }
  129. };
  130. function updateCallback(instanceId, id, onclick) {
  131. if (onclick) {
  132. contextMenus.ensureListenerSetup();
  133. contextMenus.handlersForId(instanceId, id)[id] = onclick;
  134. } else if (onclick === null) {
  135. // When onclick is explicitly set to null, remove the event listener.
  136. delete contextMenus.handlersForId(instanceId, id)[id];
  137. }
  138. }
  139. requestHandlers.update = function() {
  140. var args = $Array.from(arguments);
  141. var instanceId = getInstanceId(args);
  142. var id = args[0];
  143. var updateProperties = args[1];
  144. var callback = args[2];
  145. var onclick = updateProperties.onclick;
  146. var optArgs = {
  147. __proto__: null,
  148. customCallback: getCallback($Function.bind(updateCallback, null,
  149. instanceId, id, onclick)),
  150. };
  151. if (isWebview) {
  152. bindingUtil.sendRequest(
  153. 'chromeWebViewInternal.contextMenusUpdate',
  154. [instanceId, id, updateProperties, callback], optArgs);
  155. } else {
  156. bindingUtil.sendRequest(
  157. 'contextMenus.update', [id, updateProperties, callback], optArgs);
  158. }
  159. };
  160. function removeAllCallback(instanceId) {
  161. delete contextMenus.handlers[instanceId];
  162. }
  163. requestHandlers.removeAll = function() {
  164. var args = $Array.from(arguments);
  165. var instanceId = getInstanceId(args);
  166. var callback = args[0];
  167. var optArgs = {
  168. __proto__: null,
  169. customCallback: getCallback($Function.bind(removeAllCallback, null,
  170. instanceId)),
  171. };
  172. if (isWebview) {
  173. bindingUtil.sendRequest(
  174. 'chromeWebViewInternal.contextMenusRemoveAll', [instanceId, callback],
  175. optArgs);
  176. } else {
  177. bindingUtil.sendRequest('contextMenus.removeAll', [callback], optArgs);
  178. }
  179. };
  180. return {
  181. requestHandlers: requestHandlers,
  182. };
  183. }
  184. exports.$set('create', createContextMenusHandlers);