You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
5.6 KiB

10 years ago
10 years ago
10 years ago
10 years ago
  1. /*******************************************************************************
  2. µBlock - a browser extension to block requests.
  3. Copyright (C) 2014 The µBlock authors
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see {http://www.gnu.org/licenses/}.
  14. Home: https://github.com/gorhill/uMatrix
  15. */
  16. /* global addMessageListener, removeMessageListener, sendAsyncMessage */
  17. // For non background pages
  18. /******************************************************************************/
  19. (function(self) {
  20. 'use strict';
  21. /******************************************************************************/
  22. var vAPI = self.vAPI = self.vAPI || {};
  23. vAPI.firefox = true;
  24. vAPI.sessionId = String.fromCharCode(Date.now() % 25 + 97) +
  25. Math.random().toString(36).slice(2);
  26. /******************************************************************************/
  27. vAPI.shutdown = (function() {
  28. var jobs = [];
  29. var add = function(job) {
  30. jobs.push(job);
  31. };
  32. var exec = function() {
  33. //console.debug('Shutting down...');
  34. var job;
  35. while ( job = jobs.pop() ) {
  36. job();
  37. }
  38. };
  39. return {
  40. add: add,
  41. exec: exec
  42. };
  43. })();
  44. /******************************************************************************/
  45. var messagingConnector = function(response) {
  46. if ( !response ) {
  47. return;
  48. }
  49. var channels = vAPI.messaging.channels;
  50. var channel, listener;
  51. if ( response.broadcast === true && !response.channelName ) {
  52. for ( channel in channels ) {
  53. if ( channels.hasOwnProperty(channel) === false ) {
  54. continue;
  55. }
  56. listener = channels[channel].listener;
  57. if ( typeof listener === 'function' ) {
  58. listener(response.msg);
  59. }
  60. }
  61. return;
  62. }
  63. if ( response.requestId ) {
  64. listener = vAPI.messaging.listeners[response.requestId];
  65. delete vAPI.messaging.listeners[response.requestId];
  66. delete response.requestId;
  67. }
  68. if ( !listener ) {
  69. channel = channels[response.channelName];
  70. listener = channel && channel.listener;
  71. }
  72. if ( typeof listener === 'function' ) {
  73. listener(response.msg);
  74. }
  75. };
  76. /******************************************************************************/
  77. vAPI.messaging = {
  78. channels: {},
  79. listeners: {},
  80. requestId: 1,
  81. setup: function() {
  82. this.connector = function(msg) {
  83. messagingConnector(JSON.parse(msg));
  84. };
  85. addMessageListener(this.connector);
  86. this.channels['vAPI'] = {};
  87. this.channels['vAPI'].listener = function(msg) {
  88. if ( msg.cmd === 'injectScript' ) {
  89. var details = msg.details;
  90. if ( !details.allFrames && window !== window.top ) {
  91. return;
  92. }
  93. self.injectScript(details.file);
  94. }
  95. };
  96. },
  97. close: function() {
  98. if ( !this.connector ) {
  99. return;
  100. }
  101. removeMessageListener();
  102. this.connector = null;
  103. this.channels = {};
  104. this.listeners = {};
  105. },
  106. channel: function(channelName, callback) {
  107. if ( !channelName ) {
  108. return;
  109. }
  110. this.channels[channelName] = {
  111. channelName: channelName,
  112. listener: typeof callback === 'function' ? callback : null,
  113. send: function(message, callback) {
  114. if ( !vAPI.messaging.connector ) {
  115. vAPI.messaging.setup();
  116. }
  117. message = {
  118. channelName: self._sandboxId_ + '|' + this.channelName,
  119. msg: message
  120. };
  121. if ( callback ) {
  122. message.requestId = vAPI.messaging.requestId++;
  123. vAPI.messaging.listeners[message.requestId] = callback;
  124. }
  125. sendAsyncMessage('umatrix:background', message);
  126. },
  127. close: function() {
  128. delete vAPI.messaging.channels[this.channelName];
  129. }
  130. };
  131. return this.channels[channelName];
  132. },
  133. toggleListener: function({type, persisted}) {
  134. if ( !vAPI.messaging.connector ) {
  135. return;
  136. }
  137. if ( type === 'pagehide' ) {
  138. removeMessageListener();
  139. return;
  140. }
  141. if ( persisted ) {
  142. addMessageListener(vAPI.messaging.connector);
  143. }
  144. }
  145. };
  146. window.addEventListener('pagehide', vAPI.messaging.toggleListener, true);
  147. window.addEventListener('pageshow', vAPI.messaging.toggleListener, true);
  148. /******************************************************************************/
  149. // No need to have vAPI client linger around after shutdown if
  150. // we are not a top window (because element picker can still
  151. // be injected in top window).
  152. if ( window !== window.top ) {
  153. // Can anything be done?
  154. }
  155. /******************************************************************************/
  156. })(this);
  157. /******************************************************************************/