mirror of
https://github.com/chinchang/web-maker.git
synced 2025-07-29 01:30:16 +02:00
port saveAsHtml
This commit is contained in:
@@ -2,7 +2,7 @@ import { h, Component } from 'preact';
|
|||||||
import UserCodeMirror from './UserCodeMirror.jsx';
|
import UserCodeMirror from './UserCodeMirror.jsx';
|
||||||
import { computeHtml, computeCss, computeJs } from '../computes';
|
import { computeHtml, computeCss, computeJs } from '../computes';
|
||||||
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
||||||
import { log, writeFile, loadJS } from '../utils';
|
import { log, writeFile, loadJS, getCompleteHtml } from '../utils';
|
||||||
import { SplitPane } from './SplitPane.jsx';
|
import { SplitPane } from './SplitPane.jsx';
|
||||||
import { trackEvent } from '../analytics';
|
import { trackEvent } from '../analytics';
|
||||||
import CodeMirror from '../CodeMirror';
|
import CodeMirror from '../CodeMirror';
|
||||||
@@ -76,78 +76,15 @@ export default class ContentWrap extends Component {
|
|||||||
}
|
}
|
||||||
clearConsole() {}
|
clearConsole() {}
|
||||||
|
|
||||||
/* eslint max-params: ["error", 4] */
|
|
||||||
getCompleteHtml(html, css, js, isForExport) {
|
|
||||||
if (!this.props.currentItem) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
var externalJs = this.props.currentItem.externalLibs.js
|
|
||||||
.split('\n')
|
|
||||||
.reduce(function(scripts, url) {
|
|
||||||
return scripts + (url ? '\n<script src="' + url + '"></script>' : '');
|
|
||||||
}, '');
|
|
||||||
var externalCss = this.props.currentItem.externalLibs.css
|
|
||||||
.split('\n')
|
|
||||||
.reduce(function(links, url) {
|
|
||||||
return (
|
|
||||||
links +
|
|
||||||
(url ? '\n<link rel="stylesheet" href="' + url + '"></link>' : '')
|
|
||||||
);
|
|
||||||
}, '');
|
|
||||||
var contents =
|
|
||||||
'<!DOCTYPE html>\n' +
|
|
||||||
'<html>\n<head>\n' +
|
|
||||||
'<meta charset="UTF-8" />\n' +
|
|
||||||
externalCss +
|
|
||||||
'\n' +
|
|
||||||
'<style id="webmakerstyle">\n' +
|
|
||||||
css +
|
|
||||||
'\n</style>\n' +
|
|
||||||
'</head>\n' +
|
|
||||||
'<body>\n' +
|
|
||||||
html +
|
|
||||||
'\n' +
|
|
||||||
externalJs +
|
|
||||||
'\n';
|
|
||||||
|
|
||||||
if (!isForExport) {
|
|
||||||
contents +=
|
|
||||||
'<script src="' +
|
|
||||||
(chrome.extension
|
|
||||||
? chrome.extension.getURL('lib/screenlog.js')
|
|
||||||
: `${location.origin}${BASE_PATH}/lib/screenlog.js`) +
|
|
||||||
'"></script>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.jsMode === JsModes.ES6) {
|
|
||||||
contents +=
|
|
||||||
'<script src="' +
|
|
||||||
(chrome.extension
|
|
||||||
? chrome.extension.getURL('lib/transpilers/babel-polyfill.min.js')
|
|
||||||
: `${
|
|
||||||
location.origin
|
|
||||||
}${BASE_PATH}/lib/transpilers/babel-polyfill.min.js`) +
|
|
||||||
'"></script>';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof js === 'string') {
|
|
||||||
contents += '<script>\n' + js + '\n//# sourceURL=userscript.js';
|
|
||||||
} else {
|
|
||||||
var origin = chrome.i18n.getMessage()
|
|
||||||
? `chrome-extension://${chrome.i18n.getMessage('@@extension_id')}`
|
|
||||||
: `${location.origin}`;
|
|
||||||
contents +=
|
|
||||||
'<script src="' + `filesystem:${origin}/temporary/script.js` + '">';
|
|
||||||
}
|
|
||||||
contents += '\n</script>\n</body>\n</html>';
|
|
||||||
|
|
||||||
return contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
createPreviewFile(html, css, js) {
|
createPreviewFile(html, css, js) {
|
||||||
const shouldInlineJs =
|
const shouldInlineJs =
|
||||||
!window.webkitRequestFileSystem || !window.IS_EXTENSION;
|
!window.webkitRequestFileSystem || !window.IS_EXTENSION;
|
||||||
var contents = this.getCompleteHtml(html, css, shouldInlineJs ? js : null);
|
var contents = getCompleteHtml(
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
shouldInlineJs ? js : null,
|
||||||
|
this.props.currentItem
|
||||||
|
);
|
||||||
var blob = new Blob([contents], { type: 'text/plain;charset=UTF-8' });
|
var blob = new Blob([contents], { type: 'text/plain;charset=UTF-8' });
|
||||||
var blobjs = new Blob([js], { type: 'text/plain;charset=UTF-8' });
|
var blobjs = new Blob([js], { type: 'text/plain;charset=UTF-8' });
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@ export default class Footer extends Component {
|
|||||||
<div id="footer" class="footer">
|
<div id="footer" class="footer">
|
||||||
<div class="footer__right fr">
|
<div class="footer__right fr">
|
||||||
<a
|
<a
|
||||||
|
onClick={this.props.saveHtmlBtnClickHandler}
|
||||||
id="saveHtmlBtn"
|
id="saveHtmlBtn"
|
||||||
class="mode-btn hint--rounded hint--top-left hide-on-mobile"
|
class="mode-btn hint--rounded hint--top-left hide-on-mobile"
|
||||||
data-hint="Save as HTML file"
|
data-hint="Save as HTML file"
|
||||||
|
@@ -9,7 +9,7 @@ import AddLibrary from './AddLibrary.jsx';
|
|||||||
import Modal from './Modal.jsx';
|
import Modal from './Modal.jsx';
|
||||||
import HelpModal from './HelpModal.jsx';
|
import HelpModal from './HelpModal.jsx';
|
||||||
import Login from './Login.jsx';
|
import Login from './Login.jsx';
|
||||||
import { log, generateRandomId, semverCompare } from '../utils';
|
import { log, generateRandomId, semverCompare, saveAsHtml } from '../utils';
|
||||||
import { itemService } from '../itemService';
|
import { itemService } from '../itemService';
|
||||||
import '../db';
|
import '../db';
|
||||||
import Notifications from './Notifications';
|
import Notifications from './Notifications';
|
||||||
@@ -446,40 +446,6 @@ export default class App extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFile() {
|
|
||||||
var htmlPromise = computeHtml();
|
|
||||||
var cssPromise = computeCss();
|
|
||||||
var jsPromise = computeJs(false);
|
|
||||||
Promise.all([htmlPromise, cssPromise, jsPromise]).then(function(result) {
|
|
||||||
var html = result[0],
|
|
||||||
css = result[1],
|
|
||||||
js = result[2];
|
|
||||||
|
|
||||||
var fileContent = getCompleteHtml(html, css, js, true);
|
|
||||||
|
|
||||||
var d = new Date();
|
|
||||||
var fileName = [
|
|
||||||
'web-maker',
|
|
||||||
d.getFullYear(),
|
|
||||||
d.getMonth() + 1,
|
|
||||||
d.getDate(),
|
|
||||||
d.getHours(),
|
|
||||||
d.getMinutes(),
|
|
||||||
d.getSeconds()
|
|
||||||
].join('-');
|
|
||||||
|
|
||||||
if (this.state.currentItem.title) {
|
|
||||||
fileName = this.state.currentItem.title;
|
|
||||||
}
|
|
||||||
fileName += '.html';
|
|
||||||
|
|
||||||
var blob = new Blob([fileContent], { type: 'text/html;charset=UTF-8' });
|
|
||||||
utils.downloadFile(fileName, blob);
|
|
||||||
|
|
||||||
trackEvent('fn', 'saveFileComplete');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
closeAllOverlays() {
|
closeAllOverlays() {
|
||||||
if (this.state.isSavedItemPaneOpen) {
|
if (this.state.isSavedItemPaneOpen) {
|
||||||
this.setState({ isSavedItemPaneOpen: false });
|
this.setState({ isSavedItemPaneOpen: false });
|
||||||
@@ -833,6 +799,11 @@ export default class App extends Component {
|
|||||||
trackEvent('ui', 'openInCodepen');
|
trackEvent('ui', 'openInCodepen');
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
saveHtmlBtnClickHandler(e) {
|
||||||
|
saveAsHtml(this.state.currentItem);
|
||||||
|
trackEvent('ui', 'saveHtmlClick');
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@@ -880,6 +851,7 @@ export default class App extends Component {
|
|||||||
this
|
this
|
||||||
)}
|
)}
|
||||||
codepenBtnClickHandler={this.codepenBtnClickHandler.bind(this)}
|
codepenBtnClickHandler={this.codepenBtnClickHandler.bind(this)}
|
||||||
|
saveHtmlBtnClickHandler={this.saveHtmlBtnClickHandler.bind(this)}
|
||||||
hasUnseenChangelog={this.state.hasUnseenChangelog}
|
hasUnseenChangelog={this.state.hasUnseenChangelog}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,114 +1,123 @@
|
|||||||
import {
|
import {
|
||||||
trackEvent
|
trackEvent
|
||||||
} from './analytics';
|
} from './analytics';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
deferred
|
computeHtml,
|
||||||
} from './deferred';
|
computeCss,
|
||||||
window.DEBUG = document.cookie.indexOf('wmdebug') > -1;
|
computeJs
|
||||||
|
} from './computes';
|
||||||
|
import {
|
||||||
|
JsModes
|
||||||
|
} from './codeModes';
|
||||||
|
import {
|
||||||
|
deferred
|
||||||
|
} from './deferred';
|
||||||
|
|
||||||
window.$ = document.querySelector.bind(document);
|
window.DEBUG = document.cookie.indexOf('wmdebug') > -1;
|
||||||
window.$all = selector => [...document.querySelectorAll(selector)];
|
window.$ = document.querySelector.bind(document);
|
||||||
var alphaNum =
|
window.$all = selector => [...document.querySelectorAll(selector)];
|
||||||
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
const BASE_PATH = chrome.extension || window.DEBUG ? '/' : '/app';
|
||||||
|
|
||||||
/**
|
var alphaNum = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||||
* The following 2 functions are supposed to find the next/previous sibling until the
|
|
||||||
* passed `selector` is matched. But for now it actually finds the next/previous
|
/**
|
||||||
* element of `this` element in the list of `selector` matched element inside `this`'s
|
* The following 2 functions are supposed to find the next/previous sibling until the
|
||||||
* parent.
|
* passed `selector` is matched. But for now it actually finds the next/previous
|
||||||
* @param Selector that should match for next siblings
|
* element of `this` element in the list of `selector` matched element inside `this`'s
|
||||||
* @return element Next element that mathes `selector`
|
* parent.
|
||||||
*/
|
* @param Selector that should match for next siblings
|
||||||
Node.prototype.nextUntil = function (selector) {
|
* @return element Next element that mathes `selector`
|
||||||
const siblings = [...this.parentNode.querySelectorAll(selector)];
|
*/
|
||||||
const index = siblings.indexOf(this);
|
Node.prototype.nextUntil = function (selector) {
|
||||||
return siblings[index + 1];
|
const siblings = [...this.parentNode.querySelectorAll(selector)];
|
||||||
|
const index = siblings.indexOf(this);
|
||||||
|
return siblings[index + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Safari doesn't have this!
|
||||||
|
window.requestIdleCallback =
|
||||||
|
window.requestIdleCallback ||
|
||||||
|
function (fn) {
|
||||||
|
setTimeout(fn, 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Safari doesn't have this!
|
/*
|
||||||
window.requestIdleCallback =
|
* @param Selector that should match for next siblings
|
||||||
window.requestIdleCallback ||
|
* @return element Next element that mathes `selector`
|
||||||
function (fn) {
|
*/
|
||||||
setTimeout(fn, 10);
|
Node.prototype.previousUntil = function (selector) {
|
||||||
};
|
const siblings = [...this.parentNode.querySelectorAll(selector)];
|
||||||
|
const index = siblings.indexOf(this);
|
||||||
|
return siblings[index - 1];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
// https://github.com/substack/semver-compare/blob/master/index.js
|
||||||
* @param Selector that should match for next siblings
|
export function semverCompare(a, b) {
|
||||||
* @return element Next element that mathes `selector`
|
var pa = a.split('.');
|
||||||
*/
|
var pb = b.split('.');
|
||||||
Node.prototype.previousUntil = function (selector) {
|
for (var i = 0; i < 3; i++) {
|
||||||
const siblings = [...this.parentNode.querySelectorAll(selector)];
|
var na = Number(pa[i]);
|
||||||
const index = siblings.indexOf(this);
|
var nb = Number(pb[i]);
|
||||||
return siblings[index - 1];
|
if (na > nb) {
|
||||||
};
|
return 1;
|
||||||
|
|
||||||
// https://github.com/substack/semver-compare/blob/master/index.js
|
|
||||||
export function semverCompare(a, b) {
|
|
||||||
var pa = a.split('.');
|
|
||||||
var pb = b.split('.');
|
|
||||||
for (var i = 0; i < 3; i++) {
|
|
||||||
var na = Number(pa[i]);
|
|
||||||
var nb = Number(pb[i]);
|
|
||||||
if (na > nb) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (nb > na) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!isNaN(na) && isNaN(nb)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (isNaN(na) && !isNaN(nb)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
if (nb > na) {
|
||||||
}
|
return -1;
|
||||||
|
|
||||||
export function generateRandomId(len) {
|
|
||||||
var length = len || 10;
|
|
||||||
var id = '';
|
|
||||||
for (var i = length; i--;) {
|
|
||||||
id += alphaNum[~~(Math.random() * alphaNum.length)];
|
|
||||||
}
|
}
|
||||||
return id;
|
if (!isNaN(na) && isNaN(nb)) {
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
export function onButtonClick(btn, listener) {
|
if (isNaN(na) && !isNaN(nb)) {
|
||||||
btn.addEventListener('click', function buttonClickListener(e) {
|
return -1;
|
||||||
listener(e);
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function log() {
|
|
||||||
if (window.DEBUG) {
|
|
||||||
console.log(Date.now(), ...arguments);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
export function generateRandomId(len) {
|
||||||
* Adds timed limit on the loops found in the passed code.
|
var length = len || 10;
|
||||||
* Contributed by Ariya Hidayat!
|
var id = '';
|
||||||
* @param code {string} Code to be protected from infinite loops.
|
for (var i = length; i--;) {
|
||||||
*/
|
id += alphaNum[~~(Math.random() * alphaNum.length)];
|
||||||
export function addInfiniteLoopProtection(code, {
|
}
|
||||||
timeout
|
return id;
|
||||||
}) {
|
}
|
||||||
var loopId = 1;
|
|
||||||
var patches = [];
|
|
||||||
var varPrefix = '_wmloopvar';
|
|
||||||
var varStr = 'var %d = Date.now();\n';
|
|
||||||
var checkStr = `\nif (Date.now() - %d > ${timeout}) { window.top.previewException(new Error("Infinite loop")); break;}\n`;
|
|
||||||
|
|
||||||
esprima.parse(code, {
|
export function onButtonClick(btn, listener) {
|
||||||
|
btn.addEventListener('click', function buttonClickListener(e) {
|
||||||
|
listener(e);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function log() {
|
||||||
|
if (window.DEBUG) {
|
||||||
|
console.log(Date.now(), ...arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds timed limit on the loops found in the passed code.
|
||||||
|
* Contributed by Ariya Hidayat!
|
||||||
|
* @param code {string} Code to be protected from infinite loops.
|
||||||
|
*/
|
||||||
|
export function addInfiniteLoopProtection(code, {
|
||||||
|
timeout
|
||||||
|
}) {
|
||||||
|
var loopId = 1;
|
||||||
|
var patches = [];
|
||||||
|
var varPrefix = '_wmloopvar';
|
||||||
|
var varStr = 'var %d = Date.now();\n';
|
||||||
|
var checkStr = `\nif (Date.now() - %d > ${timeout}) { window.top.previewException(new Error("Infinite loop")); break;}\n`;
|
||||||
|
|
||||||
|
esprima.parse(
|
||||||
|
code, {
|
||||||
tolerant: true,
|
tolerant: true,
|
||||||
range: true,
|
range: true,
|
||||||
jsx: true
|
jsx: true
|
||||||
}, function (
|
},
|
||||||
node
|
function (node) {
|
||||||
) {
|
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'DoWhileStatement':
|
case 'DoWhileStatement':
|
||||||
case 'ForStatement':
|
case 'ForStatement':
|
||||||
@@ -145,159 +154,263 @@
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
patches
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return b.pos - a.pos;
|
||||||
|
})
|
||||||
|
.forEach(function (patch) {
|
||||||
|
code = code.slice(0, patch.pos) + patch.str + code.slice(patch.pos);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
patches
|
return code;
|
||||||
.sort(function (a, b) {
|
}
|
||||||
return b.pos - a.pos;
|
|
||||||
})
|
|
||||||
.forEach(function (patch) {
|
|
||||||
code = code.slice(0, patch.pos) + patch.str + code.slice(patch.pos);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
export function getHumanDate(timestamp) {
|
||||||
return code;
|
var d = new Date(timestamp);
|
||||||
|
var retVal =
|
||||||
|
d.getDate() +
|
||||||
|
' ' + [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December'
|
||||||
|
][d.getMonth()] +
|
||||||
|
' ' +
|
||||||
|
d.getFullYear();
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a one-time event
|
||||||
|
export function once(node, type, callback) {
|
||||||
|
// create event
|
||||||
|
node.addEventListener(type, function (e) {
|
||||||
|
// remove event
|
||||||
|
e.target.removeEventListener(type, arguments.callee);
|
||||||
|
// call handler
|
||||||
|
return callback(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function downloadFile(fileName, blob) {
|
||||||
|
function downloadWithAnchor() {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = window.URL.createObjectURL(blob);
|
||||||
|
a.download = fileName;
|
||||||
|
a.style.display = 'none';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
a.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHumanDate(timestamp) {
|
|
||||||
var d = new Date(timestamp);
|
|
||||||
var retVal =
|
|
||||||
d.getDate() +
|
|
||||||
' ' + [
|
|
||||||
'January',
|
|
||||||
'February',
|
|
||||||
'March',
|
|
||||||
'April',
|
|
||||||
'May',
|
|
||||||
'June',
|
|
||||||
'July',
|
|
||||||
'August',
|
|
||||||
'September',
|
|
||||||
'October',
|
|
||||||
'November',
|
|
||||||
'December'
|
|
||||||
][d.getMonth()] +
|
|
||||||
' ' +
|
|
||||||
d.getFullYear();
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a one-time event
|
|
||||||
export function once(node, type, callback) {
|
|
||||||
// create event
|
|
||||||
node.addEventListener(type, function (e) {
|
|
||||||
// remove event
|
|
||||||
e.target.removeEventListener(type, arguments.callee);
|
|
||||||
// call handler
|
|
||||||
return callback(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function downloadFile(fileName, blob) {
|
|
||||||
function downloadWithAnchor() {
|
|
||||||
var a = document.createElement('a');
|
|
||||||
a.href = window.URL.createObjectURL(blob);
|
|
||||||
a.download = fileName;
|
|
||||||
a.style.display = 'none';
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
a.remove();
|
|
||||||
}
|
|
||||||
if (window.IS_EXTENSION) {
|
|
||||||
chrome.downloads.download({
|
|
||||||
url: window.URL.createObjectURL(blob),
|
|
||||||
filename: fileName,
|
|
||||||
saveAs: true
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
// If there was an error, just download the file using ANCHOR method.
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
downloadWithAnchor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
downloadWithAnchor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function writeFile(name, blob, cb) {
|
|
||||||
var fileWritten = false;
|
|
||||||
|
|
||||||
function getErrorHandler(type) {
|
|
||||||
return function () {
|
|
||||||
log(arguments);
|
|
||||||
trackEvent('fn', 'error', type);
|
|
||||||
// When there are too many write errors, show a message.
|
|
||||||
writeFile.errorCount = (writeFile.errorCount || 0) + 1;
|
|
||||||
if (writeFile.errorCount === 4) {
|
|
||||||
setTimeout(function () {
|
|
||||||
alert(
|
|
||||||
"Oops! Seems like your preview isn't updating. It's recommended to switch to the web app: https://webmakerapp.com/app/.\n\n If you still want to get the extension working, please try the following steps until it fixes:\n - Refresh Web Maker\n - Restart browser\n - Update browser\n - Reinstall Web Maker (don't forget to export all your creations from saved items pane (click the OPEN button) before reinstalling)\n\nIf nothing works, please tweet out to @webmakerApp."
|
|
||||||
);
|
|
||||||
trackEvent('ui', 'writeFileMessageSeen');
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// utils.log('writing file ', name);
|
|
||||||
window.webkitRequestFileSystem(
|
|
||||||
window.TEMPORARY,
|
|
||||||
1024 * 1024 * 5,
|
|
||||||
function (fs) {
|
|
||||||
fs.root.getFile(
|
|
||||||
name, {
|
|
||||||
create: true
|
|
||||||
},
|
|
||||||
function (fileEntry) {
|
|
||||||
fileEntry.createWriter(fileWriter => {
|
|
||||||
function onWriteComplete() {
|
|
||||||
if (fileWritten) {
|
|
||||||
// utils.log('file written ', name);
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
fileWritten = true;
|
|
||||||
// Set the write pointer to starting of file
|
|
||||||
fileWriter.seek(0);
|
|
||||||
fileWriter.write(blob);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
fileWriter.onwriteend = onWriteComplete;
|
|
||||||
// Empty the file contents
|
|
||||||
fileWriter.truncate(0);
|
|
||||||
// utils.log('truncating file ', name);
|
|
||||||
}, getErrorHandler('createWriterFail'));
|
|
||||||
},
|
|
||||||
getErrorHandler('getFileFail')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
getErrorHandler('webkitRequestFileSystemFail')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadJS(src) {
|
|
||||||
var d = deferred();
|
|
||||||
var ref = window.document.getElementsByTagName('script')[0];
|
|
||||||
var script = window.document.createElement('script');
|
|
||||||
script.src = src;
|
|
||||||
script.async = true;
|
|
||||||
ref.parentNode.insertBefore(script, ref);
|
|
||||||
script.onload = function () {
|
|
||||||
d.resolve();
|
|
||||||
};
|
|
||||||
return d.promise;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.chrome = window.chrome || {};
|
|
||||||
window.chrome.i18n = {
|
|
||||||
getMessage: () => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.IS_EXTENSION = !!window.chrome.extension;
|
|
||||||
if (window.IS_EXTENSION) {
|
if (window.IS_EXTENSION) {
|
||||||
document.body.classList.add('is-extension');
|
chrome.downloads.download({
|
||||||
|
url: window.URL.createObjectURL(blob),
|
||||||
|
filename: fileName,
|
||||||
|
saveAs: true
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
// If there was an error, just download the file using ANCHOR method.
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
downloadWithAnchor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
document.body.classList.add('is-app');
|
downloadWithAnchor();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function writeFile(name, blob, cb) {
|
||||||
|
var fileWritten = false;
|
||||||
|
|
||||||
|
function getErrorHandler(type) {
|
||||||
|
return function () {
|
||||||
|
log(arguments);
|
||||||
|
trackEvent('fn', 'error', type);
|
||||||
|
// When there are too many write errors, show a message.
|
||||||
|
writeFile.errorCount = (writeFile.errorCount || 0) + 1;
|
||||||
|
if (writeFile.errorCount === 4) {
|
||||||
|
setTimeout(function () {
|
||||||
|
alert(
|
||||||
|
"Oops! Seems like your preview isn't updating. It's recommended to switch to the web app: https://webmakerapp.com/app/.\n\n If you still want to get the extension working, please try the following steps until it fixes:\n - Refresh Web Maker\n - Restart browser\n - Update browser\n - Reinstall Web Maker (don't forget to export all your creations from saved items pane (click the OPEN button) before reinstalling)\n\nIf nothing works, please tweet out to @webmakerApp."
|
||||||
|
);
|
||||||
|
trackEvent('ui', 'writeFileMessageSeen');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// utils.log('writing file ', name);
|
||||||
|
window.webkitRequestFileSystem(
|
||||||
|
window.TEMPORARY,
|
||||||
|
1024 * 1024 * 5,
|
||||||
|
function (fs) {
|
||||||
|
fs.root.getFile(
|
||||||
|
name, {
|
||||||
|
create: true
|
||||||
|
},
|
||||||
|
function (fileEntry) {
|
||||||
|
fileEntry.createWriter(fileWriter => {
|
||||||
|
function onWriteComplete() {
|
||||||
|
if (fileWritten) {
|
||||||
|
// utils.log('file written ', name);
|
||||||
|
return cb();
|
||||||
|
}
|
||||||
|
fileWritten = true;
|
||||||
|
// Set the write pointer to starting of file
|
||||||
|
fileWriter.seek(0);
|
||||||
|
fileWriter.write(blob);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fileWriter.onwriteend = onWriteComplete;
|
||||||
|
// Empty the file contents
|
||||||
|
fileWriter.truncate(0);
|
||||||
|
// utils.log('truncating file ', name);
|
||||||
|
}, getErrorHandler('createWriterFail'));
|
||||||
|
},
|
||||||
|
getErrorHandler('getFileFail')
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getErrorHandler('webkitRequestFileSystemFail')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadJS(src) {
|
||||||
|
var d = deferred();
|
||||||
|
var ref = window.document.getElementsByTagName('script')[0];
|
||||||
|
var script = window.document.createElement('script');
|
||||||
|
script.src = src;
|
||||||
|
script.async = true;
|
||||||
|
ref.parentNode.insertBefore(script, ref);
|
||||||
|
script.onload = function () {
|
||||||
|
d.resolve();
|
||||||
|
};
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCompleteHtml(html, css, js, item, isForExport) {
|
||||||
|
if (!item) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
var externalJs = item.externalLibs.js
|
||||||
|
.split('\n')
|
||||||
|
.reduce(function (scripts, url) {
|
||||||
|
return scripts + (url ? '\n<script src="' + url + '"></script>' : '');
|
||||||
|
}, '');
|
||||||
|
var externalCss = item.externalLibs.css
|
||||||
|
.split('\n')
|
||||||
|
.reduce(function (links, url) {
|
||||||
|
return (
|
||||||
|
links +
|
||||||
|
(url ? '\n<link rel="stylesheet" href="' + url + '"></link>' : '')
|
||||||
|
);
|
||||||
|
}, '');
|
||||||
|
var contents =
|
||||||
|
'<!DOCTYPE html>\n' +
|
||||||
|
'<html>\n<head>\n' +
|
||||||
|
'<meta charset="UTF-8" />\n' +
|
||||||
|
externalCss +
|
||||||
|
'\n' +
|
||||||
|
'<style id="webmakerstyle">\n' +
|
||||||
|
css +
|
||||||
|
'\n</style>\n' +
|
||||||
|
'</head>\n' +
|
||||||
|
'<body>\n' +
|
||||||
|
html +
|
||||||
|
'\n' +
|
||||||
|
externalJs +
|
||||||
|
'\n';
|
||||||
|
|
||||||
|
if (!isForExport) {
|
||||||
|
contents +=
|
||||||
|
'<script src="' +
|
||||||
|
(chrome.extension ?
|
||||||
|
chrome.extension.getURL('lib/screenlog.js') :
|
||||||
|
`${location.origin}${BASE_PATH}/lib/screenlog.js`) +
|
||||||
|
'"></script>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.jsMode === JsModes.ES6) {
|
||||||
|
contents +=
|
||||||
|
'<script src="' +
|
||||||
|
(chrome.extension ?
|
||||||
|
chrome.extension.getURL('lib/transpilers/babel-polyfill.min.js') :
|
||||||
|
`${
|
||||||
|
location.origin
|
||||||
|
}${BASE_PATH}/lib/transpilers/babel-polyfill.min.js`) +
|
||||||
|
'"></script>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof js === 'string') {
|
||||||
|
contents += '<script>\n' + js + '\n//# sourceURL=userscript.js';
|
||||||
|
} else {
|
||||||
|
var origin = chrome.i18n.getMessage() ?
|
||||||
|
`chrome-extension://${chrome.i18n.getMessage('@@extension_id')}` :
|
||||||
|
`${location.origin}`;
|
||||||
|
contents +=
|
||||||
|
'<script src="' + `filesystem:${origin}/temporary/script.js` + '">';
|
||||||
|
}
|
||||||
|
contents += '\n</script>\n</body>\n</html>';
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveAsHtml(item) {
|
||||||
|
var htmlPromise = computeHtml(item.html, item.htmlMode);
|
||||||
|
var cssPromise = computeCss(item.css, item.cssMode);
|
||||||
|
var jsPromise = computeJs(item.js, item.jsMode, false);
|
||||||
|
Promise.all([htmlPromise, cssPromise, jsPromise]).then(function (result) {
|
||||||
|
var html = result[0],
|
||||||
|
css = result[1],
|
||||||
|
js = result[2];
|
||||||
|
|
||||||
|
var fileContent = getCompleteHtml(html, css, js, item, true);
|
||||||
|
|
||||||
|
var d = new Date();
|
||||||
|
var fileName = [
|
||||||
|
'web-maker',
|
||||||
|
d.getFullYear(),
|
||||||
|
d.getMonth() + 1,
|
||||||
|
d.getDate(),
|
||||||
|
d.getHours(),
|
||||||
|
d.getMinutes(),
|
||||||
|
d.getSeconds()
|
||||||
|
].join('-');
|
||||||
|
|
||||||
|
if (item.title) {
|
||||||
|
fileName = item.title;
|
||||||
|
}
|
||||||
|
fileName += '.html';
|
||||||
|
|
||||||
|
var blob = new Blob([fileContent], {
|
||||||
|
type: 'text/html;charset=UTF-8'
|
||||||
|
});
|
||||||
|
downloadFile(fileName, blob);
|
||||||
|
|
||||||
|
trackEvent('fn', 'saveFileComplete');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.chrome = window.chrome || {};
|
||||||
|
window.chrome.i18n = {
|
||||||
|
getMessage: () => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.IS_EXTENSION = !!window.chrome.extension;
|
||||||
|
if (window.IS_EXTENSION) {
|
||||||
|
document.body.classList.add('is-extension');
|
||||||
|
} else {
|
||||||
|
document.body.classList.add('is-app');
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user