mirror of
https://github.com/chinchang/web-maker.git
synced 2025-10-14 04:54:24 +02:00
@@ -195,6 +195,8 @@ gulp.task('packageExtension', function () {
|
|||||||
child_process.execSync('cp src/options.html extension');
|
child_process.execSync('cp src/options.html extension');
|
||||||
child_process.execSync('cp src/eventPage.js extension');
|
child_process.execSync('cp src/eventPage.js extension');
|
||||||
child_process.execSync('cp src/icon-16.png extension');
|
child_process.execSync('cp src/icon-16.png extension');
|
||||||
|
child_process.execSync('cp offscreen.html extension');
|
||||||
|
child_process.execSync('cp offscreen.js extension');
|
||||||
child_process.execSync('rm -rf extension/service-worker.js');
|
child_process.execSync('rm -rf extension/service-worker.js');
|
||||||
return merge(
|
return merge(
|
||||||
gulp
|
gulp
|
||||||
@@ -292,10 +294,13 @@ const buildExtension = series(
|
|||||||
);
|
);
|
||||||
|
|
||||||
function runWatcher(cb) {
|
function runWatcher(cb) {
|
||||||
return watch(['src/**/*.js', 'src/**/*.jsx'], function (cbb) {
|
return watch(
|
||||||
|
['src/**/*.js', 'src/**/*.jsx', 'src/**/*.json'],
|
||||||
|
function (cbb) {
|
||||||
buildExtension();
|
buildExtension();
|
||||||
cbb();
|
cbb();
|
||||||
});
|
}
|
||||||
|
);
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
offscreen.html
Normal file
2
offscreen.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<script src="./offscreen.js"></script>
|
44
offscreen.js
Normal file
44
offscreen.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// This URL must point to the public site
|
||||||
|
const _URL = 'https://webmaker.app/signup';
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = _URL;
|
||||||
|
document.documentElement.appendChild(iframe);
|
||||||
|
chrome.runtime.onMessage.addListener(handleChromeMessages);
|
||||||
|
|
||||||
|
function handleChromeMessages(message, sender, sendResponse) {
|
||||||
|
// Extensions may have an number of other reasons to send messages, so you
|
||||||
|
// should filter out any that are not meant for the offscreen document.
|
||||||
|
if (message.target !== 'offscreen') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIframeMessage({ data }) {
|
||||||
|
console.log('got postmessage in offscreen doc from iframe');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (data.startsWith('!_{')) {
|
||||||
|
// Other parts of the Firebase library send messages using postMessage.
|
||||||
|
// You don't care about them in this context, so return early.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data = JSON.parse(data);
|
||||||
|
self.removeEventListener('message', handleIframeMessage);
|
||||||
|
|
||||||
|
// being sent back to worker
|
||||||
|
sendResponse(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`json parse failed - ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.addEventListener('message', handleIframeMessage, false);
|
||||||
|
|
||||||
|
// Initialize the authentication flow in the iframed document. You must set the
|
||||||
|
// second argument (targetOrigin) of the message in order for it to be successfully
|
||||||
|
// delivered.
|
||||||
|
iframe.contentWindow.postMessage(
|
||||||
|
{ initAuth: true, providerName: message.providerName },
|
||||||
|
new URL(_URL).origin
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
1697
package-lock.json
generated
1697
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "web-maker",
|
"name": "web-maker",
|
||||||
"version": "6.2.0",
|
"version": "6.3.0",
|
||||||
"description": "A blazing fast & offline web playground",
|
"description": "A blazing fast & offline web playground",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "concurrently --kill-others \"gulp start-preview-server\" \"npm run -s dev\"",
|
"start": "concurrently --kill-others \"gulp start-preview-server\" \"npm run -s dev\"",
|
||||||
@@ -75,8 +75,8 @@
|
|||||||
"code-blast-codemirror": "chinchang/code-blast-codemirror#web-maker",
|
"code-blast-codemirror": "chinchang/code-blast-codemirror#web-maker",
|
||||||
"codemirror": "^5.65.16",
|
"codemirror": "^5.65.16",
|
||||||
"copy-webpack-plugin": "^4.5.1",
|
"copy-webpack-plugin": "^4.5.1",
|
||||||
|
"firebase": "^10.8.0",
|
||||||
"esprima-next": "^6.0.3",
|
"esprima-next": "^6.0.3",
|
||||||
"firebase": "^8.10.0",
|
|
||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
"preact": "^10.17.0",
|
"preact": "^10.17.0",
|
||||||
"preact-portal": "^1.1.3",
|
"preact-portal": "^1.1.3",
|
||||||
|
12
packages/signup/dist/index.html
vendored
12
packages/signup/dist/index.html
vendored
@@ -1 +1,11 @@
|
|||||||
<!doctype html><html><head><title>signInWithPopup</title></head><body> <h1>signInWithPopup</h1> <script type="module" src="/signup/index.1903c1b7.js"></script> </body></html>
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>signInWithPopup</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>signInWithPopup</h1>
|
||||||
|
|
||||||
|
<script src="/index.a3cfa626.js" defer=""></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
87
src/auth.js
87
src/auth.js
@@ -1,35 +1,78 @@
|
|||||||
import { trackEvent } from './analytics';
|
import { trackEvent } from './analytics';
|
||||||
import firebase from 'firebase/app';
|
import { auth } from './firebaseInit';
|
||||||
import { log } from './utils';
|
import { log } from './utils';
|
||||||
|
import {
|
||||||
|
GithubAuthProvider as ExtensionGithubAuthProvider,
|
||||||
|
GoogleAuthProvider as ExtensionGoogleAuthProvider,
|
||||||
|
signOut,
|
||||||
|
signInWithCredential
|
||||||
|
} from 'firebase/auth/web-extension';
|
||||||
|
import {
|
||||||
|
signInWithPopup,
|
||||||
|
GithubAuthProvider,
|
||||||
|
GoogleAuthProvider
|
||||||
|
} from 'firebase/auth';
|
||||||
|
|
||||||
export const auth = {
|
export const authh = {
|
||||||
logout() {
|
logout() {
|
||||||
firebase.auth().signOut();
|
signOut(auth);
|
||||||
},
|
},
|
||||||
login(providerName) {
|
async login(providerName) {
|
||||||
var provider;
|
const onSuccess = () => {
|
||||||
if (providerName === 'facebook') {
|
trackEvent(
|
||||||
provider = new firebase.auth.FacebookAuthProvider();
|
'fn',
|
||||||
} else if (providerName === 'twitter') {
|
'loggedIn',
|
||||||
provider = new firebase.auth.TwitterAuthProvider();
|
providerName,
|
||||||
} else if (providerName === 'google') {
|
window.IS_EXTENSION ? 'extension' : 'web'
|
||||||
provider = new firebase.auth.GoogleAuthProvider();
|
);
|
||||||
provider.addScope('https://www.googleapis.com/auth/userinfo.profile');
|
|
||||||
} else {
|
|
||||||
provider = new firebase.auth.GithubAuthProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
return firebase
|
|
||||||
.auth()
|
|
||||||
.signInWithPopup(provider)
|
|
||||||
.then(function() {
|
|
||||||
trackEvent('fn', 'loggedIn', providerName);
|
|
||||||
// Save to recommend next time
|
// Save to recommend next time
|
||||||
window.db.local.set({
|
window.db.local.set({
|
||||||
lastAuthProvider: providerName
|
lastAuthProvider: providerName
|
||||||
});
|
});
|
||||||
})
|
};
|
||||||
.catch(function(error) {
|
|
||||||
|
if (window.IS_EXTENSION) {
|
||||||
|
const result = await chrome.runtime.sendMessage({
|
||||||
|
type: 'firebase-auth',
|
||||||
|
providerName
|
||||||
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
result.name === 'FirebaseError' &&
|
||||||
|
result.code === 'auth/account-exists-with-different-credential'
|
||||||
|
) {
|
||||||
|
alert(
|
||||||
|
'You have already signed up with the same email using different social login'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let credential;
|
||||||
|
switch (providerName) {
|
||||||
|
case 'google':
|
||||||
|
credential = ExtensionGoogleAuthProvider.credentialFromResult(result);
|
||||||
|
break;
|
||||||
|
case 'github':
|
||||||
|
credential = ExtensionGithubAuthProvider.credentialFromResult(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// authenticationObject is of the type UserCredentialImpl. Use it to authenticate here
|
||||||
|
return signInWithCredential(auth, credential).then(onSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider;
|
||||||
|
if (providerName === 'google') {
|
||||||
|
provider = new GoogleAuthProvider();
|
||||||
|
provider.addScope('https://www.googleapis.com/auth/userinfo.profile');
|
||||||
|
} else {
|
||||||
|
provider = new GithubAuthProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
return signInWithPopup(auth, provider)
|
||||||
|
.then(onSuccess)
|
||||||
|
.catch(function (error) {
|
||||||
log(error);
|
log(error);
|
||||||
if (error.code === 'auth/account-exists-with-different-credential') {
|
if (error.code === 'auth/account-exists-with-different-credential') {
|
||||||
alert(
|
alert(
|
||||||
|
@@ -134,7 +134,8 @@ export default class AddLibrary extends Component {
|
|||||||
https://cdnjs.cloudflare.com, https://unpkg.com,
|
https://cdnjs.cloudflare.com, https://unpkg.com,
|
||||||
https://maxcdn.com, https://cdn77.com,
|
https://maxcdn.com, https://cdn77.com,
|
||||||
https://maxcdn.bootstrapcdn.com, https://cdn.jsdelivr.net/,
|
https://maxcdn.bootstrapcdn.com, https://cdn.jsdelivr.net/,
|
||||||
https://rawgit.com, https://wzrd.in, https://cdn.tailwindcss.com
|
https://rawgit.com, https://wzrd.in, https://cdn.tailwindcss.com,
|
||||||
|
https://assets.webmaker.app
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import firebase from 'firebase/app';
|
import {
|
||||||
import 'firebase/storage';
|
deleteObject,
|
||||||
|
uploadBytesResumable,
|
||||||
|
ref,
|
||||||
|
listAll,
|
||||||
|
getDownloadURL
|
||||||
|
} from 'firebase/storage';
|
||||||
|
import { storage } from '../firebaseInit';
|
||||||
import { HStack, Stack, VStack } from './Stack';
|
import { HStack, Stack, VStack } from './Stack';
|
||||||
import { copyToClipboard } from '../utils';
|
import { copyToClipboard } from '../utils';
|
||||||
import { Trans } from '@lingui/macro';
|
import { Trans } from '@lingui/macro';
|
||||||
@@ -17,6 +23,7 @@ function getFileType(url) {
|
|||||||
}
|
}
|
||||||
return ext;
|
return ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
||||||
const [files, setFiles] = useState([]);
|
const [files, setFiles] = useState([]);
|
||||||
const [isFetchingFiles, setIsFetchingFiles] = useState(false);
|
const [isFetchingFiles, setIsFetchingFiles] = useState(false);
|
||||||
@@ -26,8 +33,6 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
const [uploadProgress, setUploadProgress] = useState();
|
const [uploadProgress, setUploadProgress] = useState();
|
||||||
const [listType, setListType] = useState('grid');
|
const [listType, setListType] = useState('grid');
|
||||||
|
|
||||||
const storageRef = firebase.storage().ref(`assets/${window.user?.uid}`);
|
|
||||||
|
|
||||||
const uploadFile = file => {
|
const uploadFile = file => {
|
||||||
if (file.size > 1024 * 1024) {
|
if (file.size > 1024 * 1024) {
|
||||||
// 1MB limit
|
// 1MB limit
|
||||||
@@ -39,9 +44,11 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
const metadata = {
|
const metadata = {
|
||||||
cacheControl: 'public, max-age=3600' // 1 hr
|
cacheControl: 'public, max-age=3600' // 1 hr
|
||||||
};
|
};
|
||||||
|
const task = uploadBytesResumable(
|
||||||
const fileRef = storageRef.child(file.name);
|
ref(storage, `assets/${window.user?.uid}/${file.name}`),
|
||||||
const task = fileRef.put(file, metadata);
|
file,
|
||||||
|
metadata
|
||||||
|
);
|
||||||
|
|
||||||
task.on(
|
task.on(
|
||||||
'state_changed',
|
'state_changed',
|
||||||
@@ -49,12 +56,12 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
// Observe state change events such as progress, pause, and resume
|
// Observe state change events such as progress, pause, and resume
|
||||||
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
|
// Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
|
||||||
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
|
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
|
||||||
console.log('Upload is ' + progress + '% done');
|
// console.log('Upload is ' + progress + '% done');
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
// Handle unsuccessful uploads
|
// Handle unsuccessful uploads
|
||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
console.error('File upload error:', error);
|
// console.log('File upload error:', error);
|
||||||
alertsService.add('⚠️ File upload failed');
|
alertsService.add('⚠️ File upload failed');
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
@@ -78,11 +85,11 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
// Function to fetch existing files
|
// Function to fetch existing files
|
||||||
const fetchFiles = () => {
|
const fetchFiles = () => {
|
||||||
setIsFetchingFiles(true);
|
setIsFetchingFiles(true);
|
||||||
storageRef
|
|
||||||
.listAll()
|
listAll(ref(storage, `assets/${window.user?.uid}`))
|
||||||
.then(result => {
|
.then(result => {
|
||||||
const filePromises = result.items.map(item => {
|
const filePromises = result.items.map(item => {
|
||||||
return item.getDownloadURL().then(url => {
|
return getDownloadURL(item).then(url => {
|
||||||
return { name: item.name, url };
|
return { name: item.name, url };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -190,9 +197,8 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
const file = files[index];
|
const file = files[index];
|
||||||
const answer = confirm(`Are you sure you want to delete "${file.name}"?`);
|
const answer = confirm(`Are you sure you want to delete "${file.name}"?`);
|
||||||
if (!answer) return;
|
if (!answer) return;
|
||||||
const fileRef = storageRef.child(file.name);
|
const fileRef = ref(storage, file.url);
|
||||||
fileRef
|
deleteObject(fileRef)
|
||||||
.delete()
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
alertsService.add('File deleted successfully');
|
alertsService.add('File deleted successfully');
|
||||||
setFiles(files.filter((_, i) => i !== index));
|
setFiles(files.filter((_, i) => i !== index));
|
||||||
@@ -259,6 +265,15 @@ const Assets = ({ onProBtnClick, onLoginBtnClick }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isFetchingFiles && <LoaderWithText>Fetching files...</LoaderWithText>}
|
{isFetchingFiles && <LoaderWithText>Fetching files...</LoaderWithText>}
|
||||||
|
|
||||||
|
{!isFetchingFiles && !files.length ? (
|
||||||
|
<Stack justify="center">
|
||||||
|
<Text align="center" appearance="secondary">
|
||||||
|
No files uploaded yet
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<VStack align="stretch" gap={1}>
|
<VStack align="stretch" gap={1}>
|
||||||
{files.length ? (
|
{files.length ? (
|
||||||
<Stack gap={1}>
|
<Stack gap={1}>
|
||||||
|
@@ -106,6 +106,19 @@ export function Changelog(props) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Whats new?</h1>
|
<h1>Whats new?</h1>
|
||||||
|
|
||||||
|
<Notification version="6.3.0" {...props} isLatest={true}>
|
||||||
|
<NotificationItem type="bug">
|
||||||
|
Extension Only: JavaScript is NOW WORKING, again! 🎉 The extension is
|
||||||
|
now migrated to MV3 which means its much more secure, and of course,
|
||||||
|
JavaScript now works again! 🥳
|
||||||
|
</NotificationItem>
|
||||||
|
<NotificationItem type="ui">
|
||||||
|
Tailwind CSS 2 template has been removed since Extension now supports
|
||||||
|
the lateat Tailwind CSS 3 template.
|
||||||
|
</NotificationItem>
|
||||||
|
</Notification>
|
||||||
|
|
||||||
<Notification version="6.2.0" {...props} isLatest={true}>
|
<Notification version="6.2.0" {...props} isLatest={true}>
|
||||||
<li>Preact template updated to latest version with hooks.</li>
|
<li>Preact template updated to latest version with hooks.</li>
|
||||||
<li>Mail option added in help modal.</li>
|
<li>Mail option added in help modal.</li>
|
||||||
|
@@ -38,7 +38,7 @@ export default class ContentWrap extends Component {
|
|||||||
window.localStorage.getItem(LocalStorageKeys.WAS_CONSOLE_OPEN) ===
|
window.localStorage.getItem(LocalStorageKeys.WAS_CONSOLE_OPEN) ===
|
||||||
'true',
|
'true',
|
||||||
isCssSettingsModalOpen: false,
|
isCssSettingsModalOpen: false,
|
||||||
isPreviewNotWorkingModalVisible: false,
|
|
||||||
logs: []
|
logs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,15 +63,11 @@ export default class ContentWrap extends Component {
|
|||||||
this.clearConsoleBtnClickHandler.bind(this);
|
this.clearConsoleBtnClickHandler.bind(this);
|
||||||
this.toggleConsole = this.toggleConsole.bind(this);
|
this.toggleConsole = this.toggleConsole.bind(this);
|
||||||
this.evalConsoleExpr = this.evalConsoleExpr.bind(this);
|
this.evalConsoleExpr = this.evalConsoleExpr.bind(this);
|
||||||
this.dismissPreviewNotWorkingModal =
|
|
||||||
this.dismissPreviewNotWorkingModal.bind(this);
|
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
return (
|
return (
|
||||||
this.state.isConsoleOpen !== nextState.isConsoleOpen ||
|
this.state.isConsoleOpen !== nextState.isConsoleOpen ||
|
||||||
this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen ||
|
this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen ||
|
||||||
this.state.isPreviewNotWorkingModalVisible !==
|
|
||||||
nextState.isPreviewNotWorkingModalVisible ||
|
|
||||||
this.state.logs !== nextState.logs ||
|
this.state.logs !== nextState.logs ||
|
||||||
this.state.codeSplitSizes !== nextState.codeSplitSizes ||
|
this.state.codeSplitSizes !== nextState.codeSplitSizes ||
|
||||||
this.state.mainSplitSizes !== nextState.mainSplitSizes ||
|
this.state.mainSplitSizes !== nextState.mainSplitSizes ||
|
||||||
@@ -145,10 +141,7 @@ export default class ContentWrap extends Component {
|
|||||||
createPreviewFile(html, css, js) {
|
createPreviewFile(html, css, js) {
|
||||||
const versionMatch = navigator.userAgent.match(/Chrome\/(\d+)/);
|
const versionMatch = navigator.userAgent.match(/Chrome\/(\d+)/);
|
||||||
|
|
||||||
const shouldInlineJs =
|
const shouldInlineJs = true;
|
||||||
!window.webkitRequestFileSystem ||
|
|
||||||
!window.IS_EXTENSION ||
|
|
||||||
(versionMatch && +versionMatch[1] >= 104);
|
|
||||||
var contents = getCompleteHtml(
|
var contents = getCompleteHtml(
|
||||||
html,
|
html,
|
||||||
css,
|
css,
|
||||||
@@ -164,7 +157,6 @@ export default class ContentWrap extends Component {
|
|||||||
trackEvent.hasTrackedCode = true;
|
trackEvent.hasTrackedCode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldInlineJs) {
|
|
||||||
if (this.detachedWindow) {
|
if (this.detachedWindow) {
|
||||||
log('✉️ Sending message to detached window');
|
log('✉️ Sending message to detached window');
|
||||||
this.detachedWindow.postMessage({ contents }, '*');
|
this.detachedWindow.postMessage({ contents }, '*');
|
||||||
@@ -192,12 +184,8 @@ export default class ContentWrap extends Component {
|
|||||||
log('resolved with ', resolutionReason);
|
log('resolved with ', resolutionReason);
|
||||||
fn();
|
fn();
|
||||||
});
|
});
|
||||||
// Setting to blank string cause frame to reload
|
|
||||||
if (window.IS_EXTENSION) {
|
|
||||||
this.frame.src = '';
|
|
||||||
} else {
|
|
||||||
this.frame.src = this.frame.src;
|
this.frame.src = this.frame.src;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const writeInsideIframe = () => {
|
const writeInsideIframe = () => {
|
||||||
if (!cachedSandboxAttribute && window.DEBUG) {
|
if (!cachedSandboxAttribute && window.DEBUG) {
|
||||||
@@ -205,13 +193,7 @@ export default class ContentWrap extends Component {
|
|||||||
}
|
}
|
||||||
log('sending PM');
|
log('sending PM');
|
||||||
|
|
||||||
if (window.IS_EXTENSION) {
|
|
||||||
this.frame.contentDocument.open();
|
|
||||||
this.frame.contentDocument.write(contents);
|
|
||||||
this.frame.contentDocument.close();
|
|
||||||
} else {
|
|
||||||
this.frame.contentWindow.postMessage({ contents }, '*');
|
this.frame.contentWindow.postMessage({ contents }, '*');
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// refreshAndDo(() => {
|
// refreshAndDo(() => {
|
||||||
// cachedSandboxAttribute = this.frame.getAttribute('sandbox');
|
// cachedSandboxAttribute = this.frame.getAttribute('sandbox');
|
||||||
@@ -222,23 +204,6 @@ export default class ContentWrap extends Component {
|
|||||||
// });
|
// });
|
||||||
refreshAndDo(writeInsideIframe);
|
refreshAndDo(writeInsideIframe);
|
||||||
}
|
}
|
||||||
} 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({ url: src }, '*');
|
|
||||||
} else {
|
|
||||||
this.frame.src = src;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cleanupErrors(lang) {
|
cleanupErrors(lang) {
|
||||||
this.cm[lang].clearGutter('error-gutter');
|
this.cm[lang].clearGutter('error-gutter');
|
||||||
@@ -277,14 +242,13 @@ export default class ContentWrap extends Component {
|
|||||||
js: this.cmCodes.js
|
js: this.cmCodes.js
|
||||||
};
|
};
|
||||||
log('🔎 setPreviewContent', isForced);
|
log('🔎 setPreviewContent', isForced);
|
||||||
const targetFrame = this.detachedWindow
|
const targetFrame = this.detachedWindow ? this.detachedWindow : this.frame;
|
||||||
? this.detachedWindow //this.detachedWindow.document.querySelector('iframe')
|
|
||||||
: this.frame;
|
|
||||||
|
|
||||||
const cssMode = this.props.currentItem.cssMode;
|
const cssMode = this.props.currentItem.cssMode;
|
||||||
// If just CSS was changed (and everything shudn't be empty),
|
// If just CSS was changed (and everything shudn't be empty),
|
||||||
// change the styles inside the iframe.
|
// change the styles inside the iframe.
|
||||||
if (
|
if (
|
||||||
|
false &&
|
||||||
!isForced &&
|
!isForced &&
|
||||||
currentCode.html === this.codeInPreview.html &&
|
currentCode.html === this.codeInPreview.html &&
|
||||||
currentCode.js === this.codeInPreview.js &&
|
currentCode.js === this.codeInPreview.js &&
|
||||||
@@ -335,19 +299,6 @@ export default class ContentWrap extends Component {
|
|||||||
this.showErrors(resultItem.errors.lang, resultItem.errors.data);
|
this.showErrors(resultItem.errors.lang, resultItem.errors.data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const versionMatch = navigator.userAgent.match(/Chrome\/(\d+)/);
|
|
||||||
if (
|
|
||||||
result[2].code &&
|
|
||||||
versionMatch &&
|
|
||||||
+versionMatch[1] >= 104 &&
|
|
||||||
window.IS_EXTENSION &&
|
|
||||||
!window.sessionStorage.getItem('previewErrorMessageDismissed')
|
|
||||||
) {
|
|
||||||
this.setState({
|
|
||||||
isPreviewNotWorkingModalVisible: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,13 +638,6 @@ export default class ContentWrap extends Component {
|
|||||||
this.props.onPrettifyBtnClick(codeType);
|
this.props.onPrettifyBtnClick(codeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissPreviewNotWorkingModal() {
|
|
||||||
this.setState({
|
|
||||||
isPreviewNotWorkingModalVisible: false
|
|
||||||
});
|
|
||||||
window.sessionStorage.setItem('previewErrorMessageDismissed', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// log('contentwrap update');
|
// log('contentwrap update');
|
||||||
|
|
||||||
@@ -960,7 +904,7 @@ export default class ContentWrap extends Component {
|
|||||||
ref={el => (this.frame = el)}
|
ref={el => (this.frame = el)}
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
id="demo-frame"
|
id="demo-frame"
|
||||||
allowpaymentrequest="true"
|
src="./indexpm.html"
|
||||||
allowfullscreen="true"
|
allowfullscreen="true"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -996,34 +940,6 @@ export default class ContentWrap extends Component {
|
|||||||
settings={this.props.currentItem.cssSettings}
|
settings={this.props.currentItem.cssSettings}
|
||||||
editorTheme={this.props.prefs.editorTheme}
|
editorTheme={this.props.prefs.editorTheme}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
|
||||||
show={this.state.isPreviewNotWorkingModalVisible}
|
|
||||||
closeHandler={this.dismissPreviewNotWorkingModal}
|
|
||||||
>
|
|
||||||
<h1>🔴 JavaScript preview not working!</h1>
|
|
||||||
<p>
|
|
||||||
Latest version of Chrome has changed a few things because of which
|
|
||||||
JavaScript preview has stopped working.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
If you want to work with just HTML & CSS, you can still continue
|
|
||||||
here. Otherwise, it is recommended to switch to the Web Maker web
|
|
||||||
app which is much more powerful and works offline too -{' '}
|
|
||||||
<a href="https://webmaker.app/app" target="_blank">
|
|
||||||
Go to web app
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<div class="flex flex-h-end">
|
|
||||||
<button
|
|
||||||
class="btn btn--primary"
|
|
||||||
onClick={this.dismissPreviewNotWorkingModal}
|
|
||||||
>
|
|
||||||
Dismiss
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
</SplitPane>
|
</SplitPane>
|
||||||
);
|
);
|
||||||
|
@@ -257,7 +257,7 @@ export default class ContentWrapFiles extends Component {
|
|||||||
obj[file.path] =
|
obj[file.path] =
|
||||||
'<script src="' +
|
'<script src="' +
|
||||||
(chrome.extension
|
(chrome.extension
|
||||||
? chrome.extension.getURL('/lib/screenlog.js')
|
? chrome.runtime.getURL('lib/screenlog.js')
|
||||||
: `${location.origin}${
|
: `${location.origin}${
|
||||||
window.DEBUG ? '' : BASE_PATH
|
window.DEBUG ? '' : BASE_PATH
|
||||||
}/lib/screenlog.js`) +
|
}/lib/screenlog.js`) +
|
||||||
|
@@ -1,12 +1,12 @@
|
|||||||
import { h, Component } from 'preact';
|
import { h, Component } from 'preact';
|
||||||
import { trackEvent } from '../analytics';
|
import { trackEvent } from '../analytics';
|
||||||
import { auth } from '../auth';
|
import { authh } from '../auth';
|
||||||
|
|
||||||
export default class Login extends Component {
|
export default class Login extends Component {
|
||||||
login(e) {
|
login(e) {
|
||||||
const provider = e.target.dataset.authProvider;
|
const provider = e.target.dataset.authProvider;
|
||||||
trackEvent('ui', 'loginProviderClick', provider);
|
trackEvent('ui', 'loginProviderClick', provider);
|
||||||
auth.login(provider);
|
authh.login(provider);
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.db.local.get(
|
window.db.local.get(
|
||||||
|
@@ -9,7 +9,9 @@ import { Icon } from './Icons';
|
|||||||
import { Text } from './Text';
|
import { Text } from './Text';
|
||||||
|
|
||||||
const FREE_PUBLIC_ITEM_COUNT = 1;
|
const FREE_PUBLIC_ITEM_COUNT = 1;
|
||||||
const BASE_URL = location.origin;
|
const BASE_URL = location.origin.includes('chrome-extension://')
|
||||||
|
? 'webmaker.app'
|
||||||
|
: location.origin;
|
||||||
const TOGGLE_VISIBILITY_API =
|
const TOGGLE_VISIBILITY_API =
|
||||||
/*!window.location.origin.includes('localhost')
|
/*!window.location.origin.includes('localhost')
|
||||||
? 'http://127.0.0.1:5001/web-maker-app/us-central1/toggleVisibility'
|
? 'http://127.0.0.1:5001/web-maker-app/us-central1/toggleVisibility'
|
||||||
|
@@ -43,10 +43,10 @@ import { modes, HtmlModes, CssModes, JsModes } from '../codeModes';
|
|||||||
import { trackEvent } from '../analytics';
|
import { trackEvent } from '../analytics';
|
||||||
import { deferred } from '../deferred';
|
import { deferred } from '../deferred';
|
||||||
import { alertsService } from '../notifications';
|
import { alertsService } from '../notifications';
|
||||||
import firebase from 'firebase/app';
|
import { auth } from '../firebaseInit';
|
||||||
import 'firebase/auth';
|
import { onAuthStateChanged } from 'firebase/auth';
|
||||||
import { Profile } from './Profile';
|
import { Profile } from './Profile';
|
||||||
import { auth } from '../auth';
|
import { authh } from '../auth';
|
||||||
import { SupportDeveloperModal } from './SupportDeveloperModal';
|
import { SupportDeveloperModal } from './SupportDeveloperModal';
|
||||||
import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
|
import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
|
||||||
import { takeScreenshot } from '../takeScreenshot';
|
import { takeScreenshot } from '../takeScreenshot';
|
||||||
@@ -84,7 +84,7 @@ if (module.hot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const UNSAVED_WARNING_COUNT = 15;
|
const UNSAVED_WARNING_COUNT = 15;
|
||||||
const version = '6.2.0';
|
const version = '6.3.0';
|
||||||
|
|
||||||
// Read forced settings as query parameters
|
// Read forced settings as query parameters
|
||||||
window.forcedSettings = {};
|
window.forcedSettings = {};
|
||||||
@@ -197,7 +197,7 @@ export default class App extends Component {
|
|||||||
window.user = savedUser;
|
window.user = savedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
firebase.auth().onAuthStateChanged(authUser => {
|
onAuthStateChanged(auth, authUser => {
|
||||||
this.setState({ isLoginModalOpen: false });
|
this.setState({ isLoginModalOpen: false });
|
||||||
if (authUser) {
|
if (authUser) {
|
||||||
log('You are -> ', authUser);
|
log('You are -> ', authUser);
|
||||||
@@ -220,7 +220,6 @@ export default class App extends Component {
|
|||||||
this.setState({ user: newUser });
|
this.setState({ user: newUser });
|
||||||
window.user = newUser;
|
window.user = newUser;
|
||||||
// window.localStorage.setItem('user', authUser);
|
// window.localStorage.setItem('user', authUser);
|
||||||
trackEvent('fn', 'loggedIn', window.IS_EXTENSION ? 'extension' : 'web');
|
|
||||||
|
|
||||||
if (!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS]) {
|
if (!window.localStorage[LocalStorageKeys.ASKED_TO_IMPORT_CREATIONS]) {
|
||||||
this.fetchItems(false, true).then(items => {
|
this.fetchItems(false, true).then(items => {
|
||||||
@@ -641,7 +640,6 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
console.log('itemId', this.props.itemId);
|
|
||||||
function setBodySize() {
|
function setBodySize() {
|
||||||
document.body.style.height = `${window.innerHeight}px`;
|
document.body.style.height = `${window.innerHeight}px`;
|
||||||
}
|
}
|
||||||
@@ -1081,18 +1079,15 @@ export default class App extends Component {
|
|||||||
alertsService.add('Setting saved');
|
alertsService.add('Setting saved');
|
||||||
});
|
});
|
||||||
if (window.user) {
|
if (window.user) {
|
||||||
window.db.getDb().then(remoteDb => {
|
db.updateUserSetting(
|
||||||
remoteDb
|
window.user.uid,
|
||||||
.collection('users')
|
settingName,
|
||||||
.doc(window.user.uid)
|
this.state.prefs[settingName]
|
||||||
.update({
|
)
|
||||||
[`settings.${settingName}`]: this.state.prefs[settingName]
|
|
||||||
})
|
|
||||||
.then(arg => {
|
.then(arg => {
|
||||||
log(`Setting "${settingName}" for user`, arg);
|
log(`Setting "${settingName}" saved`, arg);
|
||||||
})
|
})
|
||||||
.catch(error => log(error));
|
.catch(error => log(error));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
trackEvent('ui', 'updatePref-' + settingName, prefs[settingName]);
|
trackEvent('ui', 'updatePref-' + settingName, prefs[settingName]);
|
||||||
}
|
}
|
||||||
@@ -1140,7 +1135,7 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
trackEvent('fn', 'loggedOut');
|
trackEvent('fn', 'loggedOut');
|
||||||
auth.logout();
|
authh.logout();
|
||||||
this.setState({ isProfileModalOpen: false });
|
this.setState({ isProfileModalOpen: false });
|
||||||
this.createNewItem();
|
this.createNewItem();
|
||||||
alertsService.add('Log out successfull');
|
alertsService.add('Log out successfull');
|
||||||
@@ -1943,7 +1938,6 @@ export default class App extends Component {
|
|||||||
this.loginBtnClickHandler();
|
this.loginBtnClickHandler();
|
||||||
}}
|
}}
|
||||||
onBuyFromExtensionClick={() => {
|
onBuyFromExtensionClick={() => {
|
||||||
console.log('open modal');
|
|
||||||
this.closeAllOverlays();
|
this.closeAllOverlays();
|
||||||
this.setState({ isProOnAppModalOpen: true });
|
this.setState({ isProOnAppModalOpen: true });
|
||||||
}}
|
}}
|
||||||
|
121
src/db.js
121
src/db.js
@@ -1,6 +1,17 @@
|
|||||||
import './firebaseInit';
|
// import './firebaseInit';
|
||||||
import firebase from 'firebase/app';
|
|
||||||
import 'firebase/firestore';
|
import 'firebase/firestore';
|
||||||
|
import { db } from './firebaseInit';
|
||||||
|
import {
|
||||||
|
getDoc,
|
||||||
|
getDocs,
|
||||||
|
doc,
|
||||||
|
updateDoc,
|
||||||
|
setDoc,
|
||||||
|
where,
|
||||||
|
collection,
|
||||||
|
getCountFromServer,
|
||||||
|
query
|
||||||
|
} from 'firebase/firestore';
|
||||||
import { deferred } from './deferred';
|
import { deferred } from './deferred';
|
||||||
import { trackEvent } from './analytics';
|
import { trackEvent } from './analytics';
|
||||||
import { log } from './utils';
|
import { log } from './utils';
|
||||||
@@ -26,9 +37,6 @@ function getArrayFromQuerySnapshot(querySnapshot) {
|
|||||||
(() => {
|
(() => {
|
||||||
const FAUX_DELAY = 1;
|
const FAUX_DELAY = 1;
|
||||||
|
|
||||||
var db;
|
|
||||||
var dbPromise;
|
|
||||||
|
|
||||||
var local = {
|
var local = {
|
||||||
get: (obj, cb) => {
|
get: (obj, cb) => {
|
||||||
const retVal = {};
|
const retVal = {};
|
||||||
@@ -64,46 +72,9 @@ function getArrayFromQuerySnapshot(querySnapshot) {
|
|||||||
const dbLocalAlias = chrome && chrome.storage ? chrome.storage.local : local;
|
const dbLocalAlias = chrome && chrome.storage ? chrome.storage.local : local;
|
||||||
const dbSyncAlias = chrome && chrome.storage ? chrome.storage.sync : local;
|
const dbSyncAlias = chrome && chrome.storage ? chrome.storage.sync : local;
|
||||||
|
|
||||||
async function getDb() {
|
function getDb() {
|
||||||
if (dbPromise) {
|
|
||||||
return dbPromise;
|
|
||||||
}
|
|
||||||
log('Initializing firestore');
|
log('Initializing firestore');
|
||||||
dbPromise = new Promise((resolve, reject) => {
|
return db;
|
||||||
if (db) {
|
|
||||||
return resolve(db);
|
|
||||||
}
|
|
||||||
const firestoreInstance = firebase.firestore();
|
|
||||||
|
|
||||||
return firestoreInstance
|
|
||||||
.enablePersistence({ experimentalTabSynchronization: true })
|
|
||||||
.then(function () {
|
|
||||||
// Initialize Cloud Firestore through firebase
|
|
||||||
db = firebase.firestore();
|
|
||||||
// const settings = {
|
|
||||||
// timestampsInSnapshots: true
|
|
||||||
// };
|
|
||||||
// db.settings(settings);
|
|
||||||
log('firebase db ready', db);
|
|
||||||
resolve(db);
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
reject(err.code);
|
|
||||||
if (err.code === 'failed-precondition') {
|
|
||||||
// Multiple tabs open, persistence can only be enabled
|
|
||||||
// in one tab at a a time.
|
|
||||||
alert(
|
|
||||||
"Opening Web Maker web app in multiple tabs isn't supported at present and it seems like you already have it opened in another tab. Please use in one tab."
|
|
||||||
);
|
|
||||||
trackEvent('fn', 'multiTabError');
|
|
||||||
} else if (err.code === 'unimplemented') {
|
|
||||||
// The current browser does not support all of the
|
|
||||||
// features required to enable persistence
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return dbPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserLastSeenVersion() {
|
async function getUserLastSeenVersion() {
|
||||||
@@ -134,40 +105,27 @@ function getArrayFromQuerySnapshot(querySnapshot) {
|
|||||||
function () {}
|
function () {}
|
||||||
);
|
);
|
||||||
if (window.user) {
|
if (window.user) {
|
||||||
const remoteDb = await getDb();
|
updateDoc(doc(db, `users/${window.user.uid}`), {
|
||||||
remoteDb.doc(`users/${window.user.uid}`).update({
|
|
||||||
lastSeenVersion: version
|
lastSeenVersion: version
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUser(userId) {
|
async function getUser(userId) {
|
||||||
const remoteDb = await getDb();
|
return getDoc(doc(db, `users/${userId}`)).then(doc => {
|
||||||
return remoteDb
|
if (!doc.exists()) {
|
||||||
.doc(`users/${userId}`)
|
// return setDoc(doc(db, `users/${userId}`), {}, { merge: true });
|
||||||
.get()
|
|
||||||
.then(doc => {
|
|
||||||
if (!doc.exists) {
|
|
||||||
// return remoteDb.doc(`users/${userId}`).set(
|
|
||||||
// {},
|
|
||||||
// {
|
|
||||||
// merge: true
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const user = doc.data();
|
|
||||||
|
|
||||||
|
const user = doc.data();
|
||||||
|
// Object.assign(window.user, user);
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchItem(itemId) {
|
async function fetchItem(itemId) {
|
||||||
const remoteDb = await getDb();
|
getDoc(doc(db, `items/${itemId}`)).then(doc => {
|
||||||
return remoteDb
|
|
||||||
.doc(`items/${itemId}`)
|
|
||||||
.get()
|
|
||||||
.then(doc => {
|
|
||||||
if (!doc.exists) return {};
|
if (!doc.exists) return {};
|
||||||
const data = doc.data();
|
const data = doc.data();
|
||||||
return data;
|
return data;
|
||||||
@@ -188,24 +146,28 @@ function getArrayFromQuerySnapshot(querySnapshot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getPublicItemCount(userId) {
|
async function getPublicItemCount(userId) {
|
||||||
const remoteDb = await getDb();
|
const q = query(
|
||||||
return remoteDb
|
collection(db, 'items'),
|
||||||
.collection('items')
|
where('createdBy', '==', userId),
|
||||||
.where('createdBy', '==', userId)
|
where('isPublic', '==', true)
|
||||||
.where('isPublic', '==', true)
|
);
|
||||||
.get()
|
const snapshot = await getCountFromServer(q);
|
||||||
.then(snapShot => {
|
return snapshot.data().count;
|
||||||
return snapShot.size;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserSubscriptionEvents(userId) {
|
async function getUserSubscriptionEvents(userId) {
|
||||||
const remoteDb = await getDb();
|
const q = query(
|
||||||
return remoteDb
|
collection(db, 'subscriptions'),
|
||||||
.collection('subscriptions')
|
where('userId', '==', userId)
|
||||||
.where('userId', '==', userId)
|
);
|
||||||
.get()
|
|
||||||
.then(getArrayFromQuerySnapshot);
|
return getDocs(q).then(getArrayFromQuerySnapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateUserSetting(userId, settingName, settingValue) {
|
||||||
|
return updateDoc(doc(db, `users/${userId}`), {
|
||||||
|
[`settings.${settingName}`]: settingValue
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.db = {
|
window.db = {
|
||||||
@@ -217,6 +179,7 @@ function getArrayFromQuerySnapshot(querySnapshot) {
|
|||||||
fetchItem,
|
fetchItem,
|
||||||
getPublicItemCount,
|
getPublicItemCount,
|
||||||
getUserSubscriptionEvents,
|
getUserSubscriptionEvents,
|
||||||
|
updateUserSetting,
|
||||||
local: dbLocalAlias,
|
local: dbLocalAlias,
|
||||||
sync: dbSyncAlias
|
sync: dbSyncAlias
|
||||||
};
|
};
|
||||||
|
@@ -4,9 +4,7 @@ window.addEventListener('message', e => {
|
|||||||
const frame = document.querySelector('iframe');
|
const frame = document.querySelector('iframe');
|
||||||
frame.src = frame.src;
|
frame.src = frame.src;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
frame.contentDocument.open();
|
frame.contentWindow.postMessage(e.data, '*');
|
||||||
frame.contentDocument.write(e.data.contents);
|
|
||||||
frame.contentDocument.close();
|
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
if (e.data && e.data.url && e.data.url.match(/index\.html/)) {
|
if (e.data && e.data.url && e.data.url.match(/index\.html/)) {
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
function openApp() {
|
function openApp() {
|
||||||
chrome.tabs.create({
|
chrome.tabs.create({
|
||||||
url: chrome.extension.getURL('index.html'),
|
url: chrome.runtime.getURL('index.html'),
|
||||||
selected: true
|
selected: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.browserAction.onClicked.addListener(function() {
|
chrome.action.onClicked.addListener(function () {
|
||||||
openApp();
|
openApp();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for tabs getting created.
|
// Listen for tabs getting created.
|
||||||
chrome.tabs.onCreated.addListener(function(tab) {
|
chrome.tabs.onCreated.addListener(function (tab) {
|
||||||
// If a new tab is opened (without any URL), check user's
|
// If a new tab is opened (without any URL), check user's
|
||||||
// replace Tab setting and act accordingly. Default is false.
|
// replace Tab setting and act accordingly. Default is false.
|
||||||
if (tab.url === 'chrome://newtab/') {
|
if (tab.url === 'chrome://newtab/') {
|
||||||
@@ -18,12 +18,12 @@ chrome.tabs.onCreated.addListener(function(tab) {
|
|||||||
{
|
{
|
||||||
replaceNewTab: false
|
replaceNewTab: false
|
||||||
},
|
},
|
||||||
function(items) {
|
function (items) {
|
||||||
if (items.replaceNewTab) {
|
if (items.replaceNewTab) {
|
||||||
chrome.tabs.update(
|
chrome.tabs.update(
|
||||||
tab.id,
|
tab.id,
|
||||||
{
|
{
|
||||||
url: chrome.extension.getURL('index.html')
|
url: chrome.runtime.getURL('index.html')
|
||||||
},
|
},
|
||||||
function callback() {
|
function callback() {
|
||||||
console.log('ho gaya');
|
console.log('ho gaya');
|
||||||
@@ -45,3 +45,78 @@ chrome.runtime.onInstalled.addListener(function callback(details) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const OFFSCREEN_DOCUMENT_PATH = '/offscreen.html';
|
||||||
|
|
||||||
|
// Chrome only allows for a single offscreenDocument. This is a helper function
|
||||||
|
// that returns a boolean indicating if a document is already active.
|
||||||
|
async function hasDocument() {
|
||||||
|
// Check all windows controlled by the service worker to see if one
|
||||||
|
// of them is the offscreen document with the given path
|
||||||
|
const matchedClients = await clients.matchAll();
|
||||||
|
return matchedClients.some(
|
||||||
|
c => c.url === chrome.runtime.getURL(OFFSCREEN_DOCUMENT_PATH)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupOffscreenDocument(path) {
|
||||||
|
// If we do not have a document, we are already setup and can skip
|
||||||
|
if (await chrome.offscreen.hasDocument()) return;
|
||||||
|
await chrome.offscreen.createDocument({
|
||||||
|
url: path,
|
||||||
|
reasons: [chrome.offscreen.Reason.DOM_SCRAPING],
|
||||||
|
justification: 'authentication'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function closeOffscreenDocument() {
|
||||||
|
if (!(await hasDocument())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await chrome.offscreen.closeDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAuth(providerName) {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
// sending to offscreen document
|
||||||
|
const auth = await chrome.runtime.sendMessage({
|
||||||
|
type: 'firebase-auth',
|
||||||
|
target: 'offscreen',
|
||||||
|
providerName
|
||||||
|
});
|
||||||
|
auth?.name !== 'FirebaseError' ? resolve(auth) : reject(auth);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function firebaseAuth(providerName) {
|
||||||
|
await setupOffscreenDocument(OFFSCREEN_DOCUMENT_PATH);
|
||||||
|
|
||||||
|
const auth = await getAuth(providerName)
|
||||||
|
.then(auth => {
|
||||||
|
console.log('User Authenticated', auth);
|
||||||
|
return auth;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.code === 'auth/operation-not-allowed') {
|
||||||
|
console.error(
|
||||||
|
'You must enable an OAuth provider in the Firebase' +
|
||||||
|
' console in order to use signInWithPopup. This sample' +
|
||||||
|
' uses Google by default.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(closeOffscreenDocument);
|
||||||
|
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||||||
|
// received from the app
|
||||||
|
if (message.type === 'firebase-auth') {
|
||||||
|
firebaseAuth(message.providerName).then(sendResponse);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import firebase from 'firebase/app';
|
import { initializeApp } from 'firebase/app';
|
||||||
// import 'firebase/firestore';
|
import { getAuth } from 'firebase/auth';
|
||||||
|
import {
|
||||||
|
initializeFirestore,
|
||||||
|
persistentLocalCache,
|
||||||
|
persistentMultipleTabManager
|
||||||
|
} from 'firebase/firestore';
|
||||||
|
import { getStorage } from 'firebase/storage';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
apiKey: 'AIzaSyBl8Dz7ZOE7aP75mipYl2zKdLSRzBU2fFc',
|
apiKey: 'AIzaSyBl8Dz7ZOE7aP75mipYl2zKdLSRzBU2fFc',
|
||||||
authDomain: 'web-maker-app.firebaseapp.com',
|
authDomain: 'web-maker-app.firebaseapp.com',
|
||||||
@@ -8,4 +15,14 @@ const config = {
|
|||||||
storageBucket: 'web-maker-app.appspot.com',
|
storageBucket: 'web-maker-app.appspot.com',
|
||||||
messagingSenderId: '560473480645'
|
messagingSenderId: '560473480645'
|
||||||
};
|
};
|
||||||
firebase.initializeApp(config);
|
|
||||||
|
const app = initializeApp(config);
|
||||||
|
export { app };
|
||||||
|
|
||||||
|
export const auth = getAuth(app);
|
||||||
|
export const storage = getStorage(app);
|
||||||
|
export const db = initializeFirestore(app, {
|
||||||
|
localCache: persistentLocalCache({
|
||||||
|
tabManager: persistentMultipleTabManager()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
@@ -1,16 +1,27 @@
|
|||||||
import { deferred } from './deferred';
|
import { deferred } from './deferred';
|
||||||
import { log } from './utils';
|
import { log } from './utils';
|
||||||
import firebase from 'firebase/app';
|
import {
|
||||||
|
collection,
|
||||||
|
deleteField,
|
||||||
|
where,
|
||||||
|
getDoc,
|
||||||
|
query,
|
||||||
|
setDoc,
|
||||||
|
writeBatch,
|
||||||
|
doc,
|
||||||
|
deleteDoc,
|
||||||
|
updateDoc,
|
||||||
|
getDocs
|
||||||
|
} from 'firebase/firestore';
|
||||||
|
|
||||||
export const itemService = {
|
export const itemService = {
|
||||||
async getItem(id) {
|
async getItem(id) {
|
||||||
var remoteDb = await window.db.getDb();
|
var remoteDb = window.db.getDb();
|
||||||
return remoteDb
|
return getDoc(doc(remoteDb, `items/${id}`))
|
||||||
.doc(`items/${id}`)
|
|
||||||
.get()
|
|
||||||
.then(doc => {
|
.then(doc => {
|
||||||
return doc.data();
|
return doc.data();
|
||||||
});
|
})
|
||||||
|
.catch(error => log(error));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,23 +52,23 @@ export const itemService = {
|
|||||||
const items = [];
|
const items = [];
|
||||||
|
|
||||||
if (window.user && !shouldFetchLocally) {
|
if (window.user && !shouldFetchLocally) {
|
||||||
var remoteDb = await window.db.getDb();
|
var remoteDb = window.db.getDb();
|
||||||
remoteDb
|
|
||||||
.collection('items')
|
const q = query(
|
||||||
.where('createdBy', '==', window.user.uid)
|
collection(remoteDb, 'items'),
|
||||||
.onSnapshot(
|
where('createdBy', '==', window.user.uid)
|
||||||
function (querySnapshot) {
|
);
|
||||||
querySnapshot.forEach(function (doc) {
|
getDocs(q)
|
||||||
|
.then(querySnapshot => {
|
||||||
|
querySnapshot.forEach(doc => {
|
||||||
items.push(doc.data());
|
items.push(doc.data());
|
||||||
});
|
});
|
||||||
log('Items fetched in ', Date.now() - t, 'ms');
|
log(`${items.length} items fetched in `, Date.now() - t, 'ms');
|
||||||
|
|
||||||
d.resolve(items);
|
d.resolve(items);
|
||||||
},
|
})
|
||||||
function () {
|
.catch(() => {
|
||||||
d.resolve([]);
|
d.resolve([]);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let itemIds = await this.getUserItemIds(shouldFetchLocally);
|
let itemIds = await this.getUserItemIds(shouldFetchLocally);
|
||||||
itemIds = Object.getOwnPropertyNames(itemIds || {});
|
itemIds = Object.getOwnPropertyNames(itemIds || {});
|
||||||
@@ -83,8 +94,8 @@ export const itemService = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async setUser() {
|
async setUser() {
|
||||||
const remoteDb = await window.db.getDb();
|
const remoteDb = window.db.getDb();
|
||||||
return remoteDb.doc(`users/${window.user.uid}`).set({
|
return setDoc(doc(remoteDb, `users/${window.user.uid}`), {
|
||||||
items: {}
|
items: {}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -112,16 +123,13 @@ export const itemService = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LOGGED IN
|
// LOGGED IN
|
||||||
var remoteDb = await window.db.getDb();
|
var remoteDb = window.db.getDb();
|
||||||
item.createdBy = window.user.uid;
|
item.createdBy = window.user.uid;
|
||||||
remoteDb
|
setDoc(doc(remoteDb, `items/${id}`), item, {
|
||||||
.collection('items')
|
|
||||||
.doc(id)
|
|
||||||
.set(item, {
|
|
||||||
merge: true
|
merge: true
|
||||||
})
|
})
|
||||||
.then(arg => {
|
.then(() => {
|
||||||
log('Document written', arg);
|
log(`Document written`);
|
||||||
d.resolve();
|
d.resolve();
|
||||||
})
|
})
|
||||||
.catch(d.reject);
|
.catch(d.reject);
|
||||||
@@ -161,14 +169,15 @@ export const itemService = {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
window.db.getDb().then(remoteDb => {
|
window.db.getDb().then(remoteDb => {
|
||||||
const batch = remoteDb.batch();
|
const batch = writeBatch(remoteDb);
|
||||||
/* eslint-disable guard-for-in */
|
/* eslint-disable guard-for-in */
|
||||||
for (var id in items) {
|
for (var id in items) {
|
||||||
items[id].createdBy = window.user.uid;
|
items[id].createdBy = window.user.uid;
|
||||||
batch.set(remoteDb.doc(`items/${id}`), items[id]);
|
batch.set(doc(remoteDb, `items/${id}`), items[id]);
|
||||||
batch.update(remoteDb.doc(`users/${window.user.uid}`), {
|
batch.update(doc(remoteDb, `users/${window.user.uid}`), {
|
||||||
[`items.${id}`]: true
|
[`items.${id}`]: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set these items on our cached user object too
|
// Set these items on our cached user object too
|
||||||
window.user.items = window.user.items || {};
|
window.user.items = window.user.items || {};
|
||||||
window.user.items[id] = true;
|
window.user.items[id] = true;
|
||||||
@@ -187,14 +196,11 @@ export const itemService = {
|
|||||||
window.db.local.remove(id, d.resolve);
|
window.db.local.remove(id, d.resolve);
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
const remoteDb = await window.db.getDb();
|
const remoteDb = window.db.getDb();
|
||||||
log(`Starting to save item ${id}`);
|
log(`Starting to save item ${id}`);
|
||||||
return remoteDb
|
return deleteDoc(doc(remoteDb, `items/${id}`))
|
||||||
.collection('items')
|
.then(() => {
|
||||||
.doc(id)
|
log('Document removed');
|
||||||
.delete()
|
|
||||||
.then(arg => {
|
|
||||||
log('Document removed', arg);
|
|
||||||
})
|
})
|
||||||
.catch(error => log(error));
|
.catch(error => log(error));
|
||||||
},
|
},
|
||||||
@@ -214,11 +220,8 @@ export const itemService = {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const remoteDb = await window.db.getDb();
|
const remoteDb = window.db.getDb();
|
||||||
return remoteDb
|
return updateDoc(doc(remoteDb, `users/${window.user.uid}`), {
|
||||||
.collection('users')
|
|
||||||
.doc(window.user.uid)
|
|
||||||
.update({
|
|
||||||
[`items.${itemId}`]: true
|
[`items.${itemId}`]: true
|
||||||
})
|
})
|
||||||
.then(arg => {
|
.then(arg => {
|
||||||
@@ -244,16 +247,13 @@ export const itemService = {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const remoteDb = await window.db.getDb();
|
const remoteDb = window.db.getDb();
|
||||||
return remoteDb
|
return updateDoc(doc(remoteDb, `users/${window.user.uid}`), {
|
||||||
.collection('users')
|
[`items.${itemId}`]: deleteField()
|
||||||
.doc(window.user.uid)
|
|
||||||
.update({
|
|
||||||
[`items.${itemId}`]: firebase.firestore.FieldValue.delete()
|
|
||||||
})
|
})
|
||||||
.then(arg => {
|
.then(arg => {
|
||||||
delete window.user.items[itemId];
|
|
||||||
log(`Item ${itemId} unset for user`, arg);
|
log(`Item ${itemId} unset for user`, arg);
|
||||||
|
delete window.user.items[itemId];
|
||||||
})
|
})
|
||||||
.catch(error => log(error));
|
.catch(error => log(error));
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
let mainWindow = window.parent;
|
let mainWindow = window.parent === window ? window.opener : window.parent;
|
||||||
|
|
||||||
function sanitizeDomNode(node) {
|
function sanitizeDomNode(node) {
|
||||||
const fakeNode = {
|
const fakeNode = {
|
||||||
|
@@ -1,24 +1,33 @@
|
|||||||
{
|
{
|
||||||
"name": "Web Maker",
|
"name": "Web Maker",
|
||||||
"version": "6.0.0",
|
"version": "6.3.0",
|
||||||
"manifest_version": 2,
|
"manifest_version": 3,
|
||||||
"description": "Blazing fast & offline playground for your web experiments",
|
"description": "Blazing fast & offline playground for your web experiments",
|
||||||
"homepage_url": "https://webmaker.app",
|
"homepage_url": "https://webmaker.app",
|
||||||
"permissions": ["storage", "tabs", "<all_urls>"],
|
"permissions": ["storage", "tabs", "offscreen"],
|
||||||
"optional_permissions": ["downloads"],
|
"optional_permissions": ["downloads"],
|
||||||
"content_security_policy": "script-src 'self' filesystem: http://localhost:* https://localhost:* https://apis.google.com https://ajax.googleapis.com https://code.jquery.com https://cdnjs.cloudflare.com https://unpkg.com https://maxcdn.com https://cdn77.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net/ https://*.stripe.com/ https://builds.framerjs.com/ https://rawgit.com https://wzrd.in https://www.gstatic.com https://semantic-ui.com https://www.google-analytics.com https://cdn.tailwindcss.com https://www.googletagmanager.com 'unsafe-eval'; object-src 'self'",
|
"host_permissions": ["<all_urls>"],
|
||||||
|
"content_security_policy": {
|
||||||
|
"extension_pages": "script-src 'self'; object-src 'self'",
|
||||||
|
"sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' filesystem: http://localhost:* https://localhost:* https://apis.google.com https://ajax.googleapis.com https://code.jquery.com https://cdnjs.cloudflare.com https://unpkg.com https://maxcdn.com https://cdn77.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net/ https://*.stripe.com/ https://builds.framerjs.com/ https://rawgit.com https://wzrd.in https://www.gstatic.com https://semantic-ui.com https://www.google-analytics.com https://cdn.tailwindcss.com https://www.googletagmanager.com https://firebasestorage.googleapis.com https://assets.webmaker.app 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
|
||||||
|
},
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "options.html",
|
"page": "options.html",
|
||||||
"chrome_style": true
|
"open_in_tab": false
|
||||||
},
|
},
|
||||||
"browser_action": {
|
"action": {
|
||||||
"default_title": "Start Web Maker",
|
"default_title": "Start Web Maker",
|
||||||
"default_icon": "icon-16.png"
|
"default_icon": "icon-16.png"
|
||||||
},
|
},
|
||||||
"background": {
|
"sandbox": {
|
||||||
"scripts": ["eventPage.js"],
|
"pages": ["indexpm.html"]
|
||||||
"persistent": false
|
|
||||||
},
|
},
|
||||||
|
"background": {
|
||||||
|
"service_worker": "eventPage.js",
|
||||||
|
"type": "module"
|
||||||
|
},
|
||||||
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp4s9naKH2y92qItJCcj3deRGjjqhDfgUR2WDe34IEYEB4PGtmx/9IO4PaO49gMr82DBRuwxCg/vr9SyiVlG1/j0TApJlkaHVsRZE4EME2rbL1vzIQRE8gNB+b5L6rPl4GPX/eFqIuUe/UgQPZAadLBVxdwBdOv5ou8OY0jrLx/h0wcLVvk9d8/ELpk28Hb2LArCBd+vIngHK55Db1GMEGAyNUVzFCTg/MZ7w5fKLpA94mF2X0/Bv9sCjj7vDir24Mp5Z/Y3obTHvpzddppAE6ZEQ3fmpRkOJ3MbuaKYm9hNHs4az6XLW6Sdlv2YcIcCfvsev/WEKUZeD8KIRtRyyPQIDAQAB",
|
||||||
|
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "icon-16.png",
|
"16": "icon-16.png",
|
||||||
"48": "icon-48.png"
|
"48": "icon-48.png"
|
||||||
|
@@ -35,7 +35,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<h3>
|
<h3>
|
||||||
Settings
|
Settings
|
||||||
<span style="opacity: 0.6; font-size: 0.7em"> v6.0.0</span>
|
<span style="opacity: 0.6; font-size: 0.7em"> v6.3.0</span>
|
||||||
</h3>
|
</h3>
|
||||||
<form name="optionsForm">
|
<form name="optionsForm">
|
||||||
<label>
|
<label>
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<iframe
|
<iframe
|
||||||
src="about://blank"
|
src="indexpm.html"
|
||||||
frameborder="0"
|
frameborder="0"
|
||||||
id="demo-frame"
|
id="demo-frame"
|
||||||
allowfullscreen
|
allowfullscreen
|
||||||
|
@@ -15,11 +15,6 @@ export default [
|
|||||||
title: 'Preact',
|
title: 'Preact',
|
||||||
img: 'assets/preact-logo.svg'
|
img: 'assets/preact-logo.svg'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'tailwind2',
|
|
||||||
title: 'Tailwind CSS 2',
|
|
||||||
img: 'assets/tailwind-logo.svg'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'tailwind',
|
id: 'tailwind',
|
||||||
title: 'Tailwind CSS 3',
|
title: 'Tailwind CSS 3',
|
||||||
|
10
src/utils.js
10
src/utils.js
@@ -406,26 +406,26 @@ export function getCompleteHtml(html, css, js, item, isForExport) {
|
|||||||
'</head>\n' +
|
'</head>\n' +
|
||||||
'<body>\n' +
|
'<body>\n' +
|
||||||
html +
|
html +
|
||||||
'\n' +
|
|
||||||
externalJs +
|
|
||||||
'\n';
|
'\n';
|
||||||
|
|
||||||
if (!isForExport) {
|
if (!isForExport) {
|
||||||
contents +=
|
contents +=
|
||||||
'<script src="' +
|
'<script src="' +
|
||||||
(chrome.extension
|
(chrome.extension
|
||||||
? chrome.extension.getURL('lib/screenlog.js')
|
? chrome.runtime.getURL('lib/screenlog.js')
|
||||||
: `${location.origin}${
|
: `${location.origin}${
|
||||||
window.DEBUG ? '' : BASE_PATH
|
window.DEBUG ? '' : BASE_PATH
|
||||||
}/lib/screenlog.js`) +
|
}/lib/screenlog.js`) +
|
||||||
'"></script>';
|
'"></script>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contents += '\n' + externalJs;
|
||||||
|
|
||||||
if (item.jsMode === JsModes.ES6) {
|
if (item.jsMode === JsModes.ES6) {
|
||||||
contents +=
|
contents +=
|
||||||
'<script src="' +
|
'<script src="' +
|
||||||
(chrome.extension
|
(chrome.extension
|
||||||
? chrome.extension.getURL('lib/transpilers/babel-polyfill.min.js')
|
? chrome.runtime.getURL('lib/transpilers/babel-polyfill.min.js')
|
||||||
: `${location.origin}${BASE_PATH}/lib/transpilers/babel-polyfill.min.js`) +
|
: `${location.origin}${BASE_PATH}/lib/transpilers/babel-polyfill.min.js`) +
|
||||||
'"></script>';
|
'"></script>';
|
||||||
}
|
}
|
||||||
@@ -532,7 +532,7 @@ export function prettify({ file, content, type }) {
|
|||||||
}
|
}
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
chrome.extension
|
chrome.extension
|
||||||
? chrome.extension.getURL('lib/prettier-worker.js')
|
? chrome.runtime.getURL('lib/prettier-worker.js')
|
||||||
: `${BASE_PATH !== '/' ? BASE_PATH : ''}/lib/prettier-worker.js`
|
: `${BASE_PATH !== '/' ? BASE_PATH : ''}/lib/prettier-worker.js`
|
||||||
);
|
);
|
||||||
worker.postMessage({ content, type });
|
worker.postMessage({ content, type });
|
||||||
|
Reference in New Issue
Block a user