bgcore.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. * Copyright 2011 Gildas Lormeau
  3. * contact : gildas.lormeau <at> gmail.com
  4. *
  5. * This file is part of SingleFile Core.
  6. *
  7. * SingleFile Core is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * SingleFile Core is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with SingleFile Core. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. (function() {
  21. singlefile.PageData = PageData;
  22. singlefile.DocData = DocData;
  23. function PageData(tabId, pageId, senderId, config, processSelection, processFrame, callback) {
  24. var timeoutError, that = this;
  25. this.pageId = pageId;
  26. this.docs = [];
  27. this.processedDocs = 0;
  28. this.initializedDocs = 0;
  29. this.processableDocs = 0;
  30. this.senderId = senderId;
  31. this.config = config;
  32. this.processSelection = processSelection;
  33. this.processFrame = processFrame;
  34. this.processing = true;
  35. this.tabId = tabId;
  36. this.requestManager = new singlefile.nio.RequestManager();
  37. this.progressIndex = 0;
  38. this.progressMax = 0;
  39. this.title = null;
  40. this.url = null;
  41. this.top = null;
  42. this.timeoutPageInit = null;
  43. this.portsId = [];
  44. this.contextmenuTime = null;
  45. this.frameDocData = null;
  46. timeoutError = setTimeout(function() {
  47. that.processing = false;
  48. chrome.extension.sendRequest(that.senderId, {
  49. processError : true,
  50. tabId : tabId
  51. });
  52. }, 15000);
  53. wininfo.init(tabId, function(processableDocs) {
  54. clearTimeout(timeoutError);
  55. that.processableDocs = processableDocs;
  56. callback();
  57. });
  58. }
  59. PageData.prototype = {
  60. initProcess : function() {
  61. var that = this;
  62. this.docs.forEach(function(docData) {
  63. if (that.config.processInBackground) {
  64. if (docData.processDocCallback)
  65. docData.processDocCallback();
  66. } else
  67. docData.process();
  68. });
  69. },
  70. processDoc : function(port, topWindow, winId, index, content, title, url, baseURI, characterSet, canvasData, contextmenuTime, callbacks) {
  71. var that = this, docData;
  72. docData = new DocData(port, winId, index, content, baseURI, characterSet, canvasData);
  73. if (topWindow) {
  74. this.top = docData;
  75. this.title = title || "";
  76. this.url = url;
  77. }
  78. this.docs.push(docData);
  79. if (this.processFrame && contextmenuTime && (!this.contextmenuTime || contextmenuTime > this.contextmenuTime)) {
  80. this.contextmenuTime = contextmenuTime;
  81. this.frameDocData = docData;
  82. }
  83. if (this.config.processInBackground && docData.content) {
  84. docData.parseContent();
  85. docData.processDocCallback = singlefile.initProcess(docData.doc, docData.doc.documentElement, topWindow, baseURI, characterSet, this.config,
  86. canvasData, this.requestManager, function(maxIndex) {
  87. callbacks.init(that, docData, maxIndex);
  88. }, function(index, maxIndex) {
  89. callbacks.progress(that, docData, index);
  90. }, function() {
  91. callbacks.end(that, docData);
  92. });
  93. }
  94. },
  95. processDocFragment : function(docData, mutationEventId, content) {
  96. var doc = document.implementation.createHTMLDocument();
  97. doc.body.innerHTML = content;
  98. docData.processDocCallback = singlefile.initProcess(doc, doc.documentElement, this.top == docData, docData.baseURI, docData.characterSet,
  99. this.config, null, this.requestManager, function() {
  100. docData.processDocCallback();
  101. }, null, function() {
  102. docData.setDocFragment(doc.body.innerHTML, mutationEventId);
  103. });
  104. },
  105. setDocContent : function(docData, content, callback) {
  106. var selectedDocData, that = this;
  107. function buildPage(docData, setFrameContent, getContent, callback) {
  108. function setContent(docData) {
  109. var parent = docData.parent;
  110. if (parent)
  111. setFrameContent(docData, function() {
  112. parent.processedChildren++;
  113. if (parent.processedChildren == parent.childrenLength)
  114. getContent(parent, function() {
  115. setContent(parent);
  116. });
  117. });
  118. else if (callback)
  119. callback(docData);
  120. }
  121. if (docData.childrenLength)
  122. docData.children.forEach(function(data) {
  123. buildPage(data, setFrameContent, getContent, callback);
  124. });
  125. else
  126. setContent(docData);
  127. }
  128. function bgPageEnd(pageData, docData, callback) {
  129. var content = singlefile.util.getDocContent(docData.doc);
  130. if (pageData.config.displayProcessedPage)
  131. pageData.top.setContent(content);
  132. else
  133. callback(pageData.tabId, pageData.pageId, pageData.top, content);
  134. }
  135. if (content)
  136. docData.content = content;
  137. this.processedDocs++;
  138. if (this.processSelection)
  139. if (this.config.processInBackground)
  140. bgPageEnd(this, docData, callback);
  141. else
  142. docData.getContent(function() {
  143. that.top.setContent(docData.content);
  144. });
  145. else if (this.processedDocs == this.docs.length) {
  146. this.docs.forEach(function(docData) {
  147. var parentWinId = docData.winId.match(/((?:\d*\.?)*)\.\d*/);
  148. parentWinId = parentWinId ? parentWinId[1] : null;
  149. if (parentWinId)
  150. that.docs.forEach(function(data) {
  151. if (data.winId && data.winId == parentWinId)
  152. docData.parent = data;
  153. });
  154. if (docData.parent)
  155. docData.parent.setChild(docData);
  156. });
  157. if (this.frameDocData) {
  158. selectedDocData = this.frameDocData;
  159. selectedDocData.parent = null;
  160. } else
  161. selectedDocData = this.top;
  162. if (this.config.processInBackground)
  163. buildPage(selectedDocData, function(docData, callback) {
  164. docData.parent.docFrames[docData.index].setAttribute("src", "data:text/html;charset=utf-8,"
  165. + encodeURI(singlefile.util.getDocContent(docData.doc)));
  166. delete docData.doc;
  167. callback();
  168. }, function(docData, callback) {
  169. callback();
  170. }, function(docData) {
  171. bgPageEnd(that, docData, callback);
  172. });
  173. else
  174. buildPage(this.top, function(docData, callback) {
  175. docData.parent.setFrameContent(docData, callback);
  176. }, function(docData, callback) {
  177. docData.getContent(callback);
  178. }, function(docData) {
  179. docData.setContent();
  180. });
  181. }
  182. },
  183. computeProgress : function() {
  184. var that = this;
  185. this.progressIndex = 0;
  186. this.progressMax = 0;
  187. this.docs.forEach(function(docData) {
  188. that.progressIndex += docData.progressIndex || 0;
  189. that.progressMax += docData.progressMax || 0;
  190. });
  191. },
  192. getResourceContentRequest : function(url, requestId, winId, characterSet, mediaTypeParam, docData) {
  193. this.requestManager.send(url, function(content) {
  194. docData.getResourceContentResponse(content, requestId);
  195. }, characterSet, mediaTypeParam);
  196. },
  197. getDocData : function(winId) {
  198. var found;
  199. this.docs.forEach(function(docData) {
  200. if (docData.winId == winId)
  201. found = docData;
  202. });
  203. return found;
  204. }
  205. };
  206. function DocData(port, winId, index, content, baseURI, characterSet, canvasData) {
  207. this.port = port;
  208. this.content = content;
  209. this.baseURI = baseURI;
  210. this.characterSet = characterSet;
  211. this.canvasData = canvasData;
  212. this.winId = winId;
  213. this.index = index;
  214. this.children = [];
  215. this.doc = null;
  216. this.docFrames = null;
  217. this.processDocCallback = null;
  218. this.getContentCallback = null;
  219. this.setFrameContentCallback = null;
  220. this.processedChildren = 0;
  221. this.childrenLength = 0;
  222. }
  223. DocData.prototype = {
  224. parseContent : function() {
  225. var doc = document.implementation.createHTMLDocument();
  226. doc.open();
  227. doc.write(this.content);
  228. doc.close();
  229. this.doc = doc;
  230. this.docFrames = doc.querySelectorAll("iframe, frame");
  231. delete this.content;
  232. },
  233. setChild : function(childDoc) {
  234. this.children[childDoc.index] = childDoc;
  235. this.childrenLength++;
  236. },
  237. process : function() {
  238. this.port.postMessage({
  239. processDoc : true,
  240. winId : this.winId
  241. });
  242. },
  243. setDocFragment : function(content, mutationEventId) {
  244. this.port.postMessage({
  245. setDocFragment : true,
  246. content : content,
  247. mutationEventId : mutationEventId
  248. });
  249. },
  250. getResourceContentResponse : function(content, requestId) {
  251. this.port.postMessage({
  252. getResourceContentResponse : true,
  253. requestId : requestId,
  254. winId : this.winId,
  255. content : content
  256. });
  257. },
  258. setContent : function(content) {
  259. this.port.postMessage({
  260. setContentRequest : true,
  261. content : content,
  262. winProperties : singlefile.winProperties
  263. });
  264. },
  265. getContent : function(callback) {
  266. this.getContentCallback = callback;
  267. this.port.postMessage({
  268. getContentRequest : true,
  269. winId : this.winId
  270. });
  271. },
  272. setFrameContent : function(docData, callback) {
  273. docData.setFrameContentCallback = callback;
  274. this.port.postMessage({
  275. setFrameContentRequest : true,
  276. winId : this.winId,
  277. index : docData.index,
  278. content : docData.content
  279. });
  280. }
  281. };
  282. (function() {
  283. var property, winProperties = {};
  284. for (property in window)
  285. winProperties[property] = true;
  286. singlefile.winProperties = winProperties;
  287. })();
  288. })();