/** * Copyright 2015 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-env browser */ if ( 'serviceWorker' in navigator && location.protocol === 'https:' && location.href.indexOf('chrome-extension://') === -1 && location.href.indexOf('192.168') === -1 ) { // Delay registration until after the page has loaded, to ensure that our // precaching requests don't degrade the first visit experience. // See https://developers.google.com/web/fundamentals/instant-and-offline/service-worker/registration window.addEventListener('load', function() { // Your service-worker.js *must* be located at the top-level directory relative to your site. // It won't be able to control pages unless it's located at the same level or higher than them. // *Don't* register service worker file in, e.g., a scripts/ sub-directory! // See https://github.com/slightlyoff/ServiceWorker/issues/468 navigator.serviceWorker .register('service-worker.js') .then(function(reg) { // updatefound is fired if service-worker.js changes. reg.onupdatefound = function() { // The updatefound event implies that reg.installing is set; see // https://w3c.github.io/ServiceWorker/#service-worker-registration-updatefound-event var installingWorker = reg.installing; installingWorker.onstatechange = function() { /* eslint-disable default-case */ switch (installingWorker.state) { case 'installed': if (navigator.serviceWorker.controller) { // At this point, the old content will have been purged and the fresh content will // have been added to the cache. // It's the perfect time to display a "New content is available; please refresh." // message in the page's interface. console.log('New or updated content is available.'); if (window.alertsService) { window.alertsService.add( 'New version available. Please refresh the page.' ); } } else { // At this point, everything has been precached. // It's the perfect time to display a "Content is cached for offline use." message. console.log('Content is now available offline!'); if (window.alertsService) { window.alertsService.add( 'Web Maker is now ready to be used offline.' ); } } break; case 'redundant': console.error( 'The installing service worker became redundant.' ); break; } }; }; }) .catch(function(e) { console.error('Error during service worker registration:', e); }); }); } webpackJsonp([1],{ /***/ 0: /***/ (function(module, exports) { /* (ignored) */ /***/ }), /***/ 1: /***/ (function(module, exports) { /* (ignored) */ /***/ }), /***/ "JkW7": /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); // EXTERNAL MODULE: ../node_modules/preact/dist/preact.min.js var preact_min = __webpack_require__("KM04"); var preact_min_default = /*#__PURE__*/__webpack_require__.n(preact_min); // EXTERNAL MODULE: ./service-worker-registration.js var service_worker_registration = __webpack_require__("mGGS"); var service_worker_registration_default = /*#__PURE__*/__webpack_require__.n(service_worker_registration); // CONCATENATED MODULE: ./deferred.js var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function deferred() { var d = {}; var promise = new Promise(function (resolve, reject) { d.resolve = resolve; d.reject = reject; }); // Add the native promise as a key on deferred object. d.promise = promise; // Also move all props/methods of native promise on the deferred obj. return _extends(d, promise); } // CONCATENATED MODULE: ./codeModes.js const HtmlModes = { HTML: 'html', MARKDOWN: 'markdown', JADE: 'jade' // unsafe eval is put in manifest for this file }; const CssModes = { CSS: 'css', SCSS: 'scss', SASS: 'sass', LESS: 'less', STYLUS: 'stylus', ACSS: 'acss' }; const JsModes = { JS: 'js', ES6: 'es6', COFFEESCRIPT: 'coffee', TS: 'typescript' }; const modes = {}; modes[HtmlModes.HTML] = { label: 'HTML', cmMode: 'htmlmixed', codepenVal: 'none' }; modes[HtmlModes.MARKDOWN] = { label: 'Markdown', cmMode: 'markdown', codepenVal: 'markdown' }; modes[HtmlModes.JADE] = { label: 'Pug', cmMode: 'pug', codepenVal: 'pug' }; modes[JsModes.JS] = { label: 'JS', cmMode: 'javascript', codepenVal: 'none' }; modes[JsModes.COFFEESCRIPT] = { label: 'CoffeeScript', cmMode: 'coffeescript', codepenVal: 'coffeescript' }; modes[JsModes.ES6] = { label: 'ES6 (Babel)', cmMode: 'jsx', codepenVal: 'babel' }; modes[JsModes.TS] = { label: 'TypeScript', cmPath: 'jsx', cmMode: 'text/typescript-jsx', codepenVal: 'typescript' }; modes[CssModes.CSS] = { label: 'CSS', cmPath: 'css', cmMode: 'css', codepenVal: 'none' }; modes[CssModes.SCSS] = { label: 'SCSS', cmPath: 'css', cmMode: 'text/x-scss', codepenVal: 'scss' }; modes[CssModes.SASS] = { label: 'SASS', cmMode: 'sass', codepenVal: 'sass' }; modes[CssModes.LESS] = { label: 'LESS', cmPath: 'css', cmMode: 'text/x-less', codepenVal: 'less' }; modes[CssModes.STYLUS] = { label: 'Stylus', cmMode: 'stylus', codepenVal: 'stylus' }; modes[CssModes.ACSS] = { label: 'Atomic CSS', cmPath: 'css', cmMode: 'css', codepenVal: 'notsupported', cmDisable: true, hasSettings: true }; // CONCATENATED MODULE: ./computes.js const esprima = __webpack_require__("4E2n"); // computeHtml, computeCss & computeJs evaluate the final code according // to whatever mode is selected and resolve the returned promise with the code. function computeHtml(userCode, mode) { var code = userCode; var d = deferred(); if (mode === HtmlModes.HTML) { d.resolve({ code }); } else if (mode === HtmlModes.MARKDOWN) { d.resolve(window.marked ? { code: marked(code) } : { code }); } else if (mode === HtmlModes.JADE) { d.resolve(window.jade ? { code: jade.render(code) } : { code }); } return d.promise; } function computeCss(userCode, mode, settings) { var code = userCode; var d = deferred(); var errors; if (mode === CssModes.CSS) { d.resolve({ code }); } else if (mode === CssModes.SCSS || mode === CssModes.SASS) { if (window.sass && code) { window.sass.compile(code, { indentedSyntax: mode === CssModes.SASS }, function (result) { // Something was wrong if (result.line && result.message) { errors = { lang: 'css', data: [{ lineNumber: result.line - 1, message: result.message }] }; } d.resolve({ code: result.text, errors }); }); } else { d.resolve({ code }); } } else if (mode === CssModes.LESS) { less.render(code).then(function (result) { d.resolve({ code: result.css }); }, function (error) { errors = { lang: 'css', data: [{ lineNumber: error.line, message: error.message }] }; d.resolve({ code: '', errors }); }); } else if (mode === CssModes.STYLUS) { stylus(code).render(function (error, result) { if (error) { window.err = error; // Last line of message is the actual message var tempArr = error.message.split('\n'); tempArr.pop(); // This is empty string in the end errors = { lang: 'css', data: [{ lineNumber: +error.message.match(/stylus:(\d+):/)[1] - 298, message: tempArr.pop() }] }; } d.resolve({ code: result, errors }); }); } else if (mode === CssModes.ACSS) { if (!window.atomizer) { d.resolve({ code: '' }); } else { const html = code; const foundClasses = atomizer.findClassNames(html); var finalConfig; try { finalConfig = atomizer.getConfig(foundClasses, JSON.parse(settings.acssConfig)); } catch (e) { finalConfig = atomizer.getConfig(foundClasses, {}); } const acss = atomizer.getCss(finalConfig); d.resolve({ code: acss }); } } return d.promise; } /* eslint-disable max-params */ /* eslint-disable complexity */ function computeJs(userCode, mode, shouldPreventInfiniteLoops, infiniteLoopTimeout) { var code = userCode; var d = deferred(); var errors; if (!code) { d.resolve(''); return d.promise; } if (mode === JsModes.JS) { try { esprima.parse(code, { tolerant: true }); } catch (e) { errors = { lang: 'js', data: [{ lineNumber: e.lineNumber - 1, message: e.description }] }; } finally { if (shouldPreventInfiniteLoops !== false) { // If errors are found in last parse, we don't run infinite loop // protection otherwise it will again throw error. code = errors ? code : addInfiniteLoopProtection(code, { timeout: infiniteLoopTimeout }); } d.resolve({ code, errors }); } } else if (mode === JsModes.COFFEESCRIPT) { if (!window.CoffeeScript) { d.resolve(''); return d.promise; } try { code = CoffeeScript.compile(code, { bare: true }); } catch (e) { errors = { lang: 'js', data: [{ lineNumber: e.location.first_line, message: e.message }] }; } finally { if (shouldPreventInfiniteLoops !== false) { code = errors ? code : addInfiniteLoopProtection(code, { timeout: infiniteLoopTimeout }); } d.resolve({ code, errors }); } } else if (mode === JsModes.ES6) { if (!window.Babel) { d.resolve(''); return d.promise; } try { esprima.parse(code, { tolerant: true, jsx: true }); } catch (e) { errors = { lang: 'js', data: [{ lineNumber: e.lineNumber - 1, message: e.description }] }; } finally { code = Babel.transform(code, { presets: ['latest', 'stage-2', 'react'] }).code; if (shouldPreventInfiniteLoops !== false) { code = errors ? code : addInfiniteLoopProtection(code, { timeout: infiniteLoopTimeout }); } d.resolve({ code, errors }); } } else if (mode === JsModes.TS) { try { if (!window.ts) { d.resolve({ code: '' }); return d.promise; } code = ts.transpileModule(code, { reportDiagnostics: true, compilerOptions: { noEmitOnError: true, diagnostics: true, module: ts.ModuleKind.ES2015 } }); if (code.diagnostics.length) { /* eslint-disable no-throw-literal */ errors = { lang: 'js', data: [{ message: code.diagnostics[0].messageText, lineNumber: ts.getLineOfLocalPosition(code.diagnostics[0].file, code.diagnostics[0].start) - 1 }] }; } code = code.outputText; if (shouldPreventInfiniteLoops !== false && !errors) { code = addInfiniteLoopProtection(code, { timeout: infiniteLoopTimeout }); } d.resolve({ code, errors }); } catch (e) {} } return d.promise; } /* eslint-enable max-params */ /* eslint-enable complexity */ // CONCATENATED MODULE: ./fileUtils.js /** * Returns the extension from the file name. * @param {dtring} fileName File name */ function getExtensionFromFileName(fileName) { const type = fileName.match(/\.(\w+)$/); return type ? type[1] : ''; } /** * Returns a linear file list from a nested file strcuture. * It excludes the folders from the returned list. * @param {array} files Nested file structure */ function linearizeFiles(files) { function reduceToLinearFiles(_files) { return _files.reduce((list, currentFile) => { if (currentFile.isFolder) { return [...list, ...reduceToLinearFiles(currentFile.children)]; } return [...list, currentFile]; }, []); } return reduceToLinearFiles(files); } /** * Recursively iterates and assigns the `path` property to the files in passed files * array. * @param {array} files files structure for an item * @param {string} parentPath Parent path to prefix with all processed files */ function assignFilePaths(files, parentPath = '') { files.forEach(file => { file.path = parentPath ? `${parentPath}/${file.name}` : file.name; if (file.isFolder) { assignFilePaths(file.children, parentPath ? `${parentPath}/${file.name}` : file.name); } }); return files; } /** * Returns the file object and it's index that is direct child of passed files array with name as passed fileName. * If not found, returns -1 * @param {array} files files structure for an item * @param {string} fileName File/folder name */ function getChildFileFromName(files, fileName) { const index = files.findIndex(file => file.name === fileName); return { index, file: files[index] }; } /** * Returns the file object and it's index in its parent for the passed path. * If not found, returns {index:-1} * @param {array} files files structure for an item * @param {string} path Path of file to search */ function getFileFromPath(files, path) { let currentFolder = files; const pathPieces = path.split('/'); while (pathPieces.length > 1) { const folderName = pathPieces.shift(); currentFolder = getChildFileFromName(currentFolder, folderName).file.children; } // now we should be left with just one value in the pathPieces array - the actual file name return getChildFileFromName(currentFolder, pathPieces[0]); } /** * Returns the file object and it's index in its parent for the passed path. * If not found, returns {index:-1} * @param {array} files files structure for an item * @param {string} path Path of file to search */ function removeFileAtPath(files, path) { let currentFolder = files; const pathPieces = path.split('/'); while (pathPieces.length > 1) { const folderName = pathPieces.shift(); currentFolder = getChildFileFromName(currentFolder, folderName).file.children; } // now we should be left with just one value in the pathPieces array - the actual file name const { index } = getChildFileFromName(currentFolder, pathPieces[0]); currentFolder.splice(index, 1); } /** * Checks if a file with same name exists in the passed folder. * @param {object} folder Folder to search in * @param {string} fileName File name to search for */ function doesFileExistInFolder(folder, fileName) { const details = getChildFileFromName(folder.children, fileName); return !!details.file; } /** * Returns parent path of passed path * @param {string} path Path of file to find parent of */ function getParentPath(path) { const pathPieces = path.split('/'); if (pathPieces.length > 1) { return pathPieces.slice(0, -1).join('/'); } return ''; } /** * Fetches the files from a github repo and returns a suitable file structure. * @param {Promise} Promise of completition. Resolves to the files structure. */ function importGithubRepo(repoUrl) { let repoSlug, match; if (match = repoUrl.match(/github\.com\/([^/]*\/[^/]*)/)) { repoSlug = match[1]; } else { repoSlug = 'chinchang/github'; } const queryString = ''; function fetchFile(filepath) { return fetch(`https://api.github.com/repos/${repoSlug}/contents/${filepath}${queryString}`).then(response => response.json()); } function fetchDir(path, currentDir) { return fetch(`https://api.github.com/repos/${repoSlug}/contents/${path}${queryString}`).then(response => response.json()).then(response => { if (!response) { return Promise.resolve([]); } return Promise.all(response.map(file => { if (file.type === 'file') { return fetchFile(`${file.path}`).then(actualFile => { currentDir.push({ name: file.name, content: atob(actualFile.content) }); }); } else if (file.type === 'dir') { const newEntry = { name: file.name, children: [], isFolder: true }; currentDir.push(newEntry); return fetchDir(`${file.path}`, newEntry.children); } return Promise.resolve(); })); }); } const files = []; return fetchDir('', files).then(() => { return files; }); } // CONCATENATED MODULE: ./utils.js const utils_esprima = __webpack_require__("4E2n"); window.DEBUG = document.cookie.indexOf('wmdebug') > -1; window.$ = document.querySelector.bind(document); window.chrome = window.chrome || {}; window.chrome.i18n = { getMessage: () => {} }; window.$all = selector => [...document.querySelectorAll(selector)]; window.IS_EXTENSION = !!window.chrome.extension; const BASE_PATH = window.chrome.extension || window.DEBUG || "production" === 'development' ? '/' : '/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 * parent. * @param Selector that should match for next siblings * @return element Next element that mathes `selector` */ Node.prototype.nextUntil = function (selector) { const siblings = Array.from(this.parentNode.querySelectorAll(selector)); const index = siblings.indexOf(this); return siblings[index + 1]; }; /* * @param Selector that should match for next siblings * @return element Next element that mathes `selector` */ Node.prototype.previousUntil = function (selector) { const siblings = Array.from(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); }; // https://github.com/substack/semver-compare/blob/master/index.js 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; } function generateRandomId(len) { var length = len || 10; var id = ''; for (var i = length; i--;) { id += alphaNum[~~(Math.random() * alphaNum.length)]; } return id; } function onButtonClick(btn, listener) { btn.addEventListener('click', function buttonClickListener(e) { listener(e); return false; }); } function utils_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. */ 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`; utils_esprima.parse(code, { tolerant: true, range: true, jsx: true }, function (node) { switch (node.type) { case 'DoWhileStatement': case 'ForStatement': case 'ForInStatement': case 'ForOfStatement': case 'WhileStatement': var start = 1 + node.body.range[0]; var end = node.body.range[1]; var prolog = checkStr.replace('%d', varPrefix + loopId); var epilog = ''; if (node.body.type !== 'BlockStatement') { // `while(1) doThat()` becomes `while(1) {doThat()}` prolog = '{' + prolog; epilog = '}'; --start; } patches.push({ pos: start, str: prolog }); patches.push({ pos: end, str: epilog }); patches.push({ pos: node.range[0], str: varStr.replace('%d', varPrefix + loopId) }); ++loopId; break; default: 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 */ return code; } 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 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); }); } 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(); } // HACK: because chrome.downloads isn't working on optional permissions // anymore. downloadWithAnchor(); /* if (false && 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(); } */ } function writeFile(name, blob, cb) { var fileWritten = false; function getErrorHandler(type) { return function () { utils_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')); } 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; } function loadCss({ url, id }) { var d = deferred(); var style = window.document.createElement('link'); style.setAttribute('href', url); style.setAttribute('rel', 'stylesheet'); if (id) { style.setAttribute('id', id); } document.head.appendChild(style); style.onload = function () { d.resolve(); }; return d.promise; } /* eslint-disable max-params */ function getCompleteHtml(html, css, js, item, isForExport) { /* eslint-enable max-params */ if (!item) { return ''; } var externalJs = '', externalCss = ''; if (item.externalLibs) { externalJs = item.externalLibs.js.split('\n').reduce(function (scripts, url) { return scripts + (url ? '\n' : ''); }, ''); externalCss = item.externalLibs.css.split('\n').reduce(function (links, url) { return links + (url ? '\n' : ''); }, ''); } var contents = '\n' + '\n
\n' + '\n' + externalCss + '\n' + '\n' + '\n' + '\n' + html + '\n' + externalJs + '\n'; if (!isForExport) { contents += ''; } if (item.jsMode === JsModes.ES6) { contents += ''; } if (typeof js === 'string') { contents += '\n\n'; return contents; } 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(result => { var html = result[0].code, css = result[1].code, js = result[2].code; 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'); }); } function handleDownloadsPermission() { var d = deferred(); if (!window.IS_EXTENSION) { d.resolve(); return d.promise; } chrome.permissions.contains({ permissions: ['downloads'] }, function (result) { if (result) { d.resolve(); } else { chrome.permissions.request({ permissions: ['downloads'] }, function (granted) { if (granted) { trackEvent('fn', 'downloadsPermGiven'); d.resolve(); } else { d.reject(); } }); } }); return d.promise; } /** * Return the filename from a passed url. * http://a.com/path/file.png -> file.png */ function getFilenameFromUrl(url) { if (!url) { return ''; } return url.match(/\/([^/]*)$/)[1]; } function prettify({ file, content, type }) { const d = deferred(); if (file) { type = getExtensionFromFileName(file.name); content = file.content; } const worker = new Worker(chrome.extension ? chrome.extension.getURL('lib/prettier-worker.js') : `${BASE_PATH !== '/' ? BASE_PATH : ''}/lib/prettier-worker.js`); worker.postMessage({ content, type }); worker.addEventListener('message', e => { d.resolve(e.data); worker.terminate(); }); return d.promise; } if (window.IS_EXTENSION) { document.body.classList.add('is-extension'); } else { document.body.classList.add('is-app'); } // CONCATENATED MODULE: ./analytics.js /* global ga */ // eslint-disable-next-line max-params function trackEvent(category, action, label, value) { if (window.DEBUG) { utils_log('trackevent', category, action, label, value); return; } if (window.ga) { ga('send', 'event', category, action, label, value); } } // if online, load after sometime if (navigator.onLine && !window.DEBUG) { /* eslint-disable */ // prettier-ignore setTimeout(function () { (function (i, s, o, g, r, a, m) { i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () { (i[r].q = i[r].q || []).push(arguments); }, i[r].l = 1 * new Date(); a = s.createElement(o), m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m); })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga'); if (location.href.indexOf('chrome-extension://') === -1) { ga('create', 'UA-87786708-1'); } else { ga('create', 'UA-87786708-1', { 'cookieDomain': 'none' }); // required for chrome extension protocol ga('set', 'checkProtocolTask', function () {/* nothing */}); } ga('send', 'pageview'); }, 100); /* eslint-enable */ } // CONCATENATED MODULE: ./components/common.jsx var common__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } let common_Clickable = class Clickable extends preact_min["Component"] { handleClick(e) { const el = e.currentTarget; trackEvent(el.getAttribute('data-event-category'), el.getAttribute('data-event-action')); this.props.onClick(e); } render() { /* eslint-disable no-unused-vars */ const _props = this.props, { onClick, Tag } = _props, props = _objectWithoutProperties(_props, ['onClick', 'Tag']); /* eslint-enable no-unused-vars */ return Object(preact_min["h"])(Tag, common__extends({ onClick: this.handleClick.bind(this) }, props)); } }; function A(props) { return Object(preact_min["h"])(common_Clickable, common__extends({ Tag: 'a' }, props)); } function Button(props) { return Object(preact_min["h"])(common_Clickable, common__extends({ Tag: 'button' }, props)); } function AutoFocusInput(props) { return Object(preact_min["h"])('input', common__extends({ ref: el => el && setTimeout(() => el.focus(), 100) }, props)); } var _ref = Object(preact_min["h"])('div', { 'class': 'divider' }); function Divider(props) { return _ref; } // EXTERNAL MODULE: ../node_modules/@lingui/react/index.js var react = __webpack_require__("L5wL"); var react_default = /*#__PURE__*/__webpack_require__.n(react); // CONCATENATED MODULE: ./components/MainHeader.jsx const DEFAULT_PROFILE_IMG = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='#ccc' d='M12,19.2C9.5,19.2 7.29,17.92 6,16C6.03,14 10,12.9 12,12.9C14,12.9 17.97,14 18,16C16.71,17.92 14.5,19.2 12,19.2M12,5A3,3 0 0,1 15,8A3,3 0 0,1 12,11A3,3 0 0,1 9,8A3,3 0 0,1 12,5M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z' /%3E%3C/svg%3E"; var MainHeader__ref = Object(preact_min["h"])( 'svg', { style: 'width: 14px; height: 14px;' }, Object(preact_min["h"])('use', { xlinkHref: '#play-icon' }) ); var _ref2 = Object(preact_min["h"])(react["Trans"], { id: 'Run' }); var _ref3 = Object(preact_min["h"])(react["Trans"], { id: 'Add library' }); var MainHeader__ref4 = Object(preact_min["h"])( 'svg', { style: 'vertical-align:middle;width:14px;height:14px', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z' }) ); var _ref5 = Object(preact_min["h"])(react["Trans"], { id: 'New' }); var _ref6 = Object(preact_min["h"])( 'svg', { style: 'vertical-align:middle;width:14px;height:14px', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z' }) ); var _ref7 = Object(preact_min["h"])( 'svg', { 'class': 'btn-loader', width: '15', height: '15', stroke: '#fff' }, Object(preact_min["h"])('use', { xlinkHref: '#loader-icon' }) ); var _ref8 = Object(preact_min["h"])(react["Trans"], { id: 'Save' }); var _ref9 = Object(preact_min["h"])( 'svg', { style: 'width:14px;height:14px;vertical-align:middle;', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z' }) ); var _ref10 = Object(preact_min["h"])( 'svg', { 'class': 'btn-loader', width: '15', height: '15', stroke: '#fff' }, Object(preact_min["h"])('use', { xlinkHref: '#loader-icon' }) ); var _ref11 = Object(preact_min["h"])(react["Trans"], { id: 'Open' }); var _ref12 = Object(preact_min["h"])(react["Trans"], { id: 'Login' }); var _ref13 = Object(preact_min["h"])(react["Trans"], { id: 'Signup' }); function MainHeader(props) { return Object(preact_min["h"])( react["I18n"], null, ({ i18n }) => Object(preact_min["h"])( 'div', { 'class': 'main-header' }, Object(preact_min["h"])('input', { type: 'text', id: 'titleInput', title: 'Click to edit', 'class': 'item-title-input', value: props.title, onBlur: props.titleInputBlurHandler }), Object(preact_min["h"])( 'div', { 'class': 'main-header__btn-wrap flex flex-v-center' }, Object(preact_min["h"])( 'button', { id: 'runBtn', 'class': 'hide btn--dark flex flex-v-center hint--rounded hint--bottom-left', 'aria-label': 'Run preview (Ctrl/\u2318 + Shift + 5)', onClick: props.runBtnClickHandler }, MainHeader__ref, _ref2 ), !this.props.isFileMode && Object(preact_min["h"])( Button, { onClick: props.addLibraryBtnHandler, 'data-event-category': 'ui', 'data-event-action': 'addLibraryButtonClick', 'class': 'btn--dark flex-v-center hint--rounded hint--bottom-left', 'aria-label': i18n._( /*i18n*/{ id: 'Add a JS/CSS library' }) }, _ref3, ' ', Object(preact_min["h"])( 'span', { id: 'js-external-lib-count', style: `display:${props.externalLibCount ? 'inline' : 'none'}`, 'class': 'count-label' }, props.externalLibCount ) ), Object(preact_min["h"])( 'button', { 'class': 'btn--dark flex flex-v-center hint--rounded hint--bottom-left', 'aria-label': 'Start a new creation', onClick: props.newBtnHandler }, MainHeader__ref4, _ref5 ), Object(preact_min["h"])( 'button', { id: 'saveBtn', 'class': `btn--dark flex flex-v-center hint--rounded hint--bottom-left ${props.isSaving ? 'is-loading' : ''} ${props.unsavedEditCount ? 'is-marked' : 0}`, 'aria-label': 'Save current creation (Ctrl/\u2318 + S)', onClick: props.saveBtnHandler }, _ref6, _ref7, _ref8 ), Object(preact_min["h"])( 'button', { id: 'openItemsBtn', 'class': `btn--dark flex flex-v-center hint--rounded hint--bottom-left ${props.isFetchingItems ? 'is-loading' : ''}`, 'aria-label': 'Open a saved creation (Ctrl/\u2318 + O)', onClick: props.openBtnHandler }, _ref9, _ref10, _ref11 ), Object(preact_min["h"])( Button, { onClick: props.loginBtnHandler, 'data-event-category': 'ui', 'data-event-action': 'loginButtonClick', 'class': 'hide-on-login btn--dark flex flex-v-center hint--rounded hint--bottom-left', 'aria-label': 'Login/Signup' }, _ref12, '/', _ref13 ), Object(preact_min["h"])( Button, { onClick: props.profileBtnHandler, 'data-event-category': 'ui', 'data-event-action': 'headerAvatarClick', 'aria-label': 'See profile or Logout', 'class': 'hide-on-logout btn--dark hint--rounded hint--bottom-left' }, Object(preact_min["h"])('img', { id: 'headerAvatarImg', width: '20', src: props.user ? props.user.photoURL || DEFAULT_PROFILE_IMG : '', 'class': 'main-header__avatar-img' }) ) ) ) ); } // EXTERNAL MODULE: ../node_modules/codemirror/lib/codemirror.js var codemirror = __webpack_require__("tQq4"); var codemirror_default = /*#__PURE__*/__webpack_require__.n(codemirror); // CONCATENATED MODULE: ./CodeMirror.js // Most of the code from this file comes from: // https://github.com/codemirror/CodeMirror/blob/master/addon/mode/loadmode.js // Make CodeMirror available globally so the modes' can register themselves. window.CodeMirror = codemirror_default.a; if (!codemirror_default.a.modeURL) codemirror_default.a.modeURL = 'lib/codemirror/mode/%N/%N.js'; var loading = {}; function splitCallback(cont, n) { var countDown = n; return function () { if (--countDown === 0) cont(); }; } function ensureDeps(mode, cont) { var deps = codemirror_default.a.modes[mode].dependencies; if (!deps) return cont(); var missing = []; for (var i = 0; i < deps.length; ++i) { if (!codemirror_default.a.modes.hasOwnProperty(deps[i])) missing.push(deps[i]); } if (!missing.length) return cont(); var split = splitCallback(cont, missing.length); for (i = 0; i < missing.length; ++i) codemirror_default.a.requireMode(missing[i], split); } codemirror_default.a.requireMode = function (mode, cont) { if (typeof mode !== 'string') mode = mode.name; if (codemirror_default.a.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); var file = codemirror_default.a.modeURL.replace(/%N/g, mode); var script = document.createElement('script'); script.src = file; var others = document.getElementsByTagName('script')[0]; var list = loading[mode] = [cont]; codemirror_default.a.on(script, 'load', function () { ensureDeps(mode, function () { for (var i = 0; i < list.length; ++i) list[i](); }); }); others.parentNode.insertBefore(script, others); }; codemirror_default.a.autoLoadMode = function (instance, mode) { if (codemirror_default.a.modes.hasOwnProperty(mode)) return; codemirror_default.a.requireMode(mode, function () { instance.setOption('mode', instance.getOption('mode')); }); }; /* harmony default export */ var CodeMirror = (codemirror_default.a); // EXTERNAL MODULE: ../node_modules/codemirror/addon/edit/matchbrackets.js var matchbrackets = __webpack_require__("uQIK"); var matchbrackets_default = /*#__PURE__*/__webpack_require__.n(matchbrackets); // EXTERNAL MODULE: ../node_modules/codemirror/addon/edit/matchtags.js var matchtags = __webpack_require__("xdvC"); var matchtags_default = /*#__PURE__*/__webpack_require__.n(matchtags); // EXTERNAL MODULE: ../node_modules/codemirror/addon/edit/closebrackets.js var closebrackets = __webpack_require__("pTe4"); var closebrackets_default = /*#__PURE__*/__webpack_require__.n(closebrackets); // EXTERNAL MODULE: ../node_modules/codemirror/addon/edit/closetag.js var closetag = __webpack_require__("BVSg"); var closetag_default = /*#__PURE__*/__webpack_require__.n(closetag); // EXTERNAL MODULE: ../node_modules/codemirror/addon/comment/comment.js var comment = __webpack_require__("X7my"); var comment_default = /*#__PURE__*/__webpack_require__.n(comment); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/foldcode.js var foldcode = __webpack_require__("H+g/"); var foldcode_default = /*#__PURE__*/__webpack_require__.n(foldcode); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/foldgutter.js var foldgutter = __webpack_require__("tMLt"); var foldgutter_default = /*#__PURE__*/__webpack_require__.n(foldgutter); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/xml-fold.js var xml_fold = __webpack_require__("1JcR"); var xml_fold_default = /*#__PURE__*/__webpack_require__.n(xml_fold); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/indent-fold.js var indent_fold = __webpack_require__("5gBI"); var indent_fold_default = /*#__PURE__*/__webpack_require__.n(indent_fold); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/comment-fold.js var comment_fold = __webpack_require__("bU21"); var comment_fold_default = /*#__PURE__*/__webpack_require__.n(comment_fold); // EXTERNAL MODULE: ../node_modules/codemirror/addon/fold/brace-fold.js var brace_fold = __webpack_require__("zs1I"); var brace_fold_default = /*#__PURE__*/__webpack_require__.n(brace_fold); // EXTERNAL MODULE: ../node_modules/codemirror/addon/hint/show-hint.js var show_hint = __webpack_require__("rbVD"); var show_hint_default = /*#__PURE__*/__webpack_require__.n(show_hint); // EXTERNAL MODULE: ../node_modules/codemirror/addon/hint/javascript-hint.js var javascript_hint = __webpack_require__("6r0S"); var javascript_hint_default = /*#__PURE__*/__webpack_require__.n(javascript_hint); // EXTERNAL MODULE: ../node_modules/codemirror/addon/hint/xml-hint.js var xml_hint = __webpack_require__("LiPu"); var xml_hint_default = /*#__PURE__*/__webpack_require__.n(xml_hint); // EXTERNAL MODULE: ../node_modules/codemirror/addon/hint/html-hint.js var html_hint = __webpack_require__("IYZm"); var html_hint_default = /*#__PURE__*/__webpack_require__.n(html_hint); // EXTERNAL MODULE: ../node_modules/codemirror/addon/hint/css-hint.js var css_hint = __webpack_require__("SUmx"); var css_hint_default = /*#__PURE__*/__webpack_require__.n(css_hint); // EXTERNAL MODULE: ../node_modules/codemirror/addon/selection/active-line.js var active_line = __webpack_require__("gPKv"); var active_line_default = /*#__PURE__*/__webpack_require__.n(active_line); // EXTERNAL MODULE: ../node_modules/codemirror/addon/search/searchcursor.js var searchcursor = __webpack_require__("29F7"); var searchcursor_default = /*#__PURE__*/__webpack_require__.n(searchcursor); // EXTERNAL MODULE: ../node_modules/codemirror/addon/search/search.js var search_search = __webpack_require__("Jo/m"); var search_default = /*#__PURE__*/__webpack_require__.n(search_search); // EXTERNAL MODULE: ../node_modules/codemirror/addon/dialog/dialog.js var dialog = __webpack_require__("4e7A"); var dialog_default = /*#__PURE__*/__webpack_require__.n(dialog); // EXTERNAL MODULE: ../node_modules/codemirror/addon/search/jump-to-line.js var jump_to_line = __webpack_require__("ew/s"); var jump_to_line_default = /*#__PURE__*/__webpack_require__.n(jump_to_line); // EXTERNAL MODULE: ../node_modules/codemirror/mode/xml/xml.js var xml = __webpack_require__("HeB0"); var xml_default = /*#__PURE__*/__webpack_require__.n(xml); // EXTERNAL MODULE: ../node_modules/codemirror/mode/css/css.js var css_css = __webpack_require__("ggoL"); var css_default = /*#__PURE__*/__webpack_require__.n(css_css); // EXTERNAL MODULE: ../node_modules/codemirror/mode/javascript/javascript.js var javascript = __webpack_require__("qqFR"); var javascript_default = /*#__PURE__*/__webpack_require__.n(javascript); // EXTERNAL MODULE: ../node_modules/codemirror/mode/htmlmixed/htmlmixed.js var htmlmixed = __webpack_require__("AIXc"); var htmlmixed_default = /*#__PURE__*/__webpack_require__.n(htmlmixed); // EXTERNAL MODULE: ../node_modules/codemirror/keymap/sublime.js var sublime = __webpack_require__("Xc2M"); var sublime_default = /*#__PURE__*/__webpack_require__.n(sublime); // EXTERNAL MODULE: ../node_modules/codemirror/keymap/vim.js var vim = __webpack_require__("yLr7"); var vim_default = /*#__PURE__*/__webpack_require__.n(vim); // EXTERNAL MODULE: ../node_modules/code-blast-codemirror/code-blast.js var code_blast = __webpack_require__("AhD2"); var code_blast_default = /*#__PURE__*/__webpack_require__.n(code_blast); // EXTERNAL MODULE: ../node_modules/@emmetio/codemirror-plugin/dist/emmet-codemirror-plugin.es.js + 23 modules var emmet_codemirror_plugin_es = __webpack_require__("/QFk"); // CONCATENATED MODULE: ./components/CodeEditor.jsx var CodeEditor__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; Object(emmet_codemirror_plugin_es["a" /* default */])(CodeMirror); let monacoDepsDeferred; window.MonacoEnvironment = { getWorkerUrl(moduleId, label) { switch (label) { case 'html': return 'lib/monaco/workers/html.worker.bundle.js'; case 'json': return 'lib/monaco/workers/json.worker.bundle.js'; case 'css': case 'scss': case 'less': return 'lib/monaco/workers/css.worker.bundle.js'; case 'typescript': case 'javascript': return 'lib/monaco/workers/ts.worker.bundle.js'; default: return 'lib/monaco/workers/editor.worker.bundle.js'; } } }; let CodeEditor_CodeEditor = class CodeEditor extends preact_min["Component"] { componentDidMount() { this.initEditor(); } shouldComponentUpdate(nextProps) { if (nextProps.prefs !== this.props.prefs) { const { prefs } = nextProps; if (this.props.type === 'monaco') { this.instance.updateOptions({ fontSize: prefs.fontSize }); } else { this.instance.setOption('indentWithTabs', prefs.indentWith !== 'spaces'); this.instance.setOption('blastCode', prefs.isCodeBlastOn ? { effect: 2, shake: false } : false); this.instance.setOption('theme', prefs.editorTheme); this.instance.setOption('indentUnit', +prefs.indentSize); this.instance.setOption('tabSize', +prefs.indentSize); this.instance.setOption('keyMap', prefs.keymap); this.instance.setOption('lineWrapping', prefs.lineWrap); this.instance.setOption('lineWrapping', prefs.autoCloseTags); this.instance.refresh(); } } // Only condition when this component updates is when prop.type changes if (nextProps.type !== this.props.type) { if (this.node.parentElement.querySelector('.monaco-editor, .CodeMirror')) { this.node.parentElement.querySelector('.monaco-editor, .CodeMirror').remove(); } return true; } return false; } componentDidUpdate(prevProps) { // prop.type changed, reinit the editor this.initEditor(); } setModel(model) { this.editorReadyDeferred.promise.then(() => { this.instance.swapDoc ? this.instance.swapDoc(model) : this.instance.setModel(model); }); } setValue(value) { // HACK: We set a flag on window for an ultra-short duration, which 'change' // listener uses to set the change.origin to 'setValue', otherwise it's // '+input' if (this.props.type === 'monaco') { window.monacoSetValTriggered = true; setTimeout(() => { window.monacoSetValTriggered = false; }, 1); } this.instance.setValue(value); // We save last set value so that when editor type changes, we can // populate that last value this.lastSetValue = value; this.refresh(); } getValue() { return this.instance.getValue(); } saveViewState() { if (this.props.type === 'monaco') { return this.instance.saveViewState(); } } restoreViewState(state) { if (this.props.type === 'monaco') { this.instance.restoreViewState(state); } } setOption(option, value) { if (this.props.type === 'monaco') { this.editorReadyDeferred.promise.then(() => { this.instance.updateOptions({ [option]: value }); }); } else { this.instance.setOption(option, value); } } setLanguage(value) { if (!window.monaco) return; this.editorReadyDeferred.promise.then(() => { if (this.props.type === 'monaco') { monaco.editor.setModelLanguage(this.instance.getModel(), this.getMonacoLanguageFromMode(modes[value].cmMode)); } else { this.instance.setOption('mode', modes[value].cmMode); CodeMirror.autoLoadMode(this.instance, modes[value].cmPath || modes[value].cmMode); } }); } clearGutter(gutterName) { this.editorReadyDeferred.promise.then(() => { if (this.instance.clearGutter) { this.instance.clearGutter(gutterName); } }); } showErrors(errors) { if (this.props.type === 'codemirror') { errors.forEach(function (error) { this.instance.operation(function () { var n = document.createElement('div'); n.setAttribute('data-title', error.message); n.classList.add('gutter-error-marker'); editor.setGutterMarker(error.lineNumber, 'error-gutter', n); }); }); } } refresh() { this.editorReadyDeferred.promise.then(() => { this.instance.refresh ? this.instance.refresh() : this.instance.layout(); }); } focus() { this.editorReadyDeferred.promise.then(() => { this.instance.focus(); }); } /** * Converts codemirror mode value to monaco language values. * TODO: Refactor to not be codemirror related. * @param {string} mode Codemirror mode value */ getMonacoLanguageFromMode(mode) { if (['htmlmixed'].includes(mode)) { return 'html'; } if (['css', 'sass', 'scss', 'less', 'stylus'].includes(mode)) { return 'css'; } if (['javascript', 'text/typescript-jsx', 'jsx'].includes(mode)) { return 'javascript'; } return mode; } /** * Loads the asynchronous deps according to the editor type. */ async loadDeps() { if (this.props.type === 'monaco') { if (!monacoDepsDeferred) { monacoDepsDeferred = deferred(); loadCss({ url: 'lib/monaco/monaco.css', id: 'monaco-css' }); __webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, "lbPO")).then(() => { monacoDepsDeferred.resolve(); }); } return monacoDepsDeferred.promise; } return Promise.resolve(); } async initEditor() { console.log('init editor'); this.editorReadyDeferred = deferred(); await this.loadDeps(); const { options, prefs } = this.props; if (this.props.type === 'monaco') { this.instance = monaco.editor.create(this.node, { language: this.getMonacoLanguageFromMode(options.mode), value: this.lastSetValue || '', roundedSelection: false, scrollBeyondLastLine: false, theme: 'vs-dark', fontSize: prefs.fontSize, minimap: { enabled: false }, wordWrap: 'on', renderWhitespace: 'all', fontLigatures: true, automaticLayout: true }); window.monacoInstance = this.instance; this.instance.onDidChangeModelContent(change => { this.props.onChange(this.instance, CodeEditor__extends({}, change, { origin: window.monacoSetValTriggered ? 'setValue' : '+input' })); }); this.instance.addCommand(monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_F, () => { if (options.prettier) { prettify({ content: this.instance.getValue(), type: options.prettierParser }).then(formattedCode => this.instance.setValue(formattedCode)); } }); this.editorReadyDeferred.resolve(); } else { this.instance = CodeMirror.fromTextArea(this.node, { mode: options.mode, value: this.lastSetValue || '', lineNumbers: true, lineWrapping: !!prefs.lineWrap, autofocus: options.autofocus || false, autoCloseBrackets: true, autoCloseTags: !!prefs.autoCloseTags, matchBrackets: true, matchTags: options.matchTags || false, tabMode: 'indent', keyMap: prefs.keyMap || 'sublime', theme: prefs.editorTheme || 'monokai', lint: !!options.lint, tabSize: +prefs.indentSize || 2, indentWithTabs: prefs.indentWith !== 'spaces', indentUnit: +prefs.indentSize, foldGutter: true, styleActiveLine: true, gutters: options.gutters || [], // cursorScrollMargin: '20', has issue with scrolling profile: options.profile || '', extraKeys: { Up: function (editor) { // Stop up/down keys default behavior when saveditempane is open // if (isSavedItemsPaneOpen) { // return; // } CodeMirror.commands.goLineUp(editor); }, Down: function (editor) { // if (isSavedItemsPaneOpen) { // return; // } CodeMirror.commands.goLineDown(editor); }, 'Shift-Tab': function (editor) { CodeMirror.commands.indentAuto(editor); }, 'Shift-Ctrl-F': function (editor) { if (options.prettier) { prettify({ content: editor.getValue(), type: options.prettierParser }).then(formattedCode => editor.setValue(formattedCode)); } }, Tab: function (editor) { if (options.emmet) { const didEmmetWork = editor.execCommand('emmetExpandAbbreviation'); if (didEmmetWork === true) { return; } const input = $('[data-setting=indentWith]:checked'); if (!editor.somethingSelected() && (!prefs.indentWith || prefs.indentWith === 'spaces')) { // softtabs adds spaces. This is required because by default tab key will put tab, but we want // to indent with spaces if `spaces` is preferred mode of indentation. // `somethingSelected` needs to be checked otherwise, all selected code is replaced with softtab. CodeMirror.commands.insertSoftTab(editor); } else { CodeMirror.commands.defaultTab(editor); } } }, Enter: 'emmetInsertLineBreak' } }); this.editorReadyDeferred.resolve(); this.instance.on('focus', editor => { if (typeof this.props.onFocus === 'function') this.props.onFocus(editor); }); this.instance.on('change', this.props.onChange); this.instance.addKeyMap({ 'Ctrl-Space': 'autocomplete' }); this.instance.on('inputRead', (editor, input) => { // Process further If this has autocompletition on and also the global // autocomplete setting is on. if (!this.props.options.noAutocomplete && this.props.prefs.autoComplete) { if (input.origin !== '+input' || input.text[0] === ';' || input.text[0] === ',' || input.text[0] === ' ') { return; } CodeMirror.commands.autocomplete(editor, null, { completeSingle: false }); } }); } // this.props.onCreation(this.instance); } render() { const node = this.props.type === 'monaco' ? Object(preact_min["h"])('div', { ref: el => this.node = el, style: 'width:100%;height:100%;' }) : Object(preact_min["h"])('textarea', { ref: el => this.node = el }); return node; } }; // EXTERNAL MODULE: ../node_modules/split.js/split.js var split_js_split = __webpack_require__("mSND"); var split_default = /*#__PURE__*/__webpack_require__.n(split_js_split); // CONCATENATED MODULE: ./components/SplitPane.jsx var SplitPane__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function SplitPane__objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } let SplitPane_SplitPane = class SplitPane extends preact_min["Component"] { componentDidMount() { this.updateSplit(); } componentWillUpdate() { if (this.splitInstance) { this.splitInstance.destroy(); } } componentDidUpdate(prevProps) { if (this.hasGutter() && !this.hasPropsChanged(prevProps, this.props)) { return; } this.updateSplit(); } componentWillUnmount() { this.splitInstance.destroy(); delete this.splitInstance; } hasGutter() { return [...this.parent.children].indexOf(this.parent.querySelector('.gutter')) !== -1; } hasPropsChanged(a, b) { return a.direction !== b.direction || a.sizes && b.sizes && a.sizes.join('') !== b.sizes.join(''); } updateSplit() { const _props = this.props, { children } = _props, options = SplitPane__objectWithoutProperties(_props, ['children']); options.gutterSize = 6; /* eslint-disable new-cap */ this.splitInstance = split_default()([...this.parent.children], options); /* eslint-enable new-cap */ if (this.props.onSplit) { this.props.onSplit(this.splitInstance); } } render() { /* eslint-disable no-unused-vars */ const _props2 = this.props, { children } = _props2, props = SplitPane__objectWithoutProperties(_props2, ['children']); /* eslint-enable no-unused-vars */ return Object(preact_min["h"])( 'div', SplitPane__extends({ ref: el => this.parent = el }, props), this.props.children ); } }; // EXTERNAL MODULE: ../node_modules/react-inspector/lib/index.js var react_inspector_lib = __webpack_require__("Hxgu"); var lib_default = /*#__PURE__*/__webpack_require__.n(react_inspector_lib); // EXTERNAL MODULE: ../node_modules/preact-compat/dist/preact-compat.es.js var preact_compat_es = __webpack_require__("eW0v"); // CONCATENATED MODULE: ./components/Console.jsx var Console__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; let Console_LogRow = class LogRow extends preact_min["Component"] { shouldComponentUpdate() { return false; } render() { const theme = Console__extends({}, react_inspector_lib["chromeDark"], { OBJECT_VALUE_STRING_COLOR: 'green', BASE_FONT_SIZE: '20px', TREENODE_FONT_SIZE: '20px' }); return Object(preact_min["h"])(react_inspector_lib["Inspector"], { theme: theme, theme: 'chromeDark', data: this.props.data }); } }; var Console__ref = Object(preact_min["h"])(react["Trans"], { id: 'Console' }); var Console__ref2 = Object(preact_min["h"])( 'svg', null, Object(preact_min["h"])('use', { xlinkHref: '#cancel-icon' }) ); var Console__ref3 = Object(preact_min["h"])( 'svg', { width: '18', height: '18', fill: '#346fd2' }, Object(preact_min["h"])('use', { xlinkHref: '#chevron-icon' }) ); let Console_Console = class Console extends preact_compat_es["PureComponent"] { componentWillUpdate(nextProps) { if (nextProps.logs != this.props.logs) { // Scroll down after new log dom is inserted setTimeout(() => { this.logContainerEl.scrollTop = this.logContainerEl.scrollHeight; }, 1); } } render() { const { logs, isConsoleOpen, onConsoleHeaderDblClick, onClearConsoleBtnClick, toggleConsole, onEvalInputKeyup } = this.props; return Object(preact_min["h"])( 'div', { id: 'consoleEl', 'class': `console ${isConsoleOpen ? '' : 'is-minimized'}` }, Object(preact_min["h"])( 'div', { id: 'consoleLogEl', 'class': 'console__log' }, Object(preact_min["h"])( 'div', { 'class': 'js-console__header code-wrap__header', title: 'Double click to toggle console', onDblClick: onConsoleHeaderDblClick }, Object(preact_min["h"])( 'span', { 'class': 'code-wrap__header-label' }, Console__ref, ' (', Object(preact_min["h"])( 'span', null, logs.length ), ')' ), Object(preact_min["h"])( 'div', { 'class': 'code-wrap__header-right-options' }, Object(preact_min["h"])( 'a', { 'class': 'code-wrap__header-btn', title: 'Clear console (CTRL + L)', onClick: onClearConsoleBtnClick }, Console__ref2 ), Object(preact_min["h"])('a', { 'class': 'code-wrap__header-btn code-wrap__collapse-btn', title: 'Toggle console', onClick: toggleConsole }) ) ), Object(preact_min["h"])( 'ul', { 'class': 'console__items', ref: el => { this.logContainerEl = el; } }, logs.map(log => Object(preact_min["h"])(Console_LogRow, { data: log })) ) ), Object(preact_min["h"])( 'div', { id: 'consolePromptEl', 'class': 'console__prompt flex flex-v-center flex-shrink-0' }, Console__ref3, Object(preact_min["h"])('input', { tabIndex: isConsoleOpen ? 0 : -1, onKeyUp: onEvalInputKeyup, 'class': 'console-exec-input' }) ) ); } }; // EXTERNAL MODULE: ../node_modules/preact-portal/dist/preact-portal.js var preact_portal = __webpack_require__("q6qL"); var preact_portal_default = /*#__PURE__*/__webpack_require__.n(preact_portal); // CONCATENATED MODULE: ./components/Modal.jsx let Modal_Modal = class Modal extends preact_min["Component"] { componentDidMount() { window.addEventListener('keydown', this.onKeyDownHandler.bind(this)); } componentWillUnmount() { window.removeEventListener('keydown', this.onKeyDownHandler.bind(this)); if (this.focusGrabber) { this.focusGrabber.remove(); this.focusGrabber = null; } } onKeyDownHandler(e) { if (e.keyCode === 27) { this.props.closeHandler(); } } onOverlayClick(e) { if (e.target === this.overlayEl) { this.props.closeHandler(); } } componentDidUpdate(prevProps) { if (this.props.show !== prevProps.show) { if (!this.props.noOverlay) { document.body.classList[this.props.show ? 'add' : 'remove']('overlay-visible'); } if (this.props.show) { // HACK: refs will evaluate on next tick due to portals setTimeout(() => { const closeButton = this.overlayEl.querySelector('.js-modal__close-btn'); if (closeButton) { closeButton.focus(); } }, 0); /* We insert a dummy hidden input which will take focus as soon as focus escapes the modal, instead of focus going outside modal because modal is last focusable element. */ this.focusGrabber = document.createElement('input'); this.focusGrabber.setAttribute('style', 'height:0;opacity:0;overflow:hidden;width:0;'); setTimeout(() => { document.body.appendChild(this.focusGrabber); }, 10); } else { this.focusGrabber.remove(); this.focusGrabber = null; } } } render() { if (!this.props.show) return null; return Object(preact_min["h"])( preact_portal_default.a, { into: 'body' }, Object(preact_min["h"])( 'div', { 'class': `${this.props.extraClasses || ''} modal is-modal-visible ${this.props.small ? 'modal--small' : ''}`, ref: el => this.overlayEl = el, onClick: this.onOverlayClick.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'modal__content' }, this.props.hideCloseButton ? null : Object(preact_min["h"])( 'button', { type: 'button', onClick: this.props.closeHandler, 'aria-label': 'Close modal', title: 'Close', 'class': 'js-modal__close-btn modal__close-btn' }, 'Close' ), this.props.children ) ) ); } }; // CONCATENATED MODULE: ./components/CodeMirrorBox.jsx let CodeMirrorBox_CodeMirrorBox = class CodeMirrorBox extends preact_min["Component"] { componentDidMount() { this.initEditor(); } shouldComponentUpdate() { return false; } initEditor() { this.cm = CodeMirror.fromTextArea(this.textarea, this.props.options); if (this.props.onChange) { this.cm.on('change', this.props.onChange); } if (this.props.onBlur) { this.cm.on('blur', this.props.onBlur); } this.props.onCreation(this.cm); } render() { return Object(preact_min["h"])('textarea', { ref: el => this.textarea = el, name: '', id: '', cols: '30', rows: '10' }); } }; // CONCATENATED MODULE: ./components/CssSettingsModal.jsx var CssSettingsModal__ref = Object(preact_min["h"])( 'h1', null, 'Atomic CSS Settings' ); var CssSettingsModal__ref2 = Object(preact_min["h"])( 'h3', null, 'Configure Atomizer settings.', ' ', Object(preact_min["h"])( 'a', { href: 'https://github.com/acss-io/atomizer#api', target: '_blank', rel: 'noopener noreferrer' }, 'Read more' ), ' ', 'about available settings.' ); let CssSettingsModal_CssSettingsModal = class CssSettingsModal extends preact_min["Component"] { componentDidUpdate() { if (this.props.show) { setTimeout(() => { if (this.props.settings) { this.cm.setValue(this.props.settings.acssConfig); } // Refresh is required because codemirror gets scaled inside modal and loses alignement. this.cm.refresh(); this.cm.focus(); }, 500); } } render() { return Object(preact_min["h"])( Modal_Modal, { show: this.props.show, closeHandler: this.props.closeHandler }, CssSettingsModal__ref, CssSettingsModal__ref2, Object(preact_min["h"])( 'div', { style: 'height: calc(100vh - 350px);' }, Object(preact_min["h"])(CodeMirrorBox_CodeMirrorBox, { options: { mode: 'application/ld+json', theme: this.props.editorTheme }, onCreation: cm => this.cm = cm, onBlur: cm => this.props.onChange(cm.getValue()) }) ), Object(preact_min["h"])( 'div', { 'class': 'flex flex-h-end' }, Object(preact_min["h"])( 'button', { 'class': 'btn btn--primary', onClick: this.props.closeHandler }, 'Apply and Close' ) ) ); } }; // CONCATENATED MODULE: ./components/PreviewDimension.jsx var PreviewDimension__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** * This component udpates not through props or state, but by some parent * component calling a method of this component directly. This is because * using the state/prop way causes a huge unnnecessary rendering as this * component gets updated on drag event. */ const HIDE_AFTER_MILLISECONDS = 1000; let PreviewDimension_PreviewDimension = class PreviewDimension extends preact_compat_es["PureComponent"] { constructor(props) { super(props); this.state = { w: 0, h: 0, isVisible: false }; } update(dimensions) { this.setState(PreviewDimension__extends({ isVisible: true }, dimensions)); if (this.hideTimer) { clearTimeout(this.hideTimer); } /** * Automatically hide this commponent after sometime and also show * when its updated (code above). */ this.hideTimer = setTimeout(() => { this.setState({ isVisible: false }); }, HIDE_AFTER_MILLISECONDS); } render() { if (!this.state.isVisible) return null; return Object(preact_min["h"])( 'div', { 'class': 'preview-dimension' }, this.state.w, 'px \u2A2F ', this.state.h, 'px' ); } }; // CONCATENATED MODULE: ./components/ContentWrap.jsx const minCodeWrapSize = 33; /* global htmlCodeEl */ var ContentWrap__ref = Object(preact_min["h"])('span', { 'class': 'caret' }); var ContentWrap__ref2 = Object(preact_min["h"])( 'option', { value: 'html' }, 'HTML' ); var ContentWrap__ref3 = Object(preact_min["h"])( 'option', { value: 'markdown' }, 'Markdown' ); var ContentWrap__ref4 = Object(preact_min["h"])( 'option', { value: 'jade' }, 'Pug' ); var ContentWrap__ref5 = Object(preact_min["h"])('span', { 'class': 'caret' }); var ContentWrap__ref6 = Object(preact_min["h"])( 'option', { value: 'css' }, 'CSS' ); var ContentWrap__ref7 = Object(preact_min["h"])( 'option', { value: 'scss' }, 'SCSS' ); var ContentWrap__ref8 = Object(preact_min["h"])( 'option', { value: 'sass' }, 'SASS' ); var ContentWrap__ref9 = Object(preact_min["h"])( 'option', { value: 'less' }, 'LESS' ); var ContentWrap__ref10 = Object(preact_min["h"])( 'option', { value: 'stylus' }, 'Stylus' ); var ContentWrap__ref11 = Object(preact_min["h"])( 'option', { value: 'acss' }, 'Atomic CSS' ); var ContentWrap__ref12 = Object(preact_min["h"])( 'svg', null, Object(preact_min["h"])('use', { xlinkHref: '#settings-icon' }) ); var ContentWrap__ref13 = Object(preact_min["h"])('span', { 'class': 'caret' }); var _ref14 = Object(preact_min["h"])( 'option', { value: 'js' }, 'JS' ); var _ref15 = Object(preact_min["h"])( 'option', { value: 'coffee' }, 'CoffeeScript' ); var _ref16 = Object(preact_min["h"])( 'option', { value: 'es6' }, 'ES6 (Babel)' ); var _ref17 = Object(preact_min["h"])( 'option', { value: 'typescript' }, 'TypeScript' ); let ContentWrap_ContentWrap = class ContentWrap extends preact_min["Component"] { constructor(props) { super(props); this.state = { isConsoleOpen: false, isCssSettingsModalOpen: false, logs: [] }; this.updateTimer = null; this.updateDelay = 500; this.htmlMode = HtmlModes.HTML; this.jsMode = HtmlModes.HTML; this.cssMode = CssModes.CSS; this.jsMode = JsModes.JS; this.prefs = {}; this.codeInPreview = { html: null, css: null, js: null }; this.cmCodes = { html: props.currentItem.html, css: '', js: '' }; this.cm = {}; window.onMessageFromConsole = this.onMessageFromConsole.bind(this); window.previewException = this.previewException.bind(this); // `clearConsole` is on window because it gets called from inside iframe also. window.clearConsole = this.clearConsole.bind(this); this.consoleHeaderDblClickHandler = this.consoleHeaderDblClickHandler.bind(this); this.clearConsoleBtnClickHandler = this.clearConsoleBtnClickHandler.bind(this); this.toggleConsole = this.toggleConsole.bind(this); this.evalConsoleExpr = this.evalConsoleExpr.bind(this); } shouldComponentUpdate(nextProps, nextState) { return this.state.isConsoleOpen !== nextState.isConsoleOpen || this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen || this.state.logs !== nextState.logs || this.state.codeSplitSizes !== nextState.codeSplitSizes || this.state.mainSplitSizes !== nextState.mainSplitSizes || this.props.currentLayoutMode !== nextProps.currentLayoutMode || this.props.currentItem !== nextProps.currentItem || this.props.prefs !== nextProps.prefs; } componentDidUpdate() { // log('🚀', 'didupdate', this.props.currentItem); // if (this.isValidItem(this.props.currentItem)) { // this.refreshEditor(); // } } componentDidMount() { this.props.onRef(this); } onHtmlCodeChange(editor, change) { this.cmCodes.html = editor.getValue(); this.props.onCodeChange('html', this.cmCodes.html, change.origin !== 'setValue'); this.onCodeChange(editor, change); } onCssCodeChange(editor, change) { this.cmCodes.css = editor.getValue(); this.props.onCodeChange('css', this.cmCodes.css, change.origin !== 'setValue'); this.onCodeChange(editor, change); } onJsCodeChange(editor, change) { this.cmCodes.js = editor.getValue(); this.props.onCodeChange('js', this.cmCodes.js, change.origin !== 'setValue'); this.onCodeChange(editor, change); } onCodeChange(editor, change) { clearTimeout(this.updateTimer); this.updateTimer = setTimeout(() => { // This is done so that multiple simultaneous setValue don't trigger too many preview refreshes // and in turn too many file writes on a single file (eg. preview.html). if (change.origin !== 'setValue') { // Specifically checking for false so that the condition doesn't get true even // on absent key - possible when the setting key hasn't been fetched yet. if (this.prefs.autoPreview !== false) { this.setPreviewContent(); } // Track when people actually are working. trackEvent.previewCount = (trackEvent.previewCount || 0) + 1; if (trackEvent.previewCount === 4) { trackEvent('fn', 'usingPreview'); } } }, this.updateDelay); } createPreviewFile(html, css, js) { const shouldInlineJs = !window.webkitRequestFileSystem || !window.IS_EXTENSION; var contents = getCompleteHtml(html, css, shouldInlineJs ? js : null, this.props.currentItem); var blob = new Blob([contents], { type: 'text/plain;charset=UTF-8' }); var blobjs = new Blob([js], { type: 'text/plain;charset=UTF-8' }); // Track if people have written code. if (!trackEvent.hasTrackedCode && (html || css || js)) { trackEvent('fn', 'hasCode'); trackEvent.hasTrackedCode = true; } if (shouldInlineJs) { if (this.detachedWindow) { utils_log('✉️ Sending message to detached window'); this.detachedWindow.postMessage({ contents }, '*'); } else { this.frame.src = this.frame.src; setTimeout(() => { this.frame.contentDocument.open(); this.frame.contentDocument.write(contents); this.frame.contentDocument.close(); }, 10); } } else { // we need to store user script in external JS file to prevent inline-script // CSP from affecting it. writeFile('script.js', blobjs, () => { writeFile('preview.html', blob, () => { var origin = chrome.i18n.getMessage() ? `chrome-extension://${chrome.i18n.getMessage('@@extension_id')}` : `${location.origin}`; var src = `filesystem:${origin}/temporary/preview.html`; if (this.detachedWindow) { this.detachedWindow.postMessage(src, '*'); } else { this.frame.src = src; } }); }); } } cleanupErrors(lang) { this.cm[lang].clearGutter('error-gutter'); } showErrors(lang, errors) { this.cm[lang].showErrors(errors); } /** * Generates the preview from the current code. * @param {boolean} isForced Should refresh everything without any check or not * @param {boolean} isManual Is this a manual preview request from user? */ setPreviewContent(isForced, isManual) { if (!this.props.prefs.autoPreview && !isManual) { return; } if (!this.props.prefs.preserveConsoleLogs) { this.clearConsole(); } this.cleanupErrors('html'); this.cleanupErrors('css'); this.cleanupErrors('js'); var currentCode = { html: this.cmCodes.html, css: this.cmCodes.css, js: this.cmCodes.js }; utils_log('🔎 setPreviewContent', isForced); const targetFrame = this.detachedWindow ? this.detachedWindow.document.querySelector('iframe') : this.frame; const cssMode = this.props.currentItem.cssMode; // If just CSS was changed (and everything shudn't be empty), // change the styles inside the iframe. if (!isForced && currentCode.html === this.codeInPreview.html && currentCode.js === this.codeInPreview.js) { computeCss(cssMode === CssModes.ACSS ? currentCode.html : currentCode.css, cssMode, this.props.currentItem.cssSettings).then(result => { if (cssMode === CssModes.ACSS) { this.cm.css.setValue(result.code || ''); } if (targetFrame.contentDocument.querySelector('#webmakerstyle')) { targetFrame.contentDocument.querySelector('#webmakerstyle').textContent = result.code || ''; } }); } else { var htmlPromise = computeHtml(currentCode.html, this.props.currentItem.htmlMode); var cssPromise = computeCss(cssMode === CssModes.ACSS ? currentCode.html : currentCode.css, cssMode, this.props.currentItem.cssSettings); var jsPromise = computeJs(currentCode.js, this.props.currentItem.jsMode, true, this.props.prefs.infiniteLoopTimeout); Promise.all([htmlPromise, cssPromise, jsPromise]).then(result => { if (cssMode === CssModes.ACSS) { this.cm.css.setValue(result[1].code || ''); } this.createPreviewFile(result[0].code || '', result[1].code || '', result[2].code || ''); result.forEach(resultItem => { if (resultItem.errors) { this.showErrors(resultItem.errors.lang, resultItem.errors.data); } }); }); } this.codeInPreview.html = currentCode.html; this.codeInPreview.css = currentCode.css; this.codeInPreview.js = currentCode.js; } isValidItem(item) { return !!item.title; } refreshEditor() { this.cmCodes.html = this.props.currentItem.html; this.cmCodes.css = this.props.currentItem.css; this.cmCodes.js = this.props.currentItem.js; this.cm.html.setValue(this.cmCodes.html || ''); this.cm.css.setValue(this.cmCodes.css || ''); this.cm.js.setValue(this.cmCodes.js || ''); this.cm.html.refresh(); 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([this.updateHtmlMode(this.props.currentItem.htmlMode), this.updateCssMode(this.props.currentItem.cssMode), this.updateJsMode(this.props.currentItem.jsMode)]).then(() => this.setPreviewContent(true)); } applyCodemirrorSettings(prefs) { document.documentElement.style.setProperty('--code-font-size', `${parseInt(prefs.fontSize, 10)}px`); // Replace correct css file in LINK tags's href if (prefs.editorTheme) { window.editorThemeLinkTag.href = `lib/codemirror/theme/${prefs.editorTheme}.css`; } window.fontStyleTag.textContent = window.fontStyleTemplate.textContent.replace(/fontname/g, (prefs.editorFont === 'other' ? prefs.editorCustomFont : prefs.editorFont) || 'FiraCode'); } // Check all the code wrap if they are minimized or maximized updateCodeWrapCollapseStates() { // This is debounced! clearTimeout(this.updateCodeWrapCollapseStates.timeout); this.updateCodeWrapCollapseStates.timeout = setTimeout(() => { const { currentLayoutMode } = this.props; const prop = currentLayoutMode === 2 || currentLayoutMode === 5 ? 'width' : 'height'; [htmlCodeEl, cssCodeEl, jsCodeEl].forEach(function (el) { const bounds = el.getBoundingClientRect(); const size = bounds[prop]; if (size < 100) { el.classList.add('is-minimized'); } else { el.classList.remove('is-minimized'); } if (el.style[prop].indexOf(`100% - ${minCodeWrapSize * 2}px`) !== -1) { el.classList.add('is-maximized'); } else { el.classList.remove('is-maximized'); } }); }, 50); } toggleCodeWrapCollapse(codeWrapEl) { if (codeWrapEl.classList.contains('is-minimized') || codeWrapEl.classList.contains('is-maximized')) { codeWrapEl.classList.remove('is-minimized'); codeWrapEl.classList.remove('is-maximized'); this.codeSplitInstance.setSizes([33.3, 33.3, 33.3]); } else { const id = parseInt(codeWrapEl.dataset.codeWrapId, 10); var arr = [`${minCodeWrapSize}px`, `${minCodeWrapSize}px`, `${minCodeWrapSize}px`]; arr[id] = `calc(100% - ${minCodeWrapSize * 2}px)`; this.codeSplitInstance.setSizes(arr); codeWrapEl.classList.add('is-maximized'); } this.updateSplits(); } collapseBtnHandler(e) { var codeWrapParent = e.currentTarget.parentElement.parentElement.parentElement; this.toggleCodeWrapCollapse(codeWrapParent); trackEvent('ui', 'paneCollapseBtnClick', codeWrapParent.dataset.type); } codeWrapHeaderDblClickHandler(e) { if (!e.target.classList.contains('js-code-wrap__header')) { return; } const codeWrapParent = e.target.parentElement; this.toggleCodeWrapCollapse(codeWrapParent); trackEvent('ui', 'paneHeaderDblClick', codeWrapParent.dataset.type); } resetSplitting() { this.setState({ codeSplitSizes: this.getCodeSplitSizes(), mainSplitSizes: this.getMainSplitSizesToApply() }); } updateSplits() { this.props.onSplitUpdate(); // Not using setState to avoid re-render this.state.codeSplitSizes = this.props.currentItem.sizes; this.state.mainSplitSizes = this.props.currentItem.mainSizes; } // Returns the sizes of main code & preview panes. getMainSplitSizesToApply() { var mainSplitSizes; const { currentItem, currentLayoutMode } = this.props; if (currentItem && currentItem.mainSizes) { // For layout mode 3, main panes are reversed using flex-direction. // So we need to apply the saved sizes in reverse order. mainSplitSizes = currentLayoutMode === 3 ? [currentItem.mainSizes[1], currentItem.mainSizes[0]] : currentItem.mainSizes; } else { mainSplitSizes = currentLayoutMode === 5 ? [75, 25] : [50, 50]; } return mainSplitSizes; } getCodeSplitSizes() { if (this.props.currentItem && this.props.currentItem.sizes) { return this.props.currentItem.sizes; } return [33.33, 33.33, 33.33]; } mainSplitDragEndHandler() { if (this.props.prefs.refreshOnResize) { // Running preview updation in next call stack, so that error there // doesn't affect this dragend listener. setTimeout(() => { this.setPreviewContent(true); }, 1); } this.updateSplits(); } mainSplitDragHandler() { this.previewDimension.update({ w: this.frame.clientWidth, h: this.frame.clientHeight }); } codeSplitDragStart() { document.body.classList.add('is-dragging'); } codeSplitDragEnd() { this.updateCodeWrapCollapseStates(); document.body.classList.remove('is-dragging'); this.updateSplits(); } /** * Loaded the code comiler based on the mode selected */ handleModeRequirements(mode) { const baseTranspilerPath = 'lib/transpilers'; // Exit if already loaded var d = deferred(); if (modes[mode].hasLoaded) { d.resolve(); return d.promise; } function setLoadedFlag() { modes[mode].hasLoaded = true; d.resolve(); } if (mode === HtmlModes.JADE) { loadJS(`${baseTranspilerPath}/jade.js`).then(setLoadedFlag); } else if (mode === HtmlModes.MARKDOWN) { loadJS(`${baseTranspilerPath}/marked.js`).then(setLoadedFlag); } else if (mode === CssModes.LESS) { loadJS(`${baseTranspilerPath}/less.min.js`).then(setLoadedFlag); } else if (mode === CssModes.SCSS || mode === CssModes.SASS) { loadJS(`${baseTranspilerPath}/sass.js`).then(function () { window.sass = new Sass(`${baseTranspilerPath}/sass.worker.js`); setLoadedFlag(); }); } else if (mode === CssModes.STYLUS) { loadJS(`${baseTranspilerPath}/stylus.min.js`).then(setLoadedFlag); } else if (mode === CssModes.ACSS) { loadJS(`${baseTranspilerPath}/atomizer.browser.js`).then(setLoadedFlag); } else if (mode === JsModes.COFFEESCRIPT) { loadJS(`${baseTranspilerPath}/coffee-script.js`).then(setLoadedFlag); } else if (mode === JsModes.ES6) { loadJS(`${baseTranspilerPath}/babel.min.js`).then(setLoadedFlag); } else if (mode === JsModes.TS) { loadJS(`${baseTranspilerPath}/typescript.js`).then(setLoadedFlag); } else { d.resolve(); } return d.promise; } updateHtmlMode(value) { this.props.onCodeModeChange('html', value); this.props.currentItem.htmlMode = value; this.cm.html.setLanguage(value); return this.handleModeRequirements(value); } updateCssMode(value) { this.props.onCodeModeChange('css', value); this.props.currentItem.cssMode = value; this.cm.css.setOption('readOnly', modes[value].cmDisable); window.cssSettingsBtn.classList[modes[value].hasSettings ? 'remove' : 'add']('hide'); this.cm.css.setLanguage(value); return this.handleModeRequirements(value); } updateJsMode(value) { this.props.onCodeModeChange('js', value); this.props.currentItem.jsMode = value; this.cm.js.setLanguage(value); return this.handleModeRequirements(value); } codeModeChangeHandler(e) { var mode = e.target.value; var type = e.target.dataset.type; var currentMode = this.props.currentItem[type === 'html' ? 'htmlMode' : type === 'css' ? 'cssMode' : 'jsMode']; if (currentMode !== mode) { if (type === 'html') { this.updateHtmlMode(mode).then(() => this.setPreviewContent(true)); } else if (type === 'js') { this.updateJsMode(mode).then(() => this.setPreviewContent(true)); } else if (type === 'css') { this.updateCssMode(mode).then(() => this.setPreviewContent(true)); } trackEvent('ui', 'updateCodeMode', mode); } } detachPreview() { if (this.detachedWindow) { this.detachedWindow.focus(); return; } const iframeBounds = this.frame.getBoundingClientRect(); const iframeWidth = iframeBounds.width; const iframeHeight = iframeBounds.height; document.body.classList.add('is-detached-mode'); this.detachedWindow = window.open('./preview.html', 'Web Maker', `width=${iframeWidth},height=${iframeHeight},resizable,scrollbars=yes,status=1`); // Trigger initial render in detached window setTimeout(() => { this.setPreviewContent(true); }, 1500); var intervalID = window.setInterval(checkWindow => { if (this.detachedWindow && this.detachedWindow.closed) { clearInterval(intervalID); document.body.classList.remove('is-detached-mode'); this.detachedWindow = null; // Update main frame preview to get latest changes (which were not // getting reflected while detached window was open) this.setPreviewContent(true); } }, 500); } onMessageFromConsole() { const logs = [...arguments].map(arg => { if (arg && arg.indexOf && arg.indexOf('filesystem:chrome-extension') !== -1) { return arg.replace(/filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, 'script $1:$2'); } return arg; }); this.setState({ logs: [...this.state.logs, ...logs] }); } previewException(error) { console.error('Possible infinite loop detected.', error.stack); this.onMessageFromConsole('Possible infinite loop detected.', error.stack); } toggleConsole() { this.setState({ isConsoleOpen: !this.state.isConsoleOpen }); trackEvent('ui', 'consoleToggle'); } consoleHeaderDblClickHandler(e) { if (!e.target.classList.contains('js-console__header')) { return; } trackEvent('ui', 'consoleToggleDblClick'); this.toggleConsole(); } clearConsole() { this.setState({ logs: [] }); } clearConsoleBtnClickHandler() { this.clearConsole(); trackEvent('ui', 'consoleClearBtnClick'); } evalConsoleExpr(e) { // Clear console on CTRL + L if ((e.which === 76 || e.which === 12) && e.ctrlKey) { this.clearConsole(); trackEvent('ui', 'consoleClearKeyboardShortcut'); } else if (e.which === 13) { this.onMessageFromConsole('> ' + e.target.value); /* eslint-disable no-underscore-dangle */ this.frame.contentWindow._wmEvaluate(e.target.value); /* eslint-enable no-underscore-dangle */ e.target.value = ''; trackEvent('fn', 'evalConsoleExpr'); } } cssSettingsBtnClickHandler() { this.setState({ isCssSettingsModalOpen: true }); trackEvent('ui', 'cssSettingsBtnClick'); } cssSettingsChangeHandler(settings) { this.props.onCodeSettingsChange('css', settings); this.setPreviewContent(true); } getDemoFrame(callback) { callback(this.frame); } editorFocusHandler(editor) { this.props.onEditorFocus(editor); } render() { utils_log('contentwrap update'); return Object(preact_min["h"])( SplitPane_SplitPane, { 'class': 'content-wrap flex flex-grow', sizes: this.state.mainSplitSizes, minSize: 150, style: '', direction: this.props.currentLayoutMode === 2 ? 'vertical' : 'horizontal', onDrag: this.mainSplitDragHandler.bind(this), onDragEnd: this.mainSplitDragEndHandler.bind(this) }, Object(preact_min["h"])( SplitPane_SplitPane, { 'class': 'code-side', id: 'js-code-side', sizes: this.state.codeSplitSizes, minSize: minCodeWrapSize, direction: this.props.currentLayoutMode === 2 || this.props.currentLayoutMode === 5 ? 'horizontal' : 'vertical', onDragStart: this.codeSplitDragStart.bind(this), onDragEnd: this.codeSplitDragEnd.bind(this), onSplit: splitInstance => this.codeSplitInstance = splitInstance }, Object(preact_min["h"])( 'div', { 'data-code-wrap-id': '0', id: 'htmlCodeEl', 'data-type': 'html', 'class': 'code-wrap', onTransitionEnd: this.updateCodeWrapCollapseStates.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'js-code-wrap__header code-wrap__header', title: 'Double click to toggle code pane', onDblClick: this.codeWrapHeaderDblClickHandler.bind(this) }, Object(preact_min["h"])( 'label', { 'class': 'btn-group', dropdow: true, title: 'Click to change' }, Object(preact_min["h"])( 'span', { 'class': 'code-wrap__header-label' }, modes[this.props.currentItem.htmlMode || 'html'].label ), ContentWrap__ref, Object(preact_min["h"])( 'select', { 'data-type': 'html', 'class': 'js-mode-select hidden-select', onChange: this.codeModeChangeHandler.bind(this), value: this.props.currentItem.htmlMode }, ContentWrap__ref2, ContentWrap__ref3, ContentWrap__ref4 ) ), Object(preact_min["h"])( 'div', { 'class': 'code-wrap__header-right-options' }, Object(preact_min["h"])('a', { 'class': 'js-code-collapse-btn code-wrap__header-btn code-wrap__collapse-btn', title: 'Toggle code pane', onClick: this.collapseBtnHandler.bind(this) }) ) ), Object(preact_min["h"])(CodeEditor_CodeEditor, { type: this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror', options: { mode: 'htmlmixed', profile: 'xhtml', gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], noAutocomplete: true, matchTags: { bothTags: true }, prettier: true, prettierParser: 'html', emmet: true }, prefs: this.props.prefs, onChange: this.onHtmlCodeChange.bind(this), ref: editor => this.cm.html = editor, onFocus: this.editorFocusHandler.bind(this) }) ), Object(preact_min["h"])( 'div', { 'data-code-wrap-id': '1', id: 'cssCodeEl', 'data-type': 'css', 'class': 'code-wrap', onTransitionEnd: this.updateCodeWrapCollapseStates.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'js-code-wrap__header code-wrap__header', title: 'Double click to toggle code pane', onDblClick: this.codeWrapHeaderDblClickHandler.bind(this) }, Object(preact_min["h"])( 'label', { 'class': 'btn-group', title: 'Click to change' }, Object(preact_min["h"])( 'span', { 'class': 'code-wrap__header-label' }, modes[this.props.currentItem.cssMode || 'css'].label ), ContentWrap__ref5, Object(preact_min["h"])( 'select', { 'data-type': 'css', 'class': 'js-mode-select hidden-select', onChange: this.codeModeChangeHandler.bind(this), value: this.props.currentItem.cssMode }, ContentWrap__ref6, ContentWrap__ref7, ContentWrap__ref8, ContentWrap__ref9, ContentWrap__ref10, ContentWrap__ref11 ) ), Object(preact_min["h"])( 'div', { 'class': 'code-wrap__header-right-options' }, Object(preact_min["h"])( 'a', { href: '#', id: 'cssSettingsBtn', title: 'Atomic CSS configuration', onClick: this.cssSettingsBtnClickHandler.bind(this), 'class': 'code-wrap__header-btn hide' }, ContentWrap__ref12 ), Object(preact_min["h"])('a', { 'class': 'js-code-collapse-btn code-wrap__header-btn code-wrap__collapse-btn', title: 'Toggle code pane', onClick: this.collapseBtnHandler.bind(this) }) ) ), Object(preact_min["h"])(CodeEditor_CodeEditor, { type: this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror', options: { mode: 'css', gutters: ['error-gutter', 'CodeMirror-linenumbers', 'CodeMirror-foldgutter'], emmet: true, prettier: true, prettierParser: 'css' }, prefs: this.props.prefs, onChange: this.onCssCodeChange.bind(this), ref: editor => this.cm.css = editor, onFocus: this.editorFocusHandler.bind(this) }) ), Object(preact_min["h"])( 'div', { 'data-code-wrap-id': '2', id: 'jsCodeEl', 'data-type': 'js', 'class': 'code-wrap', onTransitionEnd: this.updateCodeWrapCollapseStates.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'js-code-wrap__header code-wrap__header', title: 'Double click to toggle code pane', onDblClick: this.codeWrapHeaderDblClickHandler.bind(this) }, Object(preact_min["h"])( 'label', { 'class': 'btn-group', title: 'Click to change' }, Object(preact_min["h"])( 'span', { 'class': 'code-wrap__header-label' }, modes[this.props.currentItem.jsMode || 'js'].label ), ContentWrap__ref13, Object(preact_min["h"])( 'select', { 'data-type': 'js', 'class': 'js-mode-select hidden-select', onChange: this.codeModeChangeHandler.bind(this), value: this.props.currentItem.jsMode }, _ref14, _ref15, _ref16, _ref17 ) ), Object(preact_min["h"])( 'div', { 'class': 'code-wrap__header-right-options' }, Object(preact_min["h"])('a', { 'class': 'js-code-collapse-btn code-wrap__header-btn code-wrap__collapse-btn', title: 'Toggle code pane', onClick: this.collapseBtnHandler.bind(this) }) ) ), Object(preact_min["h"])(CodeEditor_CodeEditor, { type: this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror', options: { mode: 'javascript', gutters: ['error-gutter', 'CodeMirror-linenumbers', 'CodeMirror-foldgutter'], prettier: true, prettierParser: 'js' }, prefs: this.props.prefs, autoComplete: this.props.prefs.autoComplete, onChange: this.onJsCodeChange.bind(this), ref: editor => this.cm.js = editor, onFocus: this.editorFocusHandler.bind(this) }) ) ), Object(preact_min["h"])( 'div', { 'class': 'demo-side', id: 'js-demo-side', style: '' }, Object(preact_min["h"])('iframe', { ref: el => this.frame = el, src: 'about://blank', frameborder: '0', id: 'demo-frame', allowfullscreen: true }), Object(preact_min["h"])(PreviewDimension_PreviewDimension, { ref: comp => this.previewDimension = comp }), Object(preact_min["h"])(Console_Console, { logs: this.state.logs, isConsoleOpen: this.state.isConsoleOpen, onConsoleHeaderDblClick: this.consoleHeaderDblClickHandler, onClearConsoleBtnClick: this.clearConsoleBtnClickHandler, toggleConsole: this.toggleConsole, onEvalInputKeyup: this.evalConsoleExpr }), Object(preact_min["h"])(CssSettingsModal_CssSettingsModal, { show: this.state.isCssSettingsModalOpen, closeHandler: () => this.setState({ isCssSettingsModalOpen: false }), onChange: this.cssSettingsChangeHandler.bind(this), settings: this.props.currentItem.cssSettings, editorTheme: this.props.prefs.editorTheme }) ) ); } }; // EXTERNAL MODULE: ../node_modules/codemirror/mode/meta.js var meta = __webpack_require__("87T5"); var meta_default = /*#__PURE__*/__webpack_require__.n(meta); // CONCATENATED MODULE: ./components/FileIcon.jsx var FileIcon__ref = Object(preact_min["h"])('path', { fill: 'currentColor', d: 'M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6Z' }); var FileIcon__ref2 = Object(preact_min["h"])('path', { fill: 'currentColor', d: 'M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z' }); var FileIcon__ref3 = Object(preact_min["h"])('path', { fill: 'currentColor', d: 'M19,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10L12,6H19A2,2 0 0,1 21,8H21L4,8V18L6.14,10H23.21L20.93,18.5C20.7,19.37 19.92,20 19,20Z' }); var FileIcon__ref4 = Object(preact_min["h"])('path', { fill: 'rgb(225, 187, 21)', d: 'M14.6,16.6L19.2,12L14.6,7.4L16,6L22,12L16,18L14.6,16.6M9.4,16.6L4.8,12L9.4,7.4L8,6L2,12L8,18L9.4,16.6Z' }); var FileIcon__ref5 = Object(preact_min["h"])('path', { fill: 'rgb(255, 165, 0)', d: 'M3,3H21V21H3V3M7.73,18.04C8.13,18.89 8.92,19.59 10.27,19.59C11.77,19.59 12.8,18.79 12.8,17.04V11.26H11.1V17C11.1,17.86 10.75,18.08 10.2,18.08C9.62,18.08 9.38,17.68 9.11,17.21L7.73,18.04M13.71,17.86C14.21,18.84 15.22,19.59 16.8,19.59C18.4,19.59 19.6,18.76 19.6,17.23C19.6,15.82 18.79,15.19 17.35,14.57L16.93,14.39C16.2,14.08 15.89,13.87 15.89,13.37C15.89,12.96 16.2,12.64 16.7,12.64C17.18,12.64 17.5,12.85 17.79,13.37L19.1,12.5C18.55,11.54 17.77,11.17 16.7,11.17C15.19,11.17 14.22,12.13 14.22,13.4C14.22,14.78 15.03,15.43 16.25,15.95L16.67,16.13C17.45,16.47 17.91,16.68 17.91,17.26C17.91,17.74 17.46,18.09 16.76,18.09C15.93,18.09 15.45,17.66 15.09,17.06L13.71,17.86Z' }); var FileIcon__ref6 = Object(preact_min["h"])('path', { fill: '#2874C1', d: 'M3,3H21V21H3V3M13.71,17.86C14.21,18.84 15.22,19.59 16.8,19.59C18.4,19.59 19.6,18.76 19.6,17.23C19.6,15.82 18.79,15.19 17.35,14.57L16.93,14.39C16.2,14.08 15.89,13.87 15.89,13.37C15.89,12.96 16.2,12.64 16.7,12.64C17.18,12.64 17.5,12.85 17.79,13.37L19.1,12.5C18.55,11.54 17.77,11.17 16.7,11.17C15.19,11.17 14.22,12.13 14.22,13.4C14.22,14.78 15.03,15.43 16.25,15.95L16.67,16.13C17.45,16.47 17.91,16.68 17.91,17.26C17.91,17.74 17.46,18.09 16.76,18.09C15.93,18.09 15.45,17.66 15.09,17.06L13.71,17.86M13,11.25H8V12.75H9.5V20H11.25V12.75H13V11.25Z' }); var FileIcon__ref7 = Object(preact_min["h"])('path', { fill: 'rgb(95, 158, 160)', d: 'M5,3L4.35,6.34H17.94L17.5,8.5H3.92L3.26,11.83H16.85L16.09,15.64L10.61,17.45L5.86,15.64L6.19,14H2.85L2.06,18L9.91,21L18.96,18L20.16,11.97L20.4,10.76L21.94,3H5Z' }); var FileIcon__ref8 = Object(preact_min["h"])('path', { fill: '#CF649A', d: 'M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M10,15.33C10.16,15.87 10.14,16.37 10,16.83C10,16.88 9.96,16.93 9.94,17C9.92,17 9.9,17.07 9.87,17.12C9.76,17.36 9.6,17.59 9.41,17.79C8.83,18.43 8,18.67 7.67,18.47C7.29,18.25 7.5,17.35 8.16,16.64C8.88,15.88 9.92,15.38 9.92,15.38V15.38L10,15.33M18.27,6.28C17.82,4.5 14.87,3.92 12.09,4.91C10.43,5.5 8.63,6.42 7.34,7.63C5.81,9.07 5.56,10.32 5.66,10.84C6,12.68 8.54,13.89 9.58,14.78V14.79C9.28,14.94 7.04,16.07 6.5,17.23C5.96,18.45 6.6,19.33 7,19.45C8.34,19.81 9.69,19.16 10.41,18.07C11.11,17.03 11.06,15.68 10.75,15C11.17,14.9 11.66,14.85 12.28,14.92C14.04,15.13 14.38,16.22 14.31,16.68C14.25,17.14 13.88,17.39 13.76,17.47C13.64,17.54 13.6,17.57 13.61,17.63C13.62,17.71 13.68,17.71 13.78,17.69C13.93,17.66 14.71,17.32 14.74,16.47C14.78,15.39 13.75,14.19 11.93,14.22C11.18,14.24 10.71,14.31 10.37,14.44L10.29,14.35C9.16,13.15 7.08,12.3 7.17,10.68C7.2,10.09 7.4,8.55 11.17,6.67C14.25,5.13 16.72,5.55 17.15,6.5C17.76,7.83 15.83,10.32 12.63,10.68C11.41,10.82 10.76,10.34 10.6,10.17C10.43,10 10.41,9.97 10.35,10C10.24,10.07 10.31,10.23 10.35,10.33C10.44,10.58 10.84,11 11.5,11.24C12.09,11.43 13.53,11.54 15.26,10.87C17.2,10.12 18.72,8.03 18.27,6.28Z' }); var FileIcon__ref9 = Object(preact_min["h"])('path', { fill: 'skyblue', d: 'M2,16V8H4L7,11L10,8H12V16H10V10.83L7,13.83L4,10.83V16H2M16,8H19V12H21.5L17.5,16.5L13.5,12H16V8Z' }); var FileIcon__ref10 = Object(preact_min["h"])('path', { fill: 'crimson', d: 'M19,19H5V5H19M19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5A2,2 0 0,0 19,3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z' }); var FileIcon__ref11 = Object(preact_min["h"])('path', { fill: 'orange', d: 'M5,3H7V5H5V10A2,2 0 0,1 3,12A2,2 0 0,1 5,14V19H7V21H5C3.93,20.73 3,20.1 3,19V15A2,2 0 0,0 1,13H0V11H1A2,2 0 0,0 3,9V5A2,2 0 0,1 5,3M19,3A2,2 0 0,1 21,5V9A2,2 0 0,0 23,11H24V13H23A2,2 0 0,0 21,15V19A2,2 0 0,1 19,21H17V19H19V14A2,2 0 0,1 21,12A2,2 0 0,1 19,10V5H17V3H19M12,15A1,1 0 0,1 13,16A1,1 0 0,1 12,17A1,1 0 0,1 11,16A1,1 0 0,1 12,15M8,15A1,1 0 0,1 9,16A1,1 0 0,1 8,17A1,1 0 0,1 7,16A1,1 0 0,1 8,15M16,15A1,1 0 0,1 17,16A1,1 0 0,1 16,17A1,1 0 0,1 15,16A1,1 0 0,1 16,15Z' }); var FileIcon__ref12 = Object(preact_min["h"])('path', { fill: 'currentColor', d: 'M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z' }); function FileIcon({ file }) { let path; if (file.isFolder) { if (!file.children.length) { path = FileIcon__ref; } else { path = file.isCollapsed ? FileIcon__ref2 : FileIcon__ref3; } } else { const type = getExtensionFromFileName(file.name); switch (type) { case 'html': path = FileIcon__ref4; break; case 'js': path = FileIcon__ref5; break; case 'ts': path: FileIcon__ref6; break; case 'css': case 'less': path = FileIcon__ref7; break; case 'scss': case 'sass': path = FileIcon__ref8; break; case 'md': case 'markdown': path = FileIcon__ref9; break; case 'jpg': case 'jpeg': case 'svg': case 'png': path = FileIcon__ref10; break; case 'json': path = FileIcon__ref11; break; default: path = FileIcon__ref12; } } return Object(preact_min["h"])( 'svg', { 'class': 'sidebar__file-icon', viewBox: '0 0 24 24' }, path ); } // CONCATENATED MODULE: ./components/SidePane.jsx var SidePane__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; const ENTER_KEY = 13; const ESCAPE_KEY = 27; var SidePane__ref = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24', style: 'vertical-align:middle;width:14px;height:14px' }, Object(preact_min["h"])('path', { d: 'M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z' }) ); var SidePane__ref2 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24', style: 'vertical-align:middle;width:14px;height:14px' }, Object(preact_min["h"])('path', { d: 'M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z' }) ); function File({ file, selectedFile, fileBeingRenamed, onFileSelect, onRenameBtnClick, onRemoveBtnClick, onNameInputBlur, onNameInputKeyUp, onFileDrop }) { function focusInput(el) { el && setTimeout(() => { el.focus(); }, 1); } function dragStartHandler(e) { e.dataTransfer.setData('text/plain', file.path); } function dragOverHandler(e) { if (file.isFolder) { e.preventDefault(); // e.stopPropagation(); e.currentTarget.classList.add('is-being-dragged-over'); e.currentTarget.style.outline = '1px dashed'; } } function dragLeaveHandler(e) { if (file.isFolder) { e.preventDefault(); e.currentTarget.style.outline = null; } } function dropHandler(e) { e.stopPropagation(); if (file.isFolder) { e.preventDefault(); onFileDrop(e.dataTransfer.getData('text/plain'), file); e.currentTarget.style.outline = null; } } return Object(preact_min["h"])( 'div', { onDragOver: dragOverHandler, onDragLeave: dragLeaveHandler, onDrop: dropHandler }, file === fileBeingRenamed ? Object(preact_min["h"])('input', { type: 'text', ref: focusInput, value: file.name, onBlur: onNameInputBlur, onKeyUp: onNameInputKeyUp }) : Object(preact_min["h"])( 'button', { 'class': `sidebar__file ${selectedFile === file ? 'selected' : ''}`, type: 'button', draggable: file.name !== 'index.html', onDragStart: dragStartHandler, onClick: onFileSelect.bind(null, file) }, Object(preact_min["h"])( 'div', { 'class': 'flex flex-v-center' }, Object(preact_min["h"])(FileIcon, { file: file }), file.name ), Object(preact_min["h"])( 'div', { 'class': 'sidebar__file-options' }, Object(preact_min["h"])( 'button', { type: 'button', 'class': 'btn btn--dark', onClick: onRenameBtnClick.bind(null, file) }, SidePane__ref ), Object(preact_min["h"])( 'button', { type: 'button', 'class': 'btn btn--dark', onClick: onRemoveBtnClick.bind(null, file) }, SidePane__ref2 ) ) ) ); } function Folder(props) { return Object(preact_min["h"])( 'div', null, Object(preact_min["h"])(File, SidePane__extends({}, props, { file: props.file })), Object(preact_min["h"])( 'div', { 'class': 'sidebar__folder-wrap', 'data-collapsed': props.file.isCollapsed }, props.file.children.map(childFile => childFile.isFolder ? Object(preact_min["h"])(Folder, SidePane__extends({}, props, { file: childFile })) : Object(preact_min["h"])(File, SidePane__extends({}, props, { file: childFile }))) ) ); } var SidePane__ref3 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24', style: 'vertical-align:middle;width:14px;height:14px' }, Object(preact_min["h"])('path', { d: 'M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,15V12H9V15H6V17H9V20H11V17H14V15H11Z' }) ); var SidePane__ref4 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24', style: 'vertical-align:middle;width:14px;height:14px' }, Object(preact_min["h"])('path', { d: 'M10,4L12,6H20A2,2 0 0,1 22,8V18A2,2 0 0,1 20,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10M15,9V12H12V14H15V17H17V14H20V12H17V9H15Z' }) ); let SidePane_SidePane = class SidePane extends preact_min["Component"] { addFileButtonClickHandler() { this.setState({ isAddingFile: true }); } addFolderButtonClickHandler() { this.setState({ isAddingFolder: true }); } /** * Checks if the passed filename already exists and if so, warns the user. * Also it passes false if the validation fails. * @param {string} newFileName New file name to validate */ warnForExistingFileName(newFileName) { // We also check for fileBeingRenamed !== file because when a file being renamed is // asked to be set as same name, then that should not match and warn here. let newPath = this.state.fileBeingRenamed ? `${getParentPath(this.state.fileBeingRenamed.path)}/${newFileName}` : newFileName; // remove first slash newPath = newPath.replace(/^\//, ''); const match = getFileFromPath(this.props.files, newPath); if (match.file && this.state.fileBeingRenamed !== match.file) { alert(`A file with name ${newFileName} already exists.`); return false; } return true; } addFile(e) { // This gets called twice when enter is pressed, because blur also fires. // So check `isAddingFile` before proceeding. if (!this.state.isAddingFile && !this.state.isAddingFolder) { return; } const newFileName = e.target.value; if (!this.warnForExistingFileName(newFileName)) { return; } if (newFileName) { this.props.onAddFile(newFileName, this.state.isAddingFolder); } this.setState({ isAddingFile: false, isAddingFolder: false }); } newFileNameInputKeyDownHandler(e) { if (e.which === ENTER_KEY) { this.addFile(e); } else if (e.which === ESCAPE_KEY) { this.setState({ isAddingFile: false, isAddingFolder: false }); } } removeFileClickHandler(file, e) { e.stopPropagation(); const answer = confirm(`Are you sure you want to delete "${file.name}"?`); if (answer) { this.props.onRemoveFile(file.path); } } renameFile(e) { // This gets called twice when enter is pressed, because blur also fires. if (!e.target || !this.state.fileBeingRenamed) { return; } const newFileName = e.target.value; if (!this.warnForExistingFileName(newFileName)) { return; } if (newFileName) { this.props.onRenameFile(this.state.fileBeingRenamed.path, newFileName); } this.setState({ fileBeingRenamed: null }); } renameFileNameInputKeyUpHandler(e) { if (e.which === ENTER_KEY) { this.renameFile(e); } else if (e.which === ESCAPE_KEY) { this.setState({ fileBeingRenamed: null }); } } renameFileClickHandler(file, e) { e.stopPropagation(); this.setState({ fileBeingRenamed: file }); } dragOverHandler(e) { e.preventDefault(); } dropHandler(e) { e.preventDefault(); // Object with `children` key is to simulate a folder structure for root folder this.props.onFileDrop(e.dataTransfer.getData('text/plain'), { children: this.props.files }); // e.currentTarget.style.outline = null; } render() { const { files, onFileSelect, selectedFile, onRemoveFile } = this.props; const moreProps = { onRemoveBtnClick: this.removeFileClickHandler.bind(this), onRenameBtnClick: this.renameFileClickHandler.bind(this), onNameInputBlur: this.renameFile.bind(this), onNameInputKeyUp: this.renameFileNameInputKeyUpHandler.bind(this), fileBeingRenamed: this.state.fileBeingRenamed }; return Object(preact_min["h"])( 'div', { 'class': 'sidebar', onDragOver: this.dragOverHandler.bind(this), onDrop: this.dropHandler.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'flex jc-sb', style: 'padding: 5px 4px' }, 'Files', Object(preact_min["h"])( 'div', { 'class': 'flex flex-v-center' }, Object(preact_min["h"])( 'button', { type: 'button', 'class': 'btn--dark', onClick: this.addFileButtonClickHandler.bind(this) }, SidePane__ref3 ), Object(preact_min["h"])( 'button', { type: 'button', 'class': 'btn--dark', onClick: this.addFolderButtonClickHandler.bind(this) }, SidePane__ref4 ) ) ), this.state.isAddingFile || this.state.isAddingFolder ? Object(preact_min["h"])( 'div', null, Object(preact_min["h"])('input', { type: 'text', ref: el => { el && setTimeout(() => { el.focus(); }, 1); }, onBlur: this.addFile.bind(this), onKeyUp: this.newFileNameInputKeyDownHandler.bind(this) }) ) : null, files.map(file => file.isFolder ? Object(preact_min["h"])(Folder, SidePane__extends({}, this.props, moreProps, { file: file })) : Object(preact_min["h"])(File, SidePane__extends({}, this.props, moreProps, { file: file }))) ); } }; // CONCATENATED MODULE: ./commands.js const SWITCH_FILE_EVENT = 'switchFileEvent'; const NEW_CREATION_EVENT = 'newCreationEvent'; const OPEN_SAVED_CREATIONS_EVENT = 'openSavedCreationsEvent'; const SAVE_EVENT = 'saveEvent'; const OPEN_SETTINGS_EVENT = 'openSettingsEvent'; const SHOW_KEYBOARD_SHORTCUTS_EVENT = 'showKeyboardShortcutsEvent'; const commands = [{ name: 'Start New Creation', event: NEW_CREATION_EVENT, keyboardShortcut: '' }, { name: 'Open Creation', event: OPEN_SAVED_CREATIONS_EVENT, keyboardShortcut: 'Cmd+O' }, { name: 'Save Creation', event: SAVE_EVENT, keyboardShortcut: 'Cmd+S' }, { name: 'Open Settings', event: OPEN_SETTINGS_EVENT, keyboardShortcut: '' }, { name: 'Show Keyboard Shortcuts', event: SHOW_KEYBOARD_SHORTCUTS_EVENT, keyboardShortcut: '' }]; // CONCATENATED MODULE: ./commandPaletteService.js const commandPaletteService = { subscriptions: {}, subscribe(eventName, callback) { this.subscriptions[eventName] = this.subscriptions[eventName] || []; this.subscriptions[eventName].push(callback); return () => { this.subscriptions[eventName].splice(this.subscriptions[eventName].indexOf(callback), 1); }; }, publish(eventName, ...args) { const callbacks = this.subscriptions[eventName] || []; callbacks.forEach(callback => { callback(...args); }); } }; // CONCATENATED MODULE: ./components/ContentWrapFiles.jsx var ContentWrapFiles__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; const ContentWrapFiles_minCodeWrapSize = 33; /* global htmlCodeEl */ var ContentWrapFiles__ref = Object(preact_min["h"])('a', { 'class': 'js-code-collapse-btn code-wrap__header-btn code-wrap__collapse-btn', title: 'Toggle code pane' }); let ContentWrapFiles_ContentWrapFiles = class ContentWrapFiles extends preact_min["Component"] { constructor(props) { super(props); this.state = { isConsoleOpen: false, isCssSettingsModalOpen: false, logs: [], editorOptions: this.getEditorOptions() }; this.fileBuffers = {}; this.updateTimer = null; this.updateDelay = 500; this.htmlMode = HtmlModes.HTML; this.prefs = {}; this.cmCodes = { html: props.currentItem.html, css: '', js: '' }; window.onMessageFromConsole = this.onMessageFromConsole.bind(this); window.previewException = this.previewException.bind(this); // `clearConsole` is on window because it gets called from inside iframe also. window.clearConsole = this.clearConsole.bind(this); this.consoleHeaderDblClickHandler = this.consoleHeaderDblClickHandler.bind(this); this.clearConsoleBtnClickHandler = this.clearConsoleBtnClickHandler.bind(this); this.toggleConsole = this.toggleConsole.bind(this); this.evalConsoleExpr = this.evalConsoleExpr.bind(this); } shouldComponentUpdate(nextProps, nextState) { return this.state.isConsoleOpen !== nextState.isConsoleOpen || this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen || this.state.logs !== nextState.logs || this.state.mainSplitSizes !== nextState.mainSplitSizes || this.state.selectedFile !== nextState.selectedFile || this.props.currentLayoutMode !== nextProps.currentLayoutMode || this.props.currentItem !== nextProps.currentItem || this.props.prefs !== nextProps.prefs; } componentWillUpdate(nextProps) { // If we get a new Item, clear file buffers and currently selected file. if (this.props.currentItem.createdOn !== nextProps.currentItem.createdOn || this.props.currentItem.id !== nextProps.currentItem.id) { this.fileBuffers = {}; this.state.selectedFile = null; } // If the files have changed and we have a selected file (even after previous condition), // update the buffer with new file content (may be it got prettified?) if (nextProps.currentItem.files !== this.props.currentItem.files && this.state.selectedFile && this.fileBuffers[this.state.selectedFile.path]) { this.fileBuffers[this.state.selectedFile.path].model.setValue(getFileFromPath(nextProps.currentItem.files, this.state.selectedFile.path).file.content); } } componentDidUpdate() { const { currentItem } = this.props; const linearFiles = linearizeFiles(currentItem.files); // Select a new file if nothing is selected already or the selected file exists no more. if (currentItem && currentItem.files && (!this.state.selectedFile || !linearFiles.includes(this.state.selectedFile))) { this.fileSelectHandler(linearFiles[0]); } // log('🚀', 'didupdate', this.props.currentItem); // if (this.isValidItem(this.props.currentItem)) { // this.refreshEditor(); // } } componentDidMount() { this.props.onRef(this); this.commandPaletteSubscriptions = []; this.commandPaletteSubscriptions.push(commandPaletteService.subscribe(SWITCH_FILE_EVENT, file => { const targetFile = getFileFromPath(this.props.currentItem.files, file.path); if (targetFile.file) { this.fileSelectHandler(targetFile.file); } })); } componentWillUnmount() { this.commandPaletteSubscriptions.forEach(unsubscribeFn => unsubscribeFn()); } getEditorOptions(fileName = '') { let options = { gutters: ['error-gutter', 'CodeMirror-linenumbers', 'CodeMirror-foldgutter'], emmet: true }; if (fileName.match(/\.css$/)) {} else if (fileName.match(/\.js$/)) { delete options.emmet; } else if (fileName.match(/\.html$/)) { // HTML options = ContentWrapFiles__extends({}, options, { noAutocomplete: true, matchTags: { bothTags: true } }); } return options; } createEditorDoc(file) { const detectedMode = CodeMirror.findModeByExtension(getExtensionFromFileName(file.name)); let mode, mime; if (detectedMode) { mode = detectedMode.mode; mime = detectedMode.mimes ? detectedMode.mimes[0] : detectedMode.mime; CodeMirror.autoLoadMode(this.cm, mode); } if (mime === 'application/json') { mime = this.props.prefs.isMonacoEditorOn ? 'json' : 'application/ld+json'; } if (!this.props.prefs.isMonacoEditorOn) { this.fileBuffers[file.path] = { model: CodeMirror.Doc(file.content || '', detectedMode ? mime : 'text/plain') }; } else { this.fileBuffers[file.path] = { model: monaco.editor.createModel(file.content || '', mime || 'javascript') }; } } onHtmlCodeChange(editor, change) { this.cmCodes.html = editor.getValue(); this.props.onCodeChange(this.state.selectedFile, this.cmCodes.html, change.origin !== 'setValue'); this.onCodeChange(change); } onCodeChange(change) { clearTimeout(this.updateTimer); this.updateTimer = setTimeout(() => { // This is done so that multiple simultaneous setValue don't trigger too many preview refreshes // and in turn too many file writes on a single file (eg. preview.html). if (change.origin !== 'setValue') { // Specifically checking for false so that the condition doesn't get true even // on absent key - possible when the setting key hasn't been fetched yet. if (this.prefs.autoPreview !== false) { this.setPreviewContent(); } // Track when people actually are working. trackEvent.previewCount = (trackEvent.previewCount || 0) + 1; if (trackEvent.previewCount === 4) { trackEvent('fn', 'usingPreview'); } } }, this.updateDelay); } createPreviewFile() { var obj = {}; const duplicateFiles = JSON.parse(JSON.stringify(this.props.currentItem.files)); // Namespace all file paths to '/user' because thats what the service worker // recognizes. const files = linearizeFiles(assignFilePaths(duplicateFiles, '/user')); files.forEach(file => { obj[file.path] = file.content || ''; // Add screenlog to index.html if (file.name === 'index.html') { obj[file.path] = '' + obj[file.path]; } }); navigator.serviceWorker.controller.postMessage(obj); if (this.detachedWindow) { utils_log('✉️ Sending message to detached window'); this.detachedWindow.postMessage({ contents: '/user/index.html' }, '*'); } else { this.frame.src = '/user/index.html'; } } cleanupErrors() { this.editor.clearGutter('error-gutter'); } showErrors(errors) { this.editor.showErrors(errors); } /** * Generates the preview from the current code. * @param {boolean} isForced Should refresh everything without any check or not * @param {boolean} isManual Is this a manual preview request from user? */ setPreviewContent(isForced, isManual) { if (!this.props.prefs.autoPreview && !isManual) { return; } if (!this.props.prefs.preserveConsoleLogs) { this.clearConsole(); } this.cleanupErrors(); var currentCode = { html: this.cmCodes.html, css: this.cmCodes.css, js: this.cmCodes.js }; utils_log('🔎 setPreviewContent', isForced); const targetFrame = this.detachedWindow ? this.detachedWindow.document.querySelector('iframe') : this.frame; this.createPreviewFile(); // result.forEach(resultItem => { // if (resultItem.errors) { // this.showErrors(resultItem.errors.lang, resultItem.errors.data); // } // }); } isValidItem(item) { return !!item.title; } refreshEditor() { if (this.state.selectedFile) { this.editor.setValue(this.state.selectedFile.content); } if (this.editor) { // this.editor.refresh(); } window.cm = this.cm; 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([this.updateHtmlMode(this.props.currentItem.htmlMode)]).then(() => this.setPreviewContent(true)); } applyCodemirrorSettings(prefs) { document.documentElement.style.setProperty('--code-font-size', `${parseInt(prefs.fontSize, 10)}px`); // Replace correct css file in LINK tags's href if (prefs.editorTheme) { window.editorThemeLinkTag.href = `lib/codemirror/theme/${prefs.editorTheme}.css`; } window.fontStyleTag.textContent = window.fontStyleTemplate.textContent.replace(/fontname/g, (prefs.editorFont === 'other' ? prefs.editorCustomFont : prefs.editorFont) || 'FiraCode'); } // Check all the code wrap if they are minimized or maximized updateCodeWrapCollapseStates() { // This is debounced! clearTimeout(this.updateCodeWrapCollapseStates.timeout); this.updateCodeWrapCollapseStates.timeout = setTimeout(() => { const { currentLayoutMode } = this.props; const prop = currentLayoutMode === 2 || currentLayoutMode === 5 ? 'width' : 'height'; [htmlCodeEl].forEach(function (el) { const bounds = el.getBoundingClientRect(); const size = bounds[prop]; if (size < 100) { el.classList.add('is-minimized'); } else { el.classList.remove('is-minimized'); } if (el.style[prop].indexOf(`100% - ${ContentWrapFiles_minCodeWrapSize * 2}px`) !== -1) { el.classList.add('is-maximized'); } else { el.classList.remove('is-maximized'); } }); }, 50); } resetSplitting() { this.setState({ mainSplitSizes: this.getMainSplitSizesToApply() }); } updateSplits() { this.props.onSplitUpdate(); // Not using setState to avoid re-render this.state.mainSplitSizes = this.props.currentItem.mainSizes; } // Returns the sizes of main code & preview panes. getMainSplitSizesToApply() { var mainSplitSizes; const sidebarWidth = 200; const { currentItem, currentLayoutMode } = this.props; if (currentItem && currentItem.mainSizes) { mainSplitSizes = currentItem.mainSizes; } else { mainSplitSizes = [`${sidebarWidth}px`, `calc(50% - ${sidebarWidth / 2}px)`, `calc(50% - ${sidebarWidth / 2}px)`]; } return mainSplitSizes; } mainSplitDragEndHandler() { if (this.props.prefs.refreshOnResize) { // Running preview updation in next call stack, so that error there // doesn't affect this dragend listener. setTimeout(() => { this.setPreviewContent(true); }, 1); } this.updateSplits(); } mainSplitDragHandler() { this.previewDimension.update({ w: this.frame.clientWidth, h: this.frame.clientHeight }); } /** * Loaded the code comiler based on the mode selected */ handleModeRequirements(mode) { const baseTranspilerPath = 'lib/transpilers'; // Exit if already loaded var d = deferred(); if (modes[mode].hasLoaded) { d.resolve(); return d.promise; } function setLoadedFlag() { modes[mode].hasLoaded = true; d.resolve(); } if (mode === HtmlModes.JADE) { loadJS(`${baseTranspilerPath}/jade.js`).then(setLoadedFlag); } else if (mode === HtmlModes.MARKDOWN) { loadJS(`${baseTranspilerPath}/marked.js`).then(setLoadedFlag); } else if (mode === CssModes.LESS) { loadJS(`${baseTranspilerPath}/less.min.js`).then(setLoadedFlag); } else if (mode === CssModes.SCSS || mode === CssModes.SASS) { loadJS(`${baseTranspilerPath}/sass.js`).then(function () { window.sass = new Sass(`${baseTranspilerPath}/sass.worker.js`); setLoadedFlag(); }); } else if (mode === CssModes.STYLUS) { loadJS(`${baseTranspilerPath}/stylus.min.js`).then(setLoadedFlag); } else if (mode === CssModes.ACSS) { loadJS(`${baseTranspilerPath}/atomizer.browser.js`).then(setLoadedFlag); } else if (mode === JsModes.COFFEESCRIPT) { loadJS(`${baseTranspilerPath}/coffee-script.js`).then(setLoadedFlag); } else if (mode === JsModes.ES6) { loadJS(`${baseTranspilerPath}/babel.min.js`).then(setLoadedFlag); } else if (mode === JsModes.TS) { loadJS(`${baseTranspilerPath}/typescript.js`).then(setLoadedFlag); } else { d.resolve(); } return d.promise; } updateHtmlMode(value) { // this.props.onCodeModeChange('html', value); // this.props.currentItem.htmlMode = value; // this.cm.setOption('mode', modes[value].cmMode); // CodeMirror.autoLoadMode( // this.cm, // modes[value].cmPath || modes[value].cmMode // ); // return this.handleModeRequirements(value); } updateCssMode(value) { // this.props.onCodeModeChange('css', value); // this.props.currentItem.cssMode = value; this.cm.setOption('mode', modes[value].cmMode); this.cm.setOption('readOnly', modes[value].cmDisable); /* window.cssSettingsBtn.classList[ modes[value].hasSettings ? 'remove' : 'add' ]('hide'); */ CodeMirror.autoLoadMode(this.cm, modes[value].cmPath || modes[value].cmMode); return this.handleModeRequirements(value); } updateJsMode(value) { this.cm.setOption('mode', modes[value].cmMode); CodeMirror.autoLoadMode(this.cm, modes[value].cmPath || modes[value].cmMode); return this.handleModeRequirements(value); } getDemoFrame(callback) { callback(this.frame); } editorFocusHandler(editor) { this.props.onEditorFocus(editor); } fileSelectHandler(file) { if (file.isFolder) { this.props.onFolderSelect(file); return; } if (!this.fileBuffers[file.path]) { this.createEditorDoc(file); } const currentState = this.editor.saveViewState(); if (currentState && this.state.selectedFile) { this.fileBuffers[this.state.selectedFile.path].state = currentState; } this.setState({ editorOptions: this.getEditorOptions(file.name), selectedFile: file }); this.editor.setModel(this.fileBuffers[file.path].model); if (this.fileBuffers[file.path].state) { this.editor.restoreViewState(this.fileBuffers[file.path].state); } this.editor.focus(); } onMessageFromConsole() { const logs = [...arguments].map(arg => { if (arg && arg.indexOf && arg.indexOf('filesystem:chrome-extension') !== -1) { return arg.replace(/filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, 'script $1:$2'); } return arg; }); this.setState({ logs: [...this.state.logs, ...logs] }); } previewException(error) { console.error('Possible infinite loop detected.', error.stack); this.onMessageFromConsole('Possible infinite loop detected.', error.stack); } toggleConsole() { this.setState({ isConsoleOpen: !this.state.isConsoleOpen }); trackEvent('ui', 'consoleToggle'); } consoleHeaderDblClickHandler(e) { if (!e.target.classList.contains('js-console__header')) { return; } trackEvent('ui', 'consoleToggleDblClick'); this.toggleConsole(); } clearConsole() { this.setState({ logs: [] }); } clearConsoleBtnClickHandler() { this.clearConsole(); trackEvent('ui', 'consoleClearBtnClick'); } evalConsoleExpr(e) { // Clear console on CTRL + L if ((e.which === 76 || e.which === 12) && e.ctrlKey) { this.clearConsole(); trackEvent('ui', 'consoleClearKeyboardShortcut'); } else if (e.which === 13) { this.onMessageFromConsole('> ' + e.target.value); /* eslint-disable no-underscore-dangle */ this.frame.contentWindow._wmEvaluate(e.target.value); /* eslint-enable no-underscore-dangle */ e.target.value = ''; trackEvent('fn', 'evalConsoleExpr'); } } prettifyBtnClickHandler() { this.props.onPrettifyBtnClick(this.state.selectedFile); } render() { return Object(preact_min["h"])( SplitPane_SplitPane, { 'class': 'content-wrap flex flex-grow', sizes: this.state.mainSplitSizes, minSize: 150, style: '', direction: this.props.currentLayoutMode === 2 ? 'vertical' : 'horizontal', onDrag: this.mainSplitDragHandler.bind(this), onDragEnd: this.mainSplitDragEndHandler.bind(this) }, Object(preact_min["h"])( 'div', { id: 'js-sidebar' }, Object(preact_min["h"])(SidePane_SidePane, { files: this.props.currentItem.files || [], selectedFile: this.state.selectedFile, onFileSelect: this.fileSelectHandler.bind(this), onAddFile: this.props.onAddFile, onRemoveFile: this.props.onRemoveFile, onRenameFile: this.props.onRenameFile, onFileDrop: this.props.onFileDrop }) ), Object(preact_min["h"])( 'div', { 'class': 'code-side', id: 'js-code-side' }, Object(preact_min["h"])( 'div', { 'data-code-wrap-id': '0', id: 'htmlCodeEl', 'data-type': 'html', 'class': 'code-wrap', onTransitionEnd: this.updateCodeWrapCollapseStates.bind(this) }, Object(preact_min["h"])( 'div', { 'class': 'js-code-wrap__header code-wrap__header', title: 'Double click to toggle code pane' }, Object(preact_min["h"])( 'label', { 'class': 'btn-group', dropdow: true, title: 'Click to change' }, this.state.selectedFile ? this.state.selectedFile.name : '' ), Object(preact_min["h"])( 'div', { 'class': 'code-wrap__header-right-options' }, Object(preact_min["h"])( 'button', { 'class': 'btn btn--dark', onClick: this.prettifyBtnClickHandler.bind(this) }, 'Prettify' ), ContentWrapFiles__ref ) ), Object(preact_min["h"])(CodeEditor_CodeEditor, { type: this.props.prefs.isMonacoEditorOn ? 'monaco' : 'codemirror', value: this.state.selectedFile ? this.state.selectedFile.content : '', options: this.state.editorOptions, prefs: this.props.prefs, onChange: this.onHtmlCodeChange.bind(this), ref: editor => this.editor = editor, onFocus: this.editorFocusHandler.bind(this) }) ) ), Object(preact_min["h"])( 'div', { 'class': 'demo-side', id: 'js-demo-side', style: '' }, Object(preact_min["h"])('iframe', { ref: el => this.frame = el, src: '/user/index.html', frameborder: '0', id: 'demo-frame', allowfullscreen: true }), Object(preact_min["h"])(PreviewDimension_PreviewDimension, { ref: comp => this.previewDimension = comp }), Object(preact_min["h"])(Console_Console, { logs: this.state.logs, isConsoleOpen: this.state.isConsoleOpen, onConsoleHeaderDblClick: this.consoleHeaderDblClickHandler, onClearConsoleBtnClick: this.clearConsoleBtnClickHandler, toggleConsole: this.toggleConsole, onEvalInputKeyup: this.evalConsoleExpr }) ) ); } }; // CONCATENATED MODULE: ./components/Footer.jsx var Footer__ref = Object(preact_min["h"])('img', { src: 'assets/js13kgames.png', alt: 'JS13K Games logo', height: '24' }); let Footer_JS13K = class JS13K extends preact_min["Component"] { constructor(props) { super(props); const compoDate = new Date('August 13 2018 11:00 GMT'); var now = new Date(); var daysLeft; if (+compoDate > +now) { daysLeft = Math.floor((compoDate - now) / 1000 / 3600 / 24); } this.setState({ daysLeft }); } render() { const codeSizeInKb = this.props.codeSize ? (this.props.codeSize / 1024).toFixed(2) : 0; return Object(preact_min["h"])( 'div', { role: 'button', 'class': 'flex flex-v-center', tabIndex: '0', onClick: this.props.onClick, onBlur: this.props.onBlur }, Footer__ref, ' ', Object(preact_min["h"])( 'div', { 'class': 'footer__js13k-days-left' }, this.state.daysLeft, ' days to go' ), Object(preact_min["h"])( 'div', { 'class': 'footer__js13k-code-size', style: { color: codeSizeInKb > 10 ? 'crimson' : 'limegreen' } }, codeSizeInKb, ' KB/ 13KB' ), Object(preact_min["h"])('span', { 'class': 'caret', style: `transition:0.3s ease; transform-origin: center 2px; ${this.props.isOpen ? 'transform:rotate(180deg);' : ''}` }) ); } }; var Footer__ref2 = Object(preact_min["h"])( 'a', { href: 'https://webmakerapp.com/', target: '_blank', rel: 'noopener noreferrer' }, Object(preact_min["h"])('div', { 'class': 'logo' }) ); var Footer__ref3 = Object(preact_min["h"])( 'span', { 'class': 'web-maker-with-tag' }, 'Web Maker' ); var Footer__ref4 = Object(preact_min["h"])( 'svg', { style: 'width:20px; height:20px; vertical-align:text-bottom', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M15.07,11.25L14.17,12.17C13.45,12.89 13,13.5 13,15H11V14.5C11,13.39 11.45,12.39 12.17,11.67L13.41,10.41C13.78,10.05 14,9.55 14,9C14,7.89 13.1,7 12,7A2,2 0 0,0 10,9H8A4,4 0 0,1 12,5A4,4 0 0,1 16,9C16,9.88 15.64,10.67 15.07,11.25M13,19H11V17H13M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2Z' }) ); var Footer__ref5 = Object(preact_min["h"])('use', { xlinkHref: '#keyboard-icon' }); var Footer__ref6 = Object(preact_min["h"])('use', { xlinkHref: '#twitter-icon' }); var Footer__ref7 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z' }) ); var Footer__ref8 = Object(preact_min["h"])( 'svg', { style: 'display: none;', xmlns: 'http://www.w3.org/2000/svg' }, Object(preact_min["h"])( 'symbol', { id: 'codepen-logo', viewBox: '0 0 120 120' }, Object(preact_min["h"])('path', { 'class': 'outer-ring', d: 'M60.048 0C26.884 0 0 26.9 0 60.048s26.884 60 60 60.047c33.163 0 60.047-26.883 60.047-60.047 S93.211 0 60 0z M60.048 110.233c-27.673 0-50.186-22.514-50.186-50.186S32.375 9.9 60 9.9 c27.672 0 50.2 22.5 50.2 50.186S87.72 110.2 60 110.233z' }), Object(preact_min["h"])('path', { 'class': 'inner-box', d: 'M97.147 48.319c-0.007-0.047-0.019-0.092-0.026-0.139c-0.016-0.09-0.032-0.18-0.056-0.268 c-0.014-0.053-0.033-0.104-0.05-0.154c-0.025-0.078-0.051-0.156-0.082-0.232c-0.021-0.053-0.047-0.105-0.071-0.156 c-0.033-0.072-0.068-0.143-0.108-0.211c-0.029-0.051-0.061-0.1-0.091-0.148c-0.043-0.066-0.087-0.131-0.135-0.193 c-0.035-0.047-0.072-0.094-0.109-0.139c-0.051-0.059-0.104-0.117-0.159-0.172c-0.042-0.043-0.083-0.086-0.127-0.125 c-0.059-0.053-0.119-0.104-0.181-0.152c-0.048-0.037-0.095-0.074-0.145-0.109c-0.019-0.012-0.035-0.027-0.053-0.039L61.817 23.5 c-1.072-0.715-2.468-0.715-3.54 0L24.34 46.081c-0.018 0.012-0.034 0.027-0.053 0.039c-0.05 0.035-0.097 0.072-0.144 0.1 c-0.062 0.049-0.123 0.1-0.181 0.152c-0.045 0.039-0.086 0.082-0.128 0.125c-0.056 0.055-0.108 0.113-0.158 0.2 c-0.038 0.045-0.075 0.092-0.11 0.139c-0.047 0.062-0.092 0.127-0.134 0.193c-0.032 0.049-0.062 0.098-0.092 0.1 c-0.039 0.068-0.074 0.139-0.108 0.211c-0.024 0.051-0.05 0.104-0.071 0.156c-0.031 0.076-0.057 0.154-0.082 0.2 c-0.017 0.051-0.035 0.102-0.05 0.154c-0.023 0.088-0.039 0.178-0.056 0.268c-0.008 0.047-0.02 0.092-0.025 0.1 c-0.019 0.137-0.029 0.275-0.029 0.416V71.36c0 0.1 0 0.3 0 0.418c0.006 0 0 0.1 0 0.1 c0.017 0.1 0 0.2 0.1 0.268c0.015 0.1 0 0.1 0.1 0.154c0.025 0.1 0.1 0.2 0.1 0.2 c0.021 0.1 0 0.1 0.1 0.154c0.034 0.1 0.1 0.1 0.1 0.213c0.029 0 0.1 0.1 0.1 0.1 c0.042 0.1 0.1 0.1 0.1 0.193c0.035 0 0.1 0.1 0.1 0.139c0.05 0.1 0.1 0.1 0.2 0.2 c0.042 0 0.1 0.1 0.1 0.125c0.058 0.1 0.1 0.1 0.2 0.152c0.047 0 0.1 0.1 0.1 0.1 c0.019 0 0 0 0.1 0.039L58.277 96.64c0.536 0.4 1.2 0.5 1.8 0.537c0.616 0 1.233-0.18 1.77-0.537 l33.938-22.625c0.018-0.012 0.034-0.027 0.053-0.039c0.05-0.035 0.097-0.072 0.145-0.109c0.062-0.049 0.122-0.1 0.181-0.152 c0.044-0.039 0.085-0.082 0.127-0.125c0.056-0.055 0.108-0.113 0.159-0.172c0.037-0.045 0.074-0.09 0.109-0.139 c0.048-0.062 0.092-0.127 0.135-0.193c0.03-0.049 0.062-0.098 0.091-0.146c0.04-0.07 0.075-0.141 0.108-0.213 c0.024-0.051 0.05-0.102 0.071-0.154c0.031-0.078 0.057-0.156 0.082-0.234c0.017-0.051 0.036-0.102 0.05-0.154 c0.023-0.088 0.04-0.178 0.056-0.268c0.008-0.045 0.02-0.092 0.026-0.137c0.018-0.139 0.028-0.277 0.028-0.418V48.735 C97.176 48.6 97.2 48.5 97.1 48.319z M63.238 32.073l25.001 16.666L77.072 56.21l-13.834-9.254V32.073z M56.856 32.1 v14.883L43.023 56.21l-11.168-7.471L56.856 32.073z M29.301 54.708l7.983 5.34l-7.983 5.34V54.708z M56.856 88.022L31.855 71.4 l11.168-7.469l13.833 9.252V88.022z M60.048 67.597l-11.286-7.549l11.286-7.549l11.285 7.549L60.048 67.597z M63.238 88.022V73.14 l13.834-9.252l11.167 7.469L63.238 88.022z M90.794 65.388l-7.982-5.34l7.982-5.34V65.388z' }) ) ); var Footer__ref9 = Object(preact_min["h"])( 'svg', null, Object(preact_min["h"])('use', { xlinkHref: '#codepen-logo' }) ); var Footer__ref10 = Object(preact_min["h"])( 'svg', { style: 'width:24px;height:24px', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M4,4H7L9,2H15L17,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9Z' }) ); var Footer__ref11 = Object(preact_min["h"])('div', { 'class': 'footer__separator hide-on-mobile' }); var Footer__ref12 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 100 100', style: 'transform:rotate(-90deg)' }, Object(preact_min["h"])('use', { xlinkHref: '#mode-icon' }) ); var Footer__ref13 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 100 100' }, Object(preact_min["h"])('use', { xlinkHref: '#mode-icon' }) ); var Footer__ref14 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 100 100', style: 'transform:rotate(90deg)' }, Object(preact_min["h"])('use', { xlinkHref: '#mode-icon' }) ); var Footer__ref15 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 100 100' }, Object(preact_min["h"])('use', { xlinkHref: '#vertical-mode-icon' }) ); var Footer__ref16 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 100 100' }, Object(preact_min["h"])('rect', { x: '0', y: '0', width: '100', height: '100' }) ); var Footer__ref17 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M22,17V7H6V17H22M22,5A2,2 0 0,1 24,7V17C24,18.11 23.1,19 22,19H16V21H18V23H10V21H12V19H6C4.89,19 4,18.11 4,17V7A2,2 0 0,1 6,5H22M2,3V15H0V3A2,2 0 0,1 2,1H20V3H2Z' }) ); var _ref18 = Object(preact_min["h"])('div', { 'class': 'footer__separator' }); var _ref19 = Object(preact_min["h"])( 'svg', { viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { d: 'M14,20A2,2 0 0,1 12,22A2,2 0 0,1 10,20H14M12,2A1,1 0 0,1 13,3V4.08C15.84,4.56 18,7.03 18,10V16L21,19H3L6,16V10C6,7.03 8.16,4.56 11,4.08V3A1,1 0 0,1 12,2Z' }) ); var _ref20 = Object(preact_min["h"])('span', { 'class': 'notifications-btn__dot' }); var _ref21 = Object(preact_min["h"])( 'svg', null, Object(preact_min["h"])('use', { xlinkHref: '#settings-icon' }) ); let Footer_Footer = class Footer extends preact_min["Component"] { constructor(props) { super(props); this.state = { isKeyboardShortcutsModalOpen: false, isJs13kDropdownOpen: false }; } layoutBtnClickhandler(layoutId) { this.props.layoutBtnClickHandler(layoutId); } js13kClickHandler() { // console.log(999); this.setState({ isJs13kDropdownOpen: !this.state.isJs13kDropdownOpen }); } render() { return Object(preact_min["h"])( 'div', { id: 'footer', 'class': 'footer' }, Object(preact_min["h"])( 'div', null, Footer__ref2, '\xA9', Footer__ref3, ' \xA0\xA0', Object(preact_min["h"])( Button, { onClick: this.props.helpBtnClickHandler, 'data-event-category': 'ui', 'data-event-action': 'helpButtonClick', 'class': 'footer__link hint--rounded hint--top-right', 'aria-label': 'Help' }, Footer__ref4 ), Object(preact_min["h"])( Button, { onClick: this.props.keyboardShortcutsBtnClickHandler, 'data-event-category': 'ui', 'data-event-action': 'keyboardShortcutButtonClick', 'class': 'footer__link hint--rounded hint--top-right hide-on-mobile', 'aria-label': 'Keyboard shortcuts' }, Object(preact_min["h"])( 'svg', { style: { width: '20px', height: '20px', verticalAlign: 'text-bottom' } }, Footer__ref5 ) ), Object(preact_min["h"])( 'a', { 'class': 'footer__link hint--rounded hint--top-right', 'aria-label': 'Tweet about \'Web Maker\'', href: 'http://twitter.com/share?url=https://webmakerapp.com/&text=Web Maker - A blazing fast %26 offline web playground! via @webmakerApp&related=webmakerApp&hashtags=web,frontend,playground,offline', target: '_blank', rel: 'noopener noreferrer' }, Object(preact_min["h"])( 'svg', { style: { width: '20px', height: '20px', verticalAlign: 'text-bottom' } }, Footer__ref6 ) ), Object(preact_min["h"])( Button, { onClick: this.props.supportDeveloperBtnClickHandler, 'data-event-category': 'ui', 'data-event-action': 'supportDeveloperFooterBtnClick', 'class': 'footer__link ml-1 hint--rounded hint--top-right hide-on-mobile support-link', 'aria-label': 'Support the developer by pledging some amount' }, 'Donate' ) ), this.props.prefs.isJs13kModeOn ? Object(preact_min["h"])( 'div', { 'class': 'flex flex-v-center' }, Object(preact_min["h"])(Footer_JS13K, { isOpen: this.state.isJs13kDropdownOpen, codeSize: this.props.codeSize, onClick: this.js13kClickHandler.bind(this), onBlur: () => setTimeout(() => this.setState({ isJs13kDropdownOpen: false }), 300) }), this.state.isJs13kDropdownOpen && Object(preact_min["h"])( 'div', { className: 'js13k__dropdown' }, Object(preact_min["h"])( 'button', { 'class': 'btn', style: { width: '200px', display: 'block', marginBottom: '16px' }, onClick: this.props.onJs13KDownloadBtnClick }, 'Download game as zip' ), Object(preact_min["h"])( 'a', { 'class': 'btn', rel: 'noopener', style: { width: '200px', display: 'block', marginBottom: '16px' }, href: 'https://pasteboard.co/', target: '_blank' }, 'Upload Image' ), Object(preact_min["h"])( 'button', { 'class': 'btn', style: { width: '200px', display: 'block' }, onClick: this.props.onJs13KHelpBtnClick }, 'Help' ) ) ) : null, Object(preact_min["h"])( 'div', { 'class': 'footer__right' }, Object(preact_min["h"])( 'button', { onClick: this.props.saveHtmlBtnClickHandler, id: 'saveHtmlBtn', 'class': 'mode-btn hint--rounded hint--top-left hide-on-mobile hide-in-file-mode', 'aria-label': 'Save as HTML file' }, Footer__ref7 ), Footer__ref8, Object(preact_min["h"])( 'button', { onClick: this.props.codepenBtnClickHandler, id: 'codepenBtn', 'class': 'mode-btn hint--rounded hint--top-left hide-on-mobile hide-in-file-mode', 'aria-label': 'Edit on CodePen' }, Footer__ref9 ), Object(preact_min["h"])( 'button', { id: 'screenshotBtn', 'class': 'mode-btn hint--rounded hint--top-left show-when-extension', onClick: this.props.screenshotBtnClickHandler, 'aria-label': 'Take screenshot of preview' }, Footer__ref10 ), Footer__ref11, Object(preact_min["h"])( 'button', { onClick: this.layoutBtnClickhandler.bind(this, 1), id: 'layoutBtn1', 'class': 'mode-btn hide-on-mobile hide-in-file-mode', 'aria-label': 'Switch to layout with preview on right' }, Footer__ref12 ), Object(preact_min["h"])( 'button', { onClick: this.layoutBtnClickhandler.bind(this, 2), id: 'layoutBtn2', 'class': 'mode-btn hide-on-mobile hide-in-file-mode', 'aria-label': 'Switch to layout with preview on bottom' }, Footer__ref13 ), Object(preact_min["h"])( 'button', { onClick: this.layoutBtnClickhandler.bind(this, 3), id: 'layoutBtn3', 'class': 'mode-btn hide-on-mobile hide-in-file-mode', 'aria-label': 'Switch to layout with preview on left' }, Footer__ref14 ), Object(preact_min["h"])( 'button', { onClick: this.layoutBtnClickhandler.bind(this, 5), id: 'layoutBtn5', 'class': 'mode-btn hide-on-mobile hide-in-file-mode', 'aria-label': 'Switch to layout with all vertical panes' }, Footer__ref15 ), Object(preact_min["h"])( 'button', { onClick: this.layoutBtnClickhandler.bind(this, 4), id: 'layoutBtn4', 'class': 'mode-btn hint--top-left hint--rounded hide-on-mobile', 'aria-label': 'Switch to full screen preview' }, Footer__ref16 ), Object(preact_min["h"])( 'button', { 'class': 'mode-btn hint--top-left hint--rounded hide-on-mobile', 'aria-label': 'Detach Preview', onClick: this.props.detachedPreviewBtnHandler }, Footer__ref17 ), _ref18, Object(preact_min["h"])( 'button', { onClick: this.props.notificationsBtnClickHandler, id: 'notificationsBtn', 'class': `notifications-btn mode-btn hint--top-left hint--rounded ${this.props.hasUnseenChangelog ? 'has-new' : ''}`, 'aria-label': 'See Changelog' }, _ref19, _ref20 ), Object(preact_min["h"])( Button, { onClick: this.props.settingsBtnClickHandler, 'data-event-category': 'ui', 'data-event-action': 'settingsBtnClick', 'class': 'mode-btn hint--top-left hint--rounded', 'aria-label': 'Settings' }, _ref21 ) ) ); } }; // EXTERNAL MODULE: ../node_modules/util/util.js var util = __webpack_require__("gfUn"); var util_default = /*#__PURE__*/__webpack_require__.n(util); // CONCATENATED MODULE: ./itemService.js const itemService = { async getItem(id) { var remoteDb = await window.db.getDb(); return remoteDb.doc(`items/${id}`).get().then(doc => { return doc.data(); }); }, async getUserItemIds() { if (window.user) { return new Promise(resolve => { resolve(window.user.items || {}); }); } var remoteDb = await window.db.getDb(); return remoteDb.doc(`users/${window.user.uid}`).get().then(doc => { if (!doc.exists) { return {}; } return doc.data().items; }); }, async getAllItems() { var t = Date.now(); var d = deferred(); let itemIds = await this.getUserItemIds(); itemIds = Object.getOwnPropertyNames(itemIds || {}); Object(util["log"])('itemids', itemIds); if (!itemIds.length) { d.resolve([]); } var remoteDb = await window.db.getDb(); const items = []; remoteDb.collection('items').where('createdBy', '==', window.user.uid).onSnapshot(function (querySnapshot) { querySnapshot.forEach(function (doc) { items.push(doc.data()); }); Object(util["log"])('Items fetched in ', Date.now() - t, 'ms'); d.resolve(items); }, function () { d.resolve([]); }); return d.promise; }, async setUser() { const remoteDb = await window.db.getDb(); return remoteDb.doc(`users/${window.user.uid}`).set({ items: {} }); }, async setItem(id, item) { const d = deferred(); var remotePromise; // TODO: check why we need to save locally always? const obj = { [id]: item }; db.local.set(obj, () => { // Is extension OR is app but logged out OR is logged in but offline // If logged in but offline, resolve immediately so // that you see the feedback msg immediately and not wait for // later sync. if (window.IS_EXTENSION || !window.user || !navigator.onLine) { d.resolve(); } }); // If `id` is `code`, this is a call on unloadbefore to save the last open thing. // Do not presist that on remote. if (id === 'code') { // No deferred required here as this gets called on unloadbefore return false; } if (window.user) { var remoteDb = await window.db.getDb(); Object(util["log"])(`Starting to save item ${id}`); item.createdBy = window.user.uid; remotePromise = remoteDb.collection('items').doc(id).set(item, { merge: true }).then(arg => { Object(util["log"])('Document written', arg); d.resolve(); }).catch(d.reject); } return window.user && navigator.onLine ? remotePromise : d.promise; }, /** * Saves the passed items in the database. * @param {Array} items to be saved in DB */ saveItems(items) { var d = deferred(); // When not logged in if (!window.user) { // save new items window.db.local.set(items, d.resolve); // Push in new item IDs window.db.local.get({ items: {} }, function (result) { /* eslint-disable guard-for-in */ for (var id in items) { result.items[id] = true; } window.db.local.set({ items: result.items }); /* eslint-enable guard-for-in */ }); } else { window.db.getDb().then(remoteDb => { const batch = remoteDb.batch(); /* eslint-disable guard-for-in */ for (var id in items) { items[id].createdBy = window.user.uid; batch.set(remoteDb.doc(`items/${id}`), items[id]); batch.update(remoteDb.doc(`users/${window.user.uid}`), { [`items.${id}`]: true }); // Set these items on our cached user object too window.user.items = window.user.items || {}; window.user.items[id] = true; } batch.commit().then(d.resolve); /* eslint-enable guard-for-in */ }); } return d.promise; }, async removeItem(id) { // When not logged in if (!window.user) { var d = deferred(); window.db.local.remove(id, d.resolve); return d.promise; } const remoteDb = await window.db.getDb(); Object(util["log"])(`Starting to save item ${id}`); return remoteDb.collection('items').doc(id).delete().then(arg => { Object(util["log"])('Document removed', arg); }).catch(error => Object(util["log"])(error)); }, async setItemForUser(itemId) { // When not logged in if (!window.user) { return window.db.local.get({ items: {} }, function (result) { result.items[itemId] = true; window.db.local.set({ items: result.items }); }); } const remoteDb = await window.db.getDb(); return remoteDb.collection('users').doc(window.user.uid).update({ [`items.${itemId}`]: true }).then(arg => { Object(util["log"])(`Item ${itemId} set for user`, arg); window.user.items = window.user.items || {}; window.user.items[itemId] = true; }).catch(error => Object(util["log"])(error)); }, async unsetItemForUser(itemId) { // When not logged in if (!window.user) { return window.db.local.get({ items: {} }, function (result) { delete result.items[itemId]; window.db.local.set({ items: result.items }); }); } const remoteDb = await window.db.getDb(); return remoteDb.collection('users').doc(window.user.uid).update({ [`items.${itemId}`]: firebase.firestore.FieldValue.delete() }).then(arg => { delete window.user.items[itemId]; Object(util["log"])(`Item ${itemId} unset for user`, arg); }).catch(error => Object(util["log"])(error)); } }; // CONCATENATED MODULE: ./notifications.js var hideTimeout; function addNotification(msg) { const noticationContainerEL = $('#js-alerts-container'); // var n = document.createElement('div'); // div.textContent = msg; // noticationContainerEL.appendChild(n); noticationContainerEL.textContent = msg; noticationContainerEL.classList.add('is-active'); clearTimeout(hideTimeout); hideTimeout = setTimeout(function () { noticationContainerEL.classList.remove('is-active'); }, 2000); } const alertsService = { add: addNotification }; window.alertsService = alertsService; // CONCATENATED MODULE: ./components/ItemTile.jsx var ItemTile__ref = Object(preact_min["h"])( 'span', { 'class': 'show-when-selected' }, '(Ctrl/\u2318 + F)' ); var ItemTile__ref2 = Object(preact_min["h"])( 'svg', { style: 'width:24px;height:24px', viewBox: '0 0 24 24' }, Object(preact_min["h"])('path', { fill: 'currentColor', d: 'M15,7H20.5L15,1.5V7M8,0H16L22,6V18A2,2 0 0,1 20,20H8C6.89,20 6,19.1 6,18V2A2,2 0 0,1 8,0M4,4V22H20V24H4A2,2 0 0,1 2,22V4H4Z' }) ); function ItemTile({ item, onClick, onForkBtnClick, onRemoveBtnClick, focusable, inline }) { return Object(preact_min["h"])( 'div', { role: focusable ? 'button' : null, tabindex: focusable ? 0 : null, 'class': `js-saved-item-tile saved-item-tile ${inline ? 'saved-item-tile--inline' : ''}`, 'data-item-id': item.id, onClick: onClick }, Object(preact_min["h"])( 'div', { 'class': 'saved-item-tile__btns' }, onForkBtnClick ? Object(preact_min["h"])( 'a', { 'class': 'js-saved-item-tile__fork-btn saved-item-tile__btn hint--left hint--medium', 'aria-label': 'Creates a duplicate of this creation (Ctrl/\u2318 + F)', onClick: onForkBtnClick }, 'Fork', ItemTile__ref ) : null, onRemoveBtnClick ? Object(preact_min["h"])( 'a', { 'class': 'js-saved-item-tile__remove-btn saved-item-tile__btn hint--left', 'aria-label': 'Remove', onClick: onRemoveBtnClick }, 'X' ) : null ), Object(preact_min["h"])( 'div', { className: 'flex flex-v-center' }, item.img ? Object(preact_min["h"])( 'div', null, Object(preact_min["h"])('img', { 'class': 'saved-item-tile__img', height: '40', src: item.img, alt: '' }) ) : null, Object(preact_min["h"])( 'h3', { 'class': 'saved-item-tile__title' }, item.title ), item.files ? ItemTile__ref2 : null ), item.updatedOn ? Object(preact_min["h"])( 'div', { 'class': 'saved-item-tile__meta' }, 'Last updated: ', getHumanDate(item.updatedOn) ) : null ); } // CONCATENATED MODULE: ./components/SavedItemPane.jsx var SavedItemPane__ref = Object(preact_min["h"])( 'div', { 'class': 'mt-1' }, 'No match found.' ); var SavedItemPane__ref2 = Object(preact_min["h"])( 'h2', { 'class': 'opacity--30' }, 'Nothing saved here.' ); let SavedItemPane_SavedItemPane = class SavedItemPane extends preact_min["Component"] { constructor(props) { super(props); this.items = []; this.state = { filteredItems: [] }; } componentWillUpdate(nextProps) { if (this.props.items !== nextProps.items) { this.items = Object.values(nextProps.items); this.items.sort(function (a, b) { return b.updatedOn - a.updatedOn; }); this.setState({ filteredItems: this.items }); } } componentDidUpdate(prevProps) { if (this.props.isOpen && !prevProps.isOpen) { window.searchInput.value = ''; } } onCloseIntent() { this.props.closeHandler(); } itemClickHandler(item) { this.props.itemClickHandler(item); } itemRemoveBtnClickHandler(item, e) { e.stopPropagation(); this.props.itemRemoveBtnClickHandler(item); } itemForkBtnClickHandler(item, e) { e.stopPropagation(); this.props.itemForkBtnClickHandler(item); } keyDownHandler(event) { if (!this.props.isOpen) { return; } const isCtrlOrMetaPressed = event.ctrlKey || event.metaKey; const isForkKeyPressed = isCtrlOrMetaPressed && event.keyCode === 70; const isDownKeyPressed = event.keyCode === 40; const isUpKeyPressed = event.keyCode === 38; const isEnterKeyPressed = event.keyCode === 13; const selectedItemElement = $('.js-saved-item-tile.selected'); const havePaneItems = $all('.js-saved-item-tile').length !== 0; if ((isDownKeyPressed || isUpKeyPressed) && havePaneItems) { const method = isDownKeyPressed ? 'nextUntil' : 'previousUntil'; if (selectedItemElement) { selectedItemElement.classList.remove('selected'); selectedItemElement[method]('.js-saved-item-tile:not(.hide)').classList.add('selected'); } else { $('.js-saved-item-tile:not(.hide)').classList.add('selected'); } $('.js-saved-item-tile.selected').scrollIntoView(false); } if (isEnterKeyPressed && selectedItemElement) { const item = this.props.items[selectedItemElement.dataset.itemId]; console.log('opening', item); this.props.itemClickHandler(item); trackEvent('ui', 'openItemKeyboardShortcut'); } // Fork shortcut inside saved creations panel with Ctrl/⌘ + F if (isForkKeyPressed) { event.preventDefault(); const item = this.props.items[selectedItemElement.dataset.itemId]; this.props.itemForkBtnClickHandler(item); trackEvent('ui', 'forkKeyboardShortcut'); } } importFileChangeHandler(e) { var file = e.target.files[0]; var reader = new FileReader(); reader.addEventListener('load', progressEvent => { var items; try { items = JSON.parse(progressEvent.target.result); utils_log(items); this.props.mergeImportedItems(items); } catch (exception) { utils_log(exception); alert('Oops! Selected file is corrupted. Please select a file that was generated by clicking the "Export" button.'); } }); reader.readAsText(file, 'utf-8'); } importBtnClickHandler(e) { var input = document.createElement('input'); input.type = 'file'; input.style.display = 'none'; input.accept = 'accept="application/json'; document.body.appendChild(input); input.addEventListener('change', this.importFileChangeHandler.bind(this)); input.click(); trackEvent('ui', 'importBtnClicked'); e.preventDefault(); } searchInputHandler(e) { const text = e.target.value; if (!text) { this.setState({ filteredItems: this.items }); } else { this.setState({ filteredItems: this.items.filter(item => item.title.toLowerCase().indexOf(text) !== -1) }); } trackEvent('ui', 'searchInputType'); } render() { return Object(preact_min["h"])( 'div', { id: 'js-saved-items-pane', 'class': `saved-items-pane ${this.props.isOpen ? 'is-open' : ''}`, onKeyDown: this.keyDownHandler.bind(this) }, Object(preact_min["h"])( 'button', { onClick: this.onCloseIntent.bind(this), 'class': 'btn saved-items-pane__close-btn', id: 'js-saved-items-pane-close-btn' }, 'X' ), Object(preact_min["h"])( 'div', { 'class': 'flex flex-v-center', style: 'justify-content: space-between;' }, Object(preact_min["h"])( 'h3', null, 'My Library (', this.items.length, ')' ), Object(preact_min["h"])( 'div', null, Object(preact_min["h"])( 'button', { onClick: this.props.exportBtnClickHandler, 'class': 'btn--dark hint--bottom-left hint--rounded hint--medium', 'aria-label': 'Export all your creations into a single importable file.' }, 'Export' ), Object(preact_min["h"])( 'button', { onClick: this.importBtnClickHandler.bind(this), 'class': 'btn--dark hint--bottom-left hint--rounded hint--medium', 'aria-label': 'Import your creations. Only the file that you export through the \'Export\' button can be imported.' }, 'Import' ) ) ), Object(preact_min["h"])('input', { type: 'search', id: 'searchInput', 'class': 'search-input', onInput: this.searchInputHandler.bind(this), placeholder: 'Search your creations here...' }), Object(preact_min["h"])( 'div', { id: 'js-saved-items-wrap', 'class': 'saved-items-pane__container' }, !this.state.filteredItems.length && this.items.length ? SavedItemPane__ref : null, this.state.filteredItems.map(item => Object(preact_min["h"])(ItemTile, { item: item, onClick: this.itemClickHandler.bind(this, item), onForkBtnClick: this.itemForkBtnClickHandler.bind(this, item), onRemoveBtnClick: this.itemRemoveBtnClickHandler.bind(this, item) })), !this.items.length ? SavedItemPane__ref2 : null ) ); } }; // CONCATENATED MODULE: ./libraryList.js const jsLibs = [{ url: 'https://code.jquery.com/jquery-3.2.1.min.js', label: 'jQuery', type: 'js' }, { url: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js', label: 'Bootstrap 3', type: 'js' }, { url: 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js', label: 'Bootstrap 4', type: 'js' }, { url: 'https://cdn.jsdelivr.net/npm/foundation-sites@6.5.0-rc.3/dist/js/foundation.min.js', label: 'Foundation', type: 'js' }, { url: 'https://semantic-ui.com/dist/semantic.min.js', label: 'Semantic UI', type: 'js' }, { url: 'https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js', label: 'Angular', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js', label: 'React', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js', label: 'React DOM', type: 'js' }, { url: 'https://unpkg.com/vue/dist/vue.min.js', label: 'Vue.js', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js', label: 'Three.js', type: 'js' }, { url: 'https://d3js.org/d3.v5.min.js', label: 'D3', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js', label: 'Underscore', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js', label: 'Greensock TweenMax', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/js/uikit.min.js', label: 'UIkit 2', type: 'js' }, { url: 'https://getuikit.com/assets/uikit/dist/js/uikit.js', label: 'UIkit 3', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js', label: 'p5.js', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.dom.min.js', label: 'p5.js DOM', type: 'js' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.sound.min.js', label: 'p5.js Sound', type: 'js' }, { url: 'https://unpkg.com/rxjs/bundles/rxjs.umd.min.js', label: 'RxJS', type: 'js' }]; const cssLibs = [{ url: 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', label: 'Bootstrap 3', type: 'css' }, { url: 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css', label: 'Bootstrap 4', type: 'css' }, { url: 'https://cdn.jsdelivr.net/npm/foundation-sites@6.5.0-rc.3/dist/css/foundation.min.css', label: 'Foundation', type: 'css' }, { url: 'https://semantic-ui.com/dist/semantic.min.css', label: 'Semantic UI', type: 'css' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css', label: 'Bulma', type: 'css' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/hint.css/2.5.0/hint.min.css', label: 'Hint.css', type: 'css' }, { url: 'https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css', label: 'Tailwind.css', type: 'css' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/2.27.5/css/uikit.min.css', label: 'UIkit 2', type: 'css' }, { url: 'https://getuikit.com/assets/uikit/dist/css/uikit.css', label: 'UIkit 3', type: 'css' }, { url: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css', label: 'Animate.css', type: 'css' }, { url: 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', label: 'FontAwesome 4', type: 'css' }, { url: 'https://use.fontawesome.com/releases/v5.4.1/css/all.css', label: 'FontAwesome 5', type: 'css' }]; // CONCATENATED MODULE: ./components/LibraryAutoSuggest.jsx let LibraryAutoSuggest_LibraryAutoSuggest = class LibraryAutoSuggest extends preact_min["Component"] { componentDidMount() { this.t = this.wrap.querySelector('input,textarea'); this.filter = this.props.filter; this.selectedCallback = this.props.onSelect; // after list is insrted into the DOM, we put it in the body // fixed at same position setTimeout(() => { requestIdleCallback(() => { document.body.appendChild(this.list); this.list.style.position = 'fixed'; }); }, 100); this.t.addEventListener('input', e => this.onInput(e)); this.t.addEventListener('keydown', e => this.onKeyDown(e)); this.t.addEventListener('blur', e => this.closeSuggestions(e)); } componentWillUnmount() { this.t.removeEventListener('input', e => this.onInput(e)); this.t.removeEventListener('keydown', e => this.onKeyDown(e)); this.t.removeEventListener('blur', e => this.closeSuggestions(e)); } get currentLineNumber() { return this.t.value.substr(0, this.t.selectionStart).split('\n').length; } get currentLine() { var line = this.currentLineNumber; return this.t.value.split('\n')[line - 1]; } listMouseDownHandler() {} closeSuggestions() { this.list.classList.remove('is-open'); this.isShowingSuggestions = false; } getList(input) { var url = 'https://api.cdnjs.com/libraries?search='; return fetch(url + input).then(response => { return response.json().then(json => json.results); }); } replaceCurrentLine(val) { var lines = this.t.value.split('\n'); lines.splice(this.currentLineNumber - 1, 1, val); this.t.value = lines.join('\n'); } onInput() { var currentLine = this.currentLine; if (currentLine) { if (currentLine.indexOf('/') !== -1 || currentLine.match(/https*:\/\//)) { return; } clearTimeout(this.timeout); this.timeout = setTimeout(() => { this.loader.style.display = 'block'; this.getList(currentLine).then(arr => { this.loader.style.display = 'none'; if (!arr.length) { this.closeSuggestions(); return; } this.list.innerHTML = ''; if (this.filter) { /* eslint-disable no-param-reassign */ arr = arr.filter(this.filter); } for (var i = 0; i < Math.min(arr.length, 10); i++) { this.list.innerHTML += `