diff --git a/webmaker/src/components/ContentWrap.jsx b/webmaker/src/components/ContentWrap.jsx index caa6f80..813fc24 100644 --- a/webmaker/src/components/ContentWrap.jsx +++ b/webmaker/src/components/ContentWrap.jsx @@ -85,7 +85,6 @@ export default class ContentWrap extends Component { } }, this.updateDelay); } - clearConsole() {} createPreviewFile(html, css, js) { const shouldInlineJs = @@ -236,6 +235,8 @@ export default class ContentWrap extends Component { this.cm.css.refresh(); this.cm.js.refresh(); + this.clearConsole(); + // Set preview only when all modes are updated so that preview doesn't generate on partially // correct modes and also doesn't happen 3 times. Promise.all([ @@ -626,6 +627,9 @@ export default class ContentWrap extends Component { this.props.onCodeSettingsChange('css', settings); this.setPreviewContent(true); } + getDemoFrame(callback) { + callback(this.frame); + } render() { return ( diff --git a/webmaker/src/components/Footer.jsx b/webmaker/src/components/Footer.jsx index 1a652e6..a699d1f 100644 --- a/webmaker/src/components/Footer.jsx +++ b/webmaker/src/components/Footer.jsx @@ -55,7 +55,7 @@ export default class Footer extends Component { href="" id="screenshotBtn" class="mode-btn hint--rounded hint--top-left show-when-extension" - d-click="takeScreenshot" + onClick={this.props.screenshotBtnClickHandler} aria-label="Take screenshot of preview" > diff --git a/webmaker/src/components/app.jsx b/webmaker/src/components/app.jsx index a042d05..8fc8983 100644 --- a/webmaker/src/components/app.jsx +++ b/webmaker/src/components/app.jsx @@ -31,6 +31,7 @@ import Profile from './Profile'; import { auth } from '../auth'; import SupportDeveloperModal from './SupportDeveloperModal'; import KeyboardShortcutsModal from './KeyboardShortcutsModal'; +import { takeScreenshot } from '../takeScreenshot'; if (module.hot) { require('preact/debug'); @@ -839,6 +840,12 @@ export default class App extends Component { e.preventDefault(); trackEvent('ui', 'exportBtnClicked'); } + screenshotBtnClickHandler() { + this.contentWrap.getDemoFrame(frame => { + takeScreenshot(frame.getBoundingClientRect()); + }); + e.preventDefault(); + } render() { return ( @@ -892,6 +899,9 @@ export default class App extends Component { keyboardShortcutsBtnClickHandler={() => this.setState({ isKeyboardShortcutsModalOpen: true }) } + screenshotBtnClickHandler={this.screenshotBtnClickHandler.bind( + this + )} hasUnseenChangelog={this.state.hasUnseenChangelog} /> diff --git a/webmaker/src/takeScreenshot.js b/webmaker/src/takeScreenshot.js new file mode 100644 index 0000000..65bc854 --- /dev/null +++ b/webmaker/src/takeScreenshot.js @@ -0,0 +1,138 @@ +import { + handleDownloadsPermission +} from "./utils"; + +function saveScreenshot(dataURI) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs + var byteString = atob(dataURI.split(',')[1]); + + // separate out the mime component + var mimeString = dataURI + .split(',')[0] + .split(':')[1] + .split(';')[0]; + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + // create a blob for writing to a file + var blob = new Blob([ab], { + type: mimeString + }); + var size = blob.size + 1024 / 2; + + var d = new Date(); + var fileName = [ + 'web-maker-screenshot', + d.getFullYear(), + d.getMonth() + 1, + d.getDate(), + d.getHours(), + d.getMinutes(), + d.getSeconds() + ].join('-'); + fileName += '.png'; + + function onWriteEnd() { + var filePath = + 'filesystem:chrome-extension://' + + chrome.i18n.getMessage('@@extension_id') + + '/temporary/' + + fileName; + + chrome.downloads.download({ + url: filePath + }, + function () { + // If there was an error, just open the screenshot in a tab. + // This happens in incognito mode where extension cannot access filesystem. + if (chrome.runtime.lastError) { + window.open(filePath); + } + } + ); + } + + function errorHandler(e) { + utils.log(e); + } + + // create a blob for writing to a file + window.webkitRequestFileSystem( + window.TEMPORARY, + size, + fs => { + fs.root.getFile( + fileName, { + create: true + }, + fileEntry => { + fileEntry.createWriter(fileWriter => { + fileWriter.onwriteend = onWriteEnd; + fileWriter.write(blob); + }, errorHandler); + }, + errorHandler + ); + }, + errorHandler + ); +} + +export function takeScreenshot(boundRect) { + handleDownloadsPermission().then(() => { + // Hide tooltips so that they don't show in the screenshot + var s = document.createElement('style'); + s.textContent = + '[class*="hint"]:after, [class*="hint"]:before { display: none!important; }'; + document.body.appendChild(s); + + function onImgLoad(image) { + var c = document.createElement('canvas'); + var iframeBounds = boundRect; + c.width = iframeBounds.width; + c.height = iframeBounds.height; + var ctx = c.getContext('2d'); + var devicePixelRatio = window.devicePixelRatio || 1; + + ctx.drawImage( + image, + iframeBounds.left * devicePixelRatio, + iframeBounds.top * devicePixelRatio, + iframeBounds.width * devicePixelRatio, + iframeBounds.height * devicePixelRatio, + 0, + 0, + iframeBounds.width, + iframeBounds.height + ); + image.removeEventListener('load', onImgLoad); + saveScreenshot(c.toDataURL()); + } + + setTimeout(() => { + debugger + chrome.tabs.captureVisibleTab( + null, { + format: 'png', + quality: 100 + }, + function (dataURI) { + s.remove(); + if (dataURI) { + var image = new Image(); + image.src = dataURI; + image.addEventListener('load', () => onImgLoad(image, dataURI)); + } + } + ); + }, 50); + + trackEvent('ui', 'takeScreenshotBtnClick'); + }); +};