| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- * Copyright 2010 Gildas Lormeau
- * contact : gildas.lormeau <at> gmail.com
- *
- * This file is part of SingleFile.
- *
- * SingleFile is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * SingleFile is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
- */
- (function(holder) {
- var targetDoc, doc, options, winID, processedFrames = 0, initPageCallback, timeoutCallback, bgPort, winPort, requests = {}, requestCount = 0, responseCount = 0, sendContent, scrapbooking;
- function storeRequest(url, callback, base64, encodedText, characterSet) {
- if (!requests[url]) {
- requests[url] = {
- base64 : base64,
- encodedText : encodedText,
- characterSet : characterSet,
- callbacks : []
- };
- requestCount++;
- }
- requests[url].callbacks.push(callback);
- }
- function sendRequests(methodName) {
- var url, data, msg;
- for (url in requests) {
- data = requests[url];
- msg = {
- data : {
- url : url,
- base64 : data.base64,
- encodedText : data.encodedText,
- characterSet : data.base64 ? "x-user-defined" : data.characterSet
- }
- };
- msg[methodName] = true;
- bgPort.postMessage(msg);
- }
- }
- function getDocument() {
- var clone, mask;
- if (options.removeScripts || scrapbooking) {
- clone = targetDoc.documentElement.cloneNode(true);
- mask = clone.querySelector("#__SingleFile_mask__");
- if (mask)
- mask.parentElement.removeChild(mask);
- return clone;
- }
- return targetDoc.documentElement;
- }
- function setDocument() {
- if (options.removeScripts && !scrapbooking)
- targetDoc.replaceChild(doc, targetDoc.documentElement);
- }
- function initProcess(opt) {
- options = opt;
- if (options.removeScripts || scrapbooking)
- holder.filters.canvas.replace();
- if (options.removeHidden)
- holder.filters.element.removeHidden();
- doc = getDocument();
- holder.filters.element.clean(doc);
- if (options.removeFrames)
- holder.filters.frame.remove(doc);
- if (options.removeScripts || scrapbooking)
- holder.filters.script.remove(doc);
- if (options.removeObjects)
- holder.filters.object.remove(doc);
- holder.filters.a.setAbsolute(doc);
- }
- function getStylesheets() {
- holder.filters.document.getStylesheets(doc, storeRequest);
- sendRequests("setStylesheets");
- if (requestCount == 0) {
- holder.filters.document.get(doc, storeRequest, window == top);
- bgPort.postMessage({
- setTotalResources : true,
- totalResources : requestCount
- });
- }
- }
- function getData() {
- sendRequests("setData");
- if (requestCount == 0)
- bgPort.postMessage({
- setDataDone : true,
- data : window == top && options.removeFrames && sendContent ? holder.filters.document.getDoctype() + doc.outerHTML : null,
- favicoData : window == top && options.removeFrames && sendContent ? holder.filters.image.getFavicoData(doc) : null,
- frameCount : holder.filters.frame.count(doc),
- winID : winID
- });
- }
- function setData(data, callback, isStylesheet) {
- var callbacks = requests[data.url].callbacks;
- responseCount++;
- callbacks.forEach(function(cb) {
- cb(data);
- });
- if (!isStylesheet)
- bgPort.postMessage({
- incProcessedResources : true
- });
- if (responseCount == requestCount) {
- responseCount = 0;
- requestCount = 0;
- requests = {};
- if (callback)
- callback();
- }
- }
- function getDocData(data) {
- if (options.removeUnused) {
- setDocument();
- holder.filters.style.removeUnused();
- doc = getDocument();
- }
- holder.filters.frame.set(doc, data);
- bgPort.postMessage({
- setDocData : true,
- data : window != top || sendContent ? holder.filters.document.getDoctype() + doc.outerHTML : null,
- favicoData : window == top && sendContent ? holder.filters.image.getFavicoData(doc) : null,
- mimeType : "text/html"
- });
- }
- function done(winProperties) {
- var callbackId;
- setDocument();
- targetDoc.addEventListener("DOMNodeInsertedIntoDocument", function(event) {
- if (!callbackId)
- if (event.target.querySelectorAll)
- holder.filters.document.get(event.target, storeRequest, false);
- if (callbackId)
- clearTimeout(callbackId);
- callbackId = setTimeout(function() {
- if (requestCount)
- sendRequests("setDynamicData");
- callbackId = null;
- }, 20);
- }, true);
- bgPort.postMessage({
- done : true
- });
- if (options.removeScripts && !scrapbooking) {
- function resetWindowProperties(winPropertiesStr) {
- var property, winProp = JSON.parse(winPropertiesStr);
- for (property in window)
- if (!winProp[property])
- window[property] = null;
- }
- window.location.href = "javascript:(" + resetWindowProperties.toString() + ")('" + JSON.stringify(winProperties) + "')";
- }
- }
- function start(msg) {
- sendContent = msg.sendContent;
- scrapbooking = msg.scrapbooking;
- document.documentElement.insertBefore(document.createComment("\n Archive processed by SingleFile \n url: " + document.location.href + " \n saved date: " + new Date() + " \n"),
- document.documentElement.firstChild);
- timeoutCallback = setTimeout(initPageCallback, 1000);
- setWinId("0");
- }
- function setWinId(id) {
- winID = id;
- holder.filters.frame.clean();
- if (holder.filters.frame.count())
- winPort.postMessageToFrames('iframe[src], frame[src]', function(index, params) {
- return {
- setID : true,
- winID : params.winID + "." + index
- };
- }, {
- winID : id
- });
- else
- setWinIdDone();
- }
- function setWinIdDone() {
- processedFrames++;
- if (processedFrames == holder.filters.frame.count()) {
- if (top != window)
- winPort.postMessageToParent({
- done : true
- });
- else {
- clearTimeout(timeoutCallback);
- initPageCallback();
- }
- }
- }
- holder.core = {
- init : function(srcDoc, backgroundPort, windowPort) {
- windowPort.addListener(function(message) {
- if (message.setID)
- setWinId(message.winID);
- else if (message.done)
- setWinIdDone();
- });
- bgPort = backgroundPort;
- winPort = windowPort;
- initPageCallback = function() {
- bgPort.postMessage({
- startDone : true
- });
- };
- bgPort.addListener(function(message) {
- if (message.start)
- start(message);
- else if (message.getStylesheets) {
- initProcess(message.options);
- getStylesheets();
- } else if (message.setStylesheets)
- setData(message.data, getStylesheets, true);
- else if (message.getData)
- getData();
- else if (message.setData)
- setData(message.data, function() {
- bgPort.postMessage({
- setDataDone : true,
- data : window == top && sendContent ? holder.filters.document.getDoctype() + doc.outerHTML : null,
- favicoData : window == top && options.removeFrames && sendContent ? holder.filters.image.getFavicoData(doc) : null,
- frameCount : holder.filters.frame.count(doc),
- winID : winID
- });
- });
- else if (message.setDynamicData)
- setData(message.data, null, true);
- else if (message.getDocData)
- getDocData(message.data);
- else if (message.done)
- done(message.winProperties);
- });
- targetDoc = srcDoc;
- doc = targetDoc.documentElement;
- if (doc instanceof HTMLHtmlElement)
- bgPort.postMessage({
- init : true,
- topWindow : window == top,
- url : location.href,
- title : document.title
- });
- }
- };
- holder.init = function(currDoc, backgroundPort, windowPort) {
- holder.filters.init(currDoc);
- holder.ui.init(backgroundPort);
- holder.core.init(currDoc, backgroundPort, windowPort);
- };
- })(singlefile);
|