// ==UserScript==
// @name SingleFile - 单文件保存网页
// @namespace SingleFile
// @version 0.3
// @description try to take over the world!
// @author PY-DNG
// @include *
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function() {
'use strict';
// User Swiches
const developer = true;
// variants
let i, j;
// Get HTML
const HTML_ORGINAL = document.lastChild.outerHTML;
let HTMLDOC = new DOMParser().parseFromString(HTML_ORGINAL, 'text/html');
if (developer) {console.log('HTML_ORGINAL', HTML_ORGINAL, HTMLDOC);};
// Remove <script>s
const scripts = HTMLDOC.querySelectorAll('script');
for (i = 0; i < scripts.length; i++) {
scripts[i].parentElement.removeChild(scripts[i]);
}
if (developer) {console.log('<script> DEALED', HTMLDOC, scripts);};
// Deal CSS <link>s
let CSSs = {loaded: [], style: []};
let CSSLinks = HTMLDOC.querySelectorAll('link[rel="stylesheet"]');
for (i = 0; i < CSSLinks.length; i++) {
CSSs.loaded[i] = null;
getCSSFromLink(CSSLinks, CSSs, i);
}
if (developer) {wait();};
// Deal background pictures
let PICs = {loaded: [], picture: [], base64: []};
const allEms = document.querySelectorAll('*');
let PICLinks = [];
for (let i = 0, j = 0; i < allEms.length; i++) {
const style = getComputedStyle(allEms[i]);
if (/^url\([\'"].+[\'"]\)$/.test(style.backgroundImage)) {
PICs.loaded[j] = null;
PICLinks[j] = style.backgroundImage;
console.log('backgroundImage', PICLinks[j], PICLinks[j].match(/^url\([\'"](.+)[\'"]\)$/)[1]);
getPICFromLink(PICLinks, PICs, j);
j++;
}
}
// Function: Log in console while css dealing finished
function wait() {
if(CSSs.loaded.includes(null)) {
setTimeout(wait, 100);
console.log('css dealing');
} else {
console.log('CSS DEALED', HTMLDOC, CSSs);
}
};
function getCSSFromLink(CSSLinks, CSSs, index) {
GM_xmlhttpRequest({
method: 'GET',
url: CSSLinks[index].href,
responseType: 'text',
onload: function(re) {
if (re.readyState === 4) {
// request success
CSSs.loaded[index] = true;
CSSs.style[index] = re.responseText;
CSSLinks[index].outerHTML = '<style>' + CSSs.style[index] + '</style>';
CSSLinks[index].outerHTML = CSSLinks[index].outerHTML.replace(/(<\/style>)+$/, '</style>')
} else {
// request failed
console.log('XMLHttpRequest get CSS error:', CSSLinks, CSSs, index, re);
if (developer) {debugger};
CSSs.loaded[index] = false;
}
},
onabort : function() {CSSs.loaded[index] = false;}
})
}
function getPICFromLink(PICLinks, PICs, index) {
GM_xmlhttpRequest({
method: 'GET',
url: PICLinks.hasOwnProperty('src') ? PICLinks[index].src : PICLinks[index].match(/^url\([\'"](.+)[\'"]\)$/)[1],
responseType: 'blob',
onload: function(re) {
if (re.readyState === 4) {
// request success
PICs.loaded[index] = true;
PICs.picture[index] = re.response;
blobToDataURI(PICs.picture[index], function(B64) {
PICs.base64[index] = B64;
console.log('PICGOT', index, PICs);
});
//if (developer) {console.log('CSS DEALED', index, [HTML, PICs]);};
} else {
// request failed
console.log('XMLHttpRequest get PIC error:', PICLinks, PICs, index, re);
if (developer) {debugger};
PICs.loaded[index] = false;
}
},
onabort : function() {PICs.loaded[index] = false;}
})
//console.log('request', index, PICLinks);
}
function blobToDataURI(blob, callback) {
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
callback(e.target.result);
}
}
function getBASE64FromPic(img) {
if (typeof(img) === 'string') {
//
}
}
})();