1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-08-02 11:30:22 +02:00

Merge pull request #332 from chinchang/new-console

New console
This commit is contained in:
Kushagra Gour
2018-10-21 23:07:01 +05:30
committed by GitHub
13 changed files with 175 additions and 179 deletions

View File

@@ -1,5 +1,9 @@
{ {
"env": {
"test": {
"presets": [ "presets": [
["preact-cli/babel", { "modules": "commonjs" }] ["preact-cli/babel", { "modules": "commonjs" }]
] ]
} }
}
}

View File

@@ -8,7 +8,7 @@
"serve": "preact build && preact serve", "serve": "preact build && preact serve",
"dev": "preact watch --template src/index.html --https --no-prerender", "dev": "preact watch --template src/index.html --https --no-prerender",
"lint": "eslint src", "lint": "eslint src",
"test": "jest ./tests", "test": "jest",
"precommit": "lint-staged" "precommit": "lint-staged"
}, },
"eslintConfig": { "eslintConfig": {
@@ -53,8 +53,6 @@
}, },
"dependencies": { "dependencies": {
"@emmetio/codemirror-plugin": "^0.5.4", "@emmetio/codemirror-plugin": "^0.5.4",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"code-blast-codemirror": "chinchang/code-blast-codemirror#web-maker", "code-blast-codemirror": "chinchang/code-blast-codemirror#web-maker",
"codemirror": "^5.37.0", "codemirror": "^5.37.0",
"copy-webpack-plugin": "^4.5.1", "copy-webpack-plugin": "^4.5.1",
@@ -65,13 +63,19 @@
"preact-compat": "^3.17.0", "preact-compat": "^3.17.0",
"preact-portal": "^1.1.3", "preact-portal": "^1.1.3",
"preact-router": "^2.5.7", "preact-router": "^2.5.7",
"split.js": "1.3.4", "prettier": "^1.10.2",
"prettier": "^1.10.2" "react-inspector": "^2.3.0",
"split.js": "1.3.4"
}, },
"jest": { "jest": {
"verbose": true, "verbose": true,
"setupFiles": [ "setupFiles": [
"<rootDir>/src/tests/__mocks__/browserMocks.js" "<rootDir>/tests/__mocks__/browserMocks.js"
],
"testRegex": "(/(__tests__|tests)/.*|(\\.|/)(test|spec))\\.jsx?$",
"testPathIgnorePatterns": [
"/node_modules/",
"<rootDir>/tests/__mocks__/*"
], ],
"testURL": "http://localhost:8080", "testURL": "http://localhost:8080",
"moduleFileExtensions": [ "moduleFileExtensions": [
@@ -82,7 +86,7 @@
"node_modules" "node_modules"
], ],
"moduleNameMapper": { "moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/tests/__mocks__/fileMock.js", "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tests/__mocks__/fileMock.js",
"\\.(css|less|scss)$": "identity-obj-proxy", "\\.(css|less|scss)$": "identity-obj-proxy",
"^./style$": "identity-obj-proxy", "^./style$": "identity-obj-proxy",
"^preact$": "<rootDir>/node_modules/preact/dist/preact.min.js", "^preact$": "<rootDir>/node_modules/preact/dist/preact.min.js",

View File

@@ -1,14 +1,47 @@
import { h } from 'preact'; import { h, Component } from 'preact';
import CodeMirrorBox from './CodeMirrorBox'; import { PureComponent } from 'preact-compat';
export function Console({ import { Inspector, chromeDark } from 'react-inspector';
class LogRow extends Component {
shouldComponentUpdate() {
return false;
}
render() {
const theme = {
...chromeDark,
...{
OBJECT_VALUE_STRING_COLOR: 'green',
BASE_FONT_SIZE: '20px',
TREENODE_FONT_SIZE: '20px'
}
};
return (
<Inspector theme={theme} theme="chromeDark" data={this.props.data} />
);
}
}
export class Console extends Component {
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, isConsoleOpen,
onConsoleHeaderDblClick, onConsoleHeaderDblClick,
onClearConsoleBtnClick, onClearConsoleBtnClick,
toggleConsole, toggleConsole,
onEvalInputKeyup, onEvalInputKeyup
onReady } = this.props;
}) {
return ( return (
<div <div
id="consoleEl" id="consoleEl"
@@ -21,7 +54,7 @@ export function Console({
onDblClick={onConsoleHeaderDblClick} onDblClick={onConsoleHeaderDblClick}
> >
<span class="code-wrap__header-label"> <span class="code-wrap__header-label">
Console (<span id="logCountEl">0</span>) Console (<span>{logs.length}</span>)
</span> </span>
<div class="code-wrap__header-right-options"> <div class="code-wrap__header-right-options">
<a <a
@@ -40,17 +73,14 @@ export function Console({
/> />
</div> </div>
</div> </div>
<CodeMirrorBox <ul
options={{ class="console__items"
mode: 'javascript', ref={el => {
lineWrapping: true, this.logContainerEl = el;
theme: 'monokai',
foldGutter: true,
readOnly: true,
gutters: ['CodeMirror-foldgutter']
}} }}
onCreation={el => onReady(el)} >
/> {logs.map(log => <LogRow data={log} />)}
</ul>
</div> </div>
<div <div
id="consolePromptEl" id="consolePromptEl"
@@ -68,3 +98,4 @@ export function Console({
</div> </div>
); );
} }
}

View File

@@ -19,7 +19,8 @@ export default class ContentWrap extends Component {
super(props); super(props);
this.state = { this.state = {
isConsoleOpen: false, isConsoleOpen: false,
isCssSettingsModalOpen: false isCssSettingsModalOpen: false,
logs: []
}; };
this.updateTimer = null; this.updateTimer = null;
this.updateDelay = 500; this.updateDelay = 500;
@@ -31,7 +32,6 @@ export default class ContentWrap extends Component {
this.codeInPreview = { html: null, css: null, js: null }; this.codeInPreview = { html: null, css: null, js: null };
this.cmCodes = { html: props.currentItem.html, css: '', js: '' }; this.cmCodes = { html: props.currentItem.html, css: '', js: '' };
this.cm = {}; this.cm = {};
this.logCount = 0;
window.onMessageFromConsole = this.onMessageFromConsole.bind(this); window.onMessageFromConsole = this.onMessageFromConsole.bind(this);
window.previewException = this.previewException.bind(this); window.previewException = this.previewException.bind(this);
@@ -42,6 +42,7 @@ export default class ContentWrap extends Component {
return ( return (
this.state.isConsoleOpen !== nextState.isConsoleOpen || this.state.isConsoleOpen !== nextState.isConsoleOpen ||
this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen || this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen ||
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 ||
this.props.currentLayoutMode !== nextProps.currentLayoutMode || this.props.currentLayoutMode !== nextProps.currentLayoutMode ||
@@ -50,9 +51,6 @@ export default class ContentWrap extends Component {
); );
} }
componentDidUpdate() { componentDidUpdate() {
// HACK: becuase its a DOM manipulation
this.updateLogCount();
// log('🚀', 'didupdate', this.props.currentItem); // log('🚀', 'didupdate', this.props.currentItem);
// if (this.isValidItem(this.props.currentItem)) { // if (this.isValidItem(this.props.currentItem)) {
// this.refreshEditor(); // this.refreshEditor();
@@ -288,11 +286,10 @@ export default class ContentWrap extends Component {
]).then(() => this.setPreviewContent(true)); ]).then(() => this.setPreviewContent(true));
} }
applyCodemirrorSettings(prefs) { applyCodemirrorSettings(prefs) {
if (window.consoleEl) { document.documentElement.style.setProperty(
window.consoleEl.querySelector( '--code-font-size',
'.CodeMirror' `${parseInt(prefs.fontSize, 10)}px`
).style.fontSize = `${parseInt(prefs.fontSize, 10)}px`; );
}
// Replace correct css file in LINK tags's href // Replace correct css file in LINK tags's href
if (prefs.editorTheme) { if (prefs.editorTheme) {
@@ -556,46 +553,21 @@ export default class ContentWrap extends Component {
}, 500); }, 500);
} }
updateLogCount() {
if (window.logCountEl) {
logCountEl.textContent = this.logCount;
}
}
onMessageFromConsole() { onMessageFromConsole() {
/* eslint-disable no-param-reassign */ const logs = [...arguments].map(arg => {
[...arguments].forEach(arg => {
if ( if (
arg && arg &&
arg.indexOf && arg.indexOf &&
arg.indexOf('filesystem:chrome-extension') !== -1 arg.indexOf('filesystem:chrome-extension') !== -1
) { ) {
arg = arg.replace( return arg.replace(
/filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, /filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g,
'script $1:$2' 'script $1:$2'
); );
} }
try { return arg;
this.consoleCm.replaceRange(
arg +
' ' +
((arg + '').match(/\[object \w+]/) ? JSON.stringify(arg) : '') +
'\n',
{
line: Infinity
}
);
} catch (e) {
this.consoleCm.replaceRange('🌀\n', {
line: Infinity
}); });
} this.setState({ logs: [...this.state.logs, ...logs] });
this.consoleCm.scrollTo(0, Infinity);
this.logCount++;
});
this.updateLogCount();
/* eslint-enable no-param-reassign */
} }
previewException(error) { previewException(error) {
@@ -615,9 +587,7 @@ export default class ContentWrap extends Component {
this.toggleConsole(); this.toggleConsole();
} }
clearConsole() { clearConsole() {
this.consoleCm.setValue(''); this.setState({ logs: [] });
this.logCount = 0;
this.updateLogCount();
} }
clearConsoleBtnClickHandler() { clearConsoleBtnClickHandler() {
this.clearConsole(); this.clearConsole();
@@ -864,6 +834,7 @@ export default class ContentWrap extends Component {
allowfullscreen allowfullscreen
/> />
<Console <Console
logs={this.state.logs}
isConsoleOpen={this.state.isConsoleOpen} isConsoleOpen={this.state.isConsoleOpen}
onConsoleHeaderDblClick={this.consoleHeaderDblClickHandler.bind( onConsoleHeaderDblClick={this.consoleHeaderDblClickHandler.bind(
this this
@@ -871,7 +842,6 @@ export default class ContentWrap extends Component {
onClearConsoleBtnClick={this.clearConsoleBtnClickHandler.bind(this)} onClearConsoleBtnClick={this.clearConsoleBtnClickHandler.bind(this)}
toggleConsole={this.toggleConsole.bind(this)} toggleConsole={this.toggleConsole.bind(this)}
onEvalInputKeyup={this.evalConsoleExpr.bind(this)} onEvalInputKeyup={this.evalConsoleExpr.bind(this)}
onReady={el => (this.consoleCm = el)}
/> />
<CssSettingsModal <CssSettingsModal
show={this.state.isCssSettingsModalOpen} show={this.state.isCssSettingsModalOpen}

View File

@@ -28,6 +28,7 @@ export default class ContentWrapFiles extends Component {
this.state = { this.state = {
isConsoleOpen: false, isConsoleOpen: false,
isCssSettingsModalOpen: false, isCssSettingsModalOpen: false,
logs: [],
editorOptions: this.getEditorOptions() editorOptions: this.getEditorOptions()
}; };
@@ -38,7 +39,6 @@ export default class ContentWrapFiles extends Component {
this.prefs = {}; this.prefs = {};
this.codeInPreview = { html: null, css: null, js: null }; this.codeInPreview = { html: null, css: null, js: null };
this.cmCodes = { html: props.currentItem.html, css: '', js: '' }; this.cmCodes = { html: props.currentItem.html, css: '', js: '' };
this.logCount = 0;
window.onMessageFromConsole = this.onMessageFromConsole.bind(this); window.onMessageFromConsole = this.onMessageFromConsole.bind(this);
window.previewException = this.previewException.bind(this); window.previewException = this.previewException.bind(this);
@@ -49,6 +49,7 @@ export default class ContentWrapFiles extends Component {
return ( return (
this.state.isConsoleOpen !== nextState.isConsoleOpen || this.state.isConsoleOpen !== nextState.isConsoleOpen ||
this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen || this.state.isCssSettingsModalOpen !== nextState.isCssSettingsModalOpen ||
this.state.logs !== nextState.logs ||
this.state.mainSplitSizes !== nextState.mainSplitSizes || this.state.mainSplitSizes !== nextState.mainSplitSizes ||
this.state.selectedFile !== nextState.selectedFile || this.state.selectedFile !== nextState.selectedFile ||
this.props.currentLayoutMode !== nextProps.currentLayoutMode || this.props.currentLayoutMode !== nextProps.currentLayoutMode ||
@@ -293,11 +294,10 @@ export default class ContentWrapFiles extends Component {
); );
} }
applyCodemirrorSettings(prefs) { applyCodemirrorSettings(prefs) {
if (window.consoleEl) { document.documentElement.style.setProperty(
window.consoleEl.querySelector( '--code-font-size',
'.CodeMirror' `${parseInt(prefs.fontSize, 10)}px`
).style.fontSize = `${parseInt(prefs.fontSize, 10)}px`; );
}
// Replace correct css file in LINK tags's href // Replace correct css file in LINK tags's href
if (prefs.editorTheme) { if (prefs.editorTheme) {
@@ -493,46 +493,21 @@ export default class ContentWrapFiles extends Component {
this.cm.focus(); this.cm.focus();
} }
updateLogCount() {
if (window.logCountEl) {
logCountEl.textContent = this.logCount;
}
}
onMessageFromConsole() { onMessageFromConsole() {
/* eslint-disable no-param-reassign */ const logs = [...arguments].map(arg => {
[...arguments].forEach(arg => {
if ( if (
arg && arg &&
arg.indexOf && arg.indexOf &&
arg.indexOf('filesystem:chrome-extension') !== -1 arg.indexOf('filesystem:chrome-extension') !== -1
) { ) {
arg = arg.replace( return arg.replace(
/filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, /filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g,
'script $1:$2' 'script $1:$2'
); );
} }
try { return arg;
this.consoleCm.replaceRange(
arg +
' ' +
((arg + '').match(/\[object \w+]/) ? JSON.stringify(arg) : '') +
'\n',
{
line: Infinity
}
);
} catch (e) {
this.consoleCm.replaceRange('🌀\n', {
line: Infinity
}); });
} this.setState({ logs: [...this.state.logs, ...logs] });
this.consoleCm.scrollTo(0, Infinity);
this.logCount++;
});
this.updateLogCount();
/* eslint-enable no-param-reassign */
} }
previewException(error) { previewException(error) {
@@ -552,9 +527,7 @@ export default class ContentWrapFiles extends Component {
this.toggleConsole(); this.toggleConsole();
} }
clearConsole() { clearConsole() {
this.consoleCm.setValue(''); this.setState({ logs: [] });
this.logCount = 0;
this.updateLogCount();
} }
clearConsoleBtnClickHandler() { clearConsoleBtnClickHandler() {
this.clearConsole(); this.clearConsole();
@@ -654,6 +627,7 @@ export default class ContentWrapFiles extends Component {
allowfullscreen allowfullscreen
/> />
<Console <Console
logs={this.state.logs}
isConsoleOpen={this.state.isConsoleOpen} isConsoleOpen={this.state.isConsoleOpen}
onConsoleHeaderDblClick={this.consoleHeaderDblClickHandler.bind( onConsoleHeaderDblClick={this.consoleHeaderDblClickHandler.bind(
this this
@@ -661,7 +635,6 @@ export default class ContentWrapFiles extends Component {
onClearConsoleBtnClick={this.clearConsoleBtnClickHandler.bind(this)} onClearConsoleBtnClick={this.clearConsoleBtnClickHandler.bind(this)}
toggleConsole={this.toggleConsole.bind(this)} toggleConsole={this.toggleConsole.bind(this)}
onEvalInputKeyup={this.evalConsoleExpr.bind(this)} onEvalInputKeyup={this.evalConsoleExpr.bind(this)}
onReady={el => (this.consoleCm = el)}
/> />
</div> </div>
</SplitPane> </SplitPane>

View File

@@ -38,9 +38,6 @@ emmet(CodeMirror);
export default class UserCodeMirror extends Component { export default class UserCodeMirror extends Component {
componentDidMount() { componentDidMount() {
this.initEditor(); this.initEditor();
this.textarea.parentNode.querySelector(
'.CodeMirror'
).style.fontSize = `${parseInt(this.props.prefs.fontSize, 10)}px`;
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
if (nextProps.prefs !== this.props.prefs) { if (nextProps.prefs !== this.props.prefs) {
@@ -60,12 +57,6 @@ export default class UserCodeMirror extends Component {
this.cm.setOption('keyMap', prefs.keymap); this.cm.setOption('keyMap', prefs.keymap);
this.cm.setOption('lineWrapping', prefs.lineWrap); this.cm.setOption('lineWrapping', prefs.lineWrap);
if (this.textarea) {
this.textarea.parentNode.querySelector(
'.CodeMirror'
).style.fontSize = `${parseInt(prefs.fontSize, 10)}px`;
}
this.cm.refresh(); this.cm.refresh();
} }

View File

@@ -309,7 +309,11 @@ export default class App extends Component {
item = { item = {
...item, ...item,
files: assignFilePaths([ files: assignFilePaths([
{ name: 'index.html', content: '' }, {
name: 'index.html',
content:
'hello\n<link rel="stylesheet" href="styles/style.css">\n<script src="script.js"></script>'
},
{ {
name: 'styles', name: 'styles',
isFolder: true, isFolder: true,

View File

@@ -1418,12 +1418,6 @@ body > #demo-frame {
transform: translateY(calc(100% - 29px)); transform: translateY(calc(100% - 29px));
} }
.console .CodeMirror {
flex-grow: 1;
/* flex-basis of 0 to trigger overflow https://stackoverflow.com/a/52489012/891962 */
flex-basis: 0;
}
.console__log { .console__log {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -1442,6 +1436,20 @@ body > #demo-frame {
.console:not(.is-minimized) .code-wrap__header { .console:not(.is-minimized) .code-wrap__header {
cursor: ns-resize; cursor: ns-resize;
} }
.console__items {
padding: 0;
margin: 0;
overflow: auto;
flex-grow: 1;
/* flex-basis of 0 to trigger overflow https://stackoverflow.com/a/52489012/891962 */
flex-basis: 0;
}
.console__items li {
font-size: var(--code-font-size) !important;
line-height: inherit !important;
padding: 5px 10px !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
/* Detached mode */ /* Detached mode */

View File

@@ -6,7 +6,7 @@ import {
removeFileAtPath, removeFileAtPath,
getParentPath, getParentPath,
getExtensionFromFileName getExtensionFromFileName
} from '../fileUtils'; } from '../src/fileUtils';
function getNestedFiles() { function getNestedFiles() {
return [ return [

View File

@@ -1,5 +1,5 @@
import { h, Component } from 'preact'; import { h, Component } from 'preact';
import Footer from '../components/Footer'; import Footer from '../src/components/Footer';
import { Link } from 'preact-router/match'; import { Link } from 'preact-router/match';
// See: https://github.com/mzgoddard/preact-render-spy // See: https://github.com/mzgoddard/preact-render-spy
import { shallow, deep } from 'preact-render-spy'; import { shallow, deep } from 'preact-render-spy';

View File

@@ -5088,6 +5088,10 @@ is-directory@^0.3.1:
version "0.3.1" version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
is-dom@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d"
is-dotfile@^1.0.0: is-dotfile@^1.0.0:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
@@ -7973,6 +7977,13 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-inspector@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-2.3.0.tgz#fc9c1d38ab687fc0d190dcaf133ae40158968fc8"
dependencies:
babel-runtime "^6.26.0"
is-dom "^1.0.9"
read-all-stream@^3.0.0: read-all-stream@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa" resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"