Compare commits
10
Commits
d24e605ea9
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74f812c5aa | ||
|
|
221183962c | ||
|
|
65a6312b8e | ||
|
|
e3515901e4 | ||
|
|
28631e8251 | ||
|
|
e0c998cfac | ||
|
|
d3a0bd984e | ||
|
|
eae4476ed8 | ||
|
|
1d90760c33 | ||
|
|
7fce9b48c3 |
@@ -2,12 +2,17 @@
|
||||
<div class="flex-shrink section top">
|
||||
<h1>code editor</h1>
|
||||
<window-control distribute=".code-editor-containers">
|
||||
<window-control-connector style="display: none;" target=".menu-container" class="active">Sessions</window-control-connector>
|
||||
<window-control-connector target="code-editor-container[language='Javascript']" class="active">Javascript</window-control-connector>
|
||||
<window-control-connector target="code-editor-container[language='HTML']">HTML</window-control-connector>
|
||||
<window-control-connector target="code-editor-container[language='CSS']">CSS</window-control-connector>
|
||||
</window-control>
|
||||
</div>
|
||||
<div class="flex-dynamic">
|
||||
<div class="menu menu-container" id="session-menu" style="display: none">
|
||||
<resize-handle target=".menu-container" place="right" dir="horizontal"></resize-handle>
|
||||
<session-list></session-list>
|
||||
</div>
|
||||
<div class="code-editor-containers flex-vert">
|
||||
<code-editor-container language="Javascript" dir="vertical" class="first-visible last-visible">
|
||||
</code-editor-container>
|
||||
@@ -24,6 +29,6 @@
|
||||
<output-frame></output-frame>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-shrink section bottom">methods: rect, box, center, width, height, rand</div>
|
||||
<div class="flex-shrink section bottom">methods: rect, box, center, width, height, rand, randomColor</div>
|
||||
</div>
|
||||
<notification-bubbles></notification-bubbles>
|
||||
+3
-41
@@ -1,4 +1,5 @@
|
||||
@import url('../shared/theme.less');
|
||||
@import url('../shared/flex.less');
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
@@ -9,18 +10,6 @@ html, body {
|
||||
}
|
||||
|
||||
|
||||
.flex-horiz {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flex-vert {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.flex-horiz > * {
|
||||
min-height: auto !important;
|
||||
@@ -33,37 +22,10 @@ html, body {
|
||||
}
|
||||
|
||||
|
||||
.flex-horiz > *, .flex-vert > * {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.animate .flex-horiz > *, .animate .flex-vert > * {
|
||||
transition: all 280ms ease-in-out;
|
||||
}
|
||||
|
||||
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.flex-horiz .flex-grow, .flex-vert .flex-grow {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.flex-reset {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: @primary-font-family;
|
||||
}
|
||||
@@ -119,11 +81,11 @@ body {
|
||||
max-height: 0 !important;
|
||||
}
|
||||
|
||||
.flex-dynamic.flex-horiz .code-editor-containers resize-handle[dir='vertical'] {
|
||||
.flex-dynamic.flex-horiz .output-frame-container resize-handle[dir='vertical'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flex-dynamic.flex-vert .code-editor-containers resize-handle[dir='horizontal'] {
|
||||
.flex-dynamic.flex-vert .output-frame-container resize-handle[dir='horizontal'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -12,6 +12,10 @@ import { JavascriptCodeEditor } from './elements/code-editor/javascript-code-edi
|
||||
import { HtmlCodeEditor } from './elements/code-editor/html-code-editor';
|
||||
import { CssCodeEditor } from './elements/code-editor/css-code-editor';
|
||||
import { setDynamicFlexListener } from '../shared/set-dynamic-flex-listener';
|
||||
import { SessionList } from './elements/session-list/session-list';
|
||||
import { SessionListItem } from './elements/session-list-item/session-list-item';
|
||||
import { LoadingSpinner } from './elements/loading-spinner/loading-spinner';
|
||||
import { isSessionPage } from '../shared/page';
|
||||
|
||||
window.customElements.define('app-root', AppRoot);
|
||||
window.customElements.define('code-editor-container', CodeEditorContainer);
|
||||
@@ -24,8 +28,23 @@ window.customElements.define('notification-bubble', NotificationBubble);
|
||||
window.customElements.define('resize-handle', ResizeHandle);
|
||||
window.customElements.define('window-control', WindowControl);
|
||||
window.customElements.define('window-control-connector', WindowControlConnector);
|
||||
|
||||
window.customElements.define('session-list', SessionList);
|
||||
window.customElements.define('session-list-item', SessionListItem);
|
||||
window.customElements.define('loading-spinner', LoadingSpinner);
|
||||
|
||||
document.body.innerHTML += bootHtml;
|
||||
|
||||
if (isSessionPage()) {
|
||||
var menuEle = document.getElementById("session-menu");
|
||||
var containers = <HTMLElement>document.getElementsByClassName("code-editor-containers")[0];
|
||||
var outputframe = <HTMLElement>document.getElementsByClassName("output-frame-container")[0];
|
||||
var sessionMenuItem = <HTMLElement>document.querySelector("window-control-connector[target='.menu-container']");
|
||||
if (menuEle) {
|
||||
menuEle.style.display = "block";
|
||||
sessionMenuItem.style.display = "inline-block";
|
||||
containers.style.display = "none";
|
||||
outputframe.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
setDynamicFlexListener();
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ResizeHandle } from "../resize-handle/resize-handle";
|
||||
import './code-editor-container.less';
|
||||
|
||||
export class CodeEditorContainer extends BaseElement {
|
||||
private codeEditor: CodeEditor | null = null;
|
||||
onInit(): void {
|
||||
var language = this.getAttribute("language");
|
||||
this.classList.add("flex-vert");
|
||||
@@ -22,11 +23,15 @@ export class CodeEditorContainer extends BaseElement {
|
||||
this.appendChild(div);
|
||||
}
|
||||
|
||||
setInput(input: any) {
|
||||
this.codeEditor?.setInput(input);
|
||||
}
|
||||
|
||||
createCodeEditor(language: string, expandDir: 'vertical' | 'horizontal') {
|
||||
var codeEditorContent = document.createElement("div");
|
||||
codeEditorContent.classList.add("code-editor-content");
|
||||
var codeEditor = <CodeEditor>document.createElement(language + "-code-editor");
|
||||
codeEditorContent.appendChild(codeEditor);
|
||||
this.codeEditor = <CodeEditor>document.createElement(language + "-code-editor");
|
||||
codeEditorContent.appendChild(this.codeEditor);
|
||||
|
||||
var resizeHandle = <ResizeHandle>document.createElement("resize-handle");
|
||||
resizeHandle.setAttribute("dir", expandDir);
|
||||
|
||||
@@ -3,27 +3,34 @@ import './code-editor.less';
|
||||
import * as monaco from 'monaco-editor';
|
||||
import { OutputFrame } from "../output-frame/output-frame";
|
||||
import { debounceManager } from "../../../shared/ensure-debounce";
|
||||
import * as sessionApi from '../../../shared/session-api';
|
||||
import { isSessionPage } from "../../../shared/page";
|
||||
import { sanityConvert } from "../../../shared/sanity-code-check";
|
||||
|
||||
export class CodeEditor extends BaseElement {
|
||||
|
||||
public input: string = "";
|
||||
public language: string = "";
|
||||
public editor!: monaco.editor.IStandaloneCodeEditor;
|
||||
public lastInputCache: any;
|
||||
|
||||
onInit(): void {
|
||||
|
||||
this.initWorkers();
|
||||
this.input = this.setInitInput();
|
||||
this.language = this.tagName.substring(0, this.tagName.indexOf("-")).toLocaleLowerCase();
|
||||
this.lastInputCache = localStorage.getItem(this.language + "LastInputCache");
|
||||
this.input = this.setInitInput();
|
||||
|
||||
console.log(this.language);
|
||||
this.setInitSettings();
|
||||
|
||||
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
var editor = monaco.editor.create(this, {
|
||||
value: this.input,
|
||||
this.editor = monaco.editor.create(this, {
|
||||
value: isSessionPage() ? "" : this.input,
|
||||
language: this.language,
|
||||
automaticLayout: true,
|
||||
contextmenu: false,
|
||||
readOnly: isSessionPage(),
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
@@ -32,23 +39,44 @@ export class CodeEditor extends BaseElement {
|
||||
});
|
||||
|
||||
var debounce = debounceManager(1000);
|
||||
editor.onDidChangeModelContent((e) => {
|
||||
this.input = editor.getValue();
|
||||
this.editor.onDidChangeModelContent((e) => {
|
||||
if (!isSessionPage()) {
|
||||
this.input = this.editor.getValue();
|
||||
this.lastInputCache = this.input;
|
||||
localStorage.setItem(this.language + "LastInputCache", this.input);
|
||||
debounce.ensureDebounce(() => {
|
||||
this.outputFrame.setContent(this.language, this.input);
|
||||
sessionApi.setSessionData(this.language, this.input);
|
||||
this.outputFrame.setContent(this.language, this.language.toLowerCase() === "javascript" ? sanityConvert(this.input) : this.input);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.waitFor(this.outputFrame, () => {
|
||||
this.outputFrame.setContent(this.language, this.input);
|
||||
this.outputFrame.setContent(this.language, isSessionPage() ? "" : (this.language.toLowerCase() === "javascript" ? sanityConvert(this.input) : this.input));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
setInput(input: any) {
|
||||
if (this.input !== input) {
|
||||
this.input = input;
|
||||
this.lastInputCache = this.input;
|
||||
localStorage.setItem(this.language + "LastInputCache", this.input);
|
||||
this.editor.setValue(input);
|
||||
this.outputFrame.setContent(this.language, this.language.toLowerCase() === "javascript" ? sanityConvert(this.input) : this.input);
|
||||
}
|
||||
}
|
||||
|
||||
setInitInput(): string {
|
||||
if (!isSessionPage() && sessionApi.hasSession()) {
|
||||
return this.lastInputCache;
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setInitSettings(): void {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { CodeEditor } from "./code-editor";
|
||||
import * as monaco from 'monaco-editor';
|
||||
import initCss from '!!raw-loader!./injects/editor-init.css';
|
||||
import { createScript } from "../../../shared/create-script";
|
||||
|
||||
import flexCss from '!!raw-loader!../../../shared/flex.less';
|
||||
|
||||
export class CssCodeEditor extends CodeEditor {
|
||||
setInitInput(): string {
|
||||
var base = super.setInitInput();
|
||||
if (!base) {
|
||||
return initCss;
|
||||
}
|
||||
else {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
setInitSettings(): void {
|
||||
monaco.languages.registerCompletionItemProvider("css", {
|
||||
@@ -16,7 +23,7 @@ export class CssCodeEditor extends CodeEditor {
|
||||
{
|
||||
label: 'insert-flex',
|
||||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||
insertText: createScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js', false).toString(),
|
||||
insertText: flexCss,
|
||||
range: <any>null,
|
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { CodeEditor } from "./code-editor";
|
||||
import * as monaco from 'monaco-editor';
|
||||
import initHtml from '!!raw-loader!./injects/editor-init.html';
|
||||
import { createScript } from "../../../shared/create-script";
|
||||
|
||||
export class HtmlCodeEditor extends CodeEditor {
|
||||
setInitInput(): string {
|
||||
var base = super.setInitInput();
|
||||
if (!base) {
|
||||
return initHtml;
|
||||
}
|
||||
else {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
setInitSettings(): void {
|
||||
monaco.languages.registerCompletionItemProvider("html", {
|
||||
@@ -16,7 +21,7 @@ export class HtmlCodeEditor extends CodeEditor {
|
||||
{
|
||||
label: 'jqueryCDN',
|
||||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||
insertText: createScript('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js', false).toString(),
|
||||
insertText: "<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js'></script>",
|
||||
range: <any>null,
|
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
||||
}
|
||||
|
||||
@@ -6,8 +6,14 @@ import declarations from '!!raw-loader!./injects/declarations.d.ts';
|
||||
|
||||
export class JavascriptCodeEditor extends CodeEditor {
|
||||
setInitInput(): string {
|
||||
var base = super.setInitInput();
|
||||
if (!base) {
|
||||
return initScript;
|
||||
}
|
||||
else {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
setInitSettings(): void {
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(declarations, 'ts:filename/declarations.d.ts');
|
||||
@@ -31,8 +37,8 @@ export class JavascriptCodeEditor extends CodeEditor {
|
||||
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
|
||||
},
|
||||
{
|
||||
label: 'spiralBoxesSolutionSnippet',
|
||||
detail: "inserts solution of spiral boxes",
|
||||
label: 'spiralSolutionSnippet',
|
||||
detail: "",
|
||||
kind: monaco.languages.CompletionItemKind.Snippet,
|
||||
insertText: spiralBoxesSolutionScript,
|
||||
range: <any>null,
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
loading-spinner {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-radius: 50%;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.infinity-1 {
|
||||
width:90px;
|
||||
height:14px;
|
||||
background:
|
||||
radial-gradient(circle 7px at bottom, #fff 92%,#0000 ) 0 0,
|
||||
radial-gradient(circle 7px at top , #fff 92%,#0000 ) 0 100%;
|
||||
background-size:calc(100%/4) 50%;
|
||||
background-repeat:repeat-x;
|
||||
animation:i1 1s infinite;
|
||||
}
|
||||
@keyframes i1 {
|
||||
80%,100% {background-position: calc(100%/3) 0,calc(100%/-3) 100%}
|
||||
}
|
||||
|
||||
.infinity-2 {
|
||||
width:90px;
|
||||
height:14px;
|
||||
background:
|
||||
conic-gradient(from 135deg at top ,#fff 90deg,#0000 0) 0 0,
|
||||
conic-gradient(from -45deg at bottom,#fff 90deg,#0000 0) 0 100%;
|
||||
background-size:calc(100%/4) 50%;
|
||||
background-repeat:repeat-x;
|
||||
animation:i2 1s infinite;
|
||||
}
|
||||
@keyframes i2 {
|
||||
80%,100% {background-position: calc(100%/3) 0,calc(100%/-3) 100%}
|
||||
}
|
||||
|
||||
.infinity-3 {
|
||||
width:90px;
|
||||
height:14px;
|
||||
background:
|
||||
radial-gradient(circle 7px at bottom, #fff 92%,#0000 ) calc(100%/2) 0,
|
||||
radial-gradient(circle 7px at top , #fff 92%,#0000 ) calc(100%/2) 100%,
|
||||
conic-gradient(from 135deg at top ,#fff 90deg,#0000 0) 0 0,
|
||||
conic-gradient(from -45deg at bottom,#fff 90deg,#0000 0) 0 100%;
|
||||
background-size:calc(100%/2) 50%;
|
||||
background-repeat:repeat-x;
|
||||
animation:i3 3s infinite;
|
||||
}
|
||||
@keyframes i3 {
|
||||
0% {background-position: calc(100%/2) 0,calc(100%/2) 100%,0 0, 0 100%}
|
||||
20%,
|
||||
30% {background-position: calc(3*100%/4) 0,calc(100%/4) 100%,calc(100%/4) 0, calc(100%/-4) 100%}
|
||||
45%,
|
||||
55% {background-position: 100% 0,0 100%,calc(100%/2) 0, calc(100%/-2) 100%}
|
||||
70%,
|
||||
80% {background-position: calc(5*100%/4) 0,calc(100%/-4) 100%,calc(3*100%/4) 0, calc(3*100%/-4) 100%}
|
||||
100%{background-position: calc(3*100%/2) 0,calc(100%/-2) 100%,100% 0, -100% 100%}
|
||||
}
|
||||
|
||||
.infinity-4 {
|
||||
width:90px;
|
||||
height:14px;
|
||||
background:
|
||||
radial-gradient(circle closest-side, #fff 92%,#0000 ) calc(100%/-4) 0,
|
||||
radial-gradient(circle closest-side, #fff 92%,#0000 ) calc(100%/4) 0;
|
||||
background-size:calc(100%/2) 100%;
|
||||
animation:i4 1.5s infinite;
|
||||
}
|
||||
@keyframes i4 {
|
||||
0% {background-position: calc(100%/-4) 0 ,calc(100%/4) 0}
|
||||
50% {background-position: calc(100%/-4) -14px,calc(100%/4) 14px}
|
||||
100% {background-position: calc(100%/4) -14px,calc(3*100%/4) 14px}
|
||||
}
|
||||
|
||||
.infinity-5 {
|
||||
width:60px;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background:
|
||||
var(--g),
|
||||
var(--g) 10px 10px,
|
||||
var(--g) 20px 20px;
|
||||
background-size: 50% 50%;
|
||||
animation:i5 1s infinite;
|
||||
}
|
||||
@keyframes i5 {
|
||||
90%,100% {background-position: -30px 30px,-20px 40px,-10px 50px}
|
||||
}
|
||||
|
||||
.infinity-6 {
|
||||
width:60px;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background: var(--g), var(--g), var(--g);
|
||||
background-size: 50% 50%;
|
||||
animation:i6 1s infinite;
|
||||
}
|
||||
@keyframes i6 {
|
||||
0% {background-position:0 0 ,10px 10px,20px 20px}
|
||||
50% {background-position:0 20px,10px 10px,20px 0 }
|
||||
100% {background-position:20px 20px,10px 10px,0 0 }
|
||||
}
|
||||
|
||||
.infinity-7 {
|
||||
width:60px;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background: var(--g), var(--g), var(--g);
|
||||
background-size: 50% 50%;
|
||||
animation:i7 1s infinite;
|
||||
}
|
||||
@keyframes i7 {
|
||||
0% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
33% {background-position:-30px 0, 10px 10px, 20px 20px}
|
||||
66% {background-position:-30px 0,-20px 10px, 20px 20px}
|
||||
100% {background-position:-30px 0,-20px 10px,-10px 20px}
|
||||
}
|
||||
|
||||
.infinity-8 {
|
||||
width:60px;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background: var(--g), var(--g), var(--g);
|
||||
background-size: 50% 50%;
|
||||
animation:i8 1s infinite;
|
||||
}
|
||||
@keyframes i8 {
|
||||
0% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
33% {background-position:-30px 0, 10px 10px, 20px 20px}
|
||||
66% {background-position:-30px 0, 10px 40px, 20px 20px}
|
||||
100% {background-position:-30px 0, 10px 40px, 50px 20px}
|
||||
}
|
||||
|
||||
.infinity-9 {
|
||||
width:60px;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background: var(--g), var(--g), var(--g);
|
||||
background-size: 50% 50%;
|
||||
animation:i9 1s infinite;
|
||||
}
|
||||
@keyframes i9 {
|
||||
0% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
33% {background-position:10px 10px}
|
||||
66% {background-position:0 20px,10px 10px,20px 0 }
|
||||
100% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
}
|
||||
|
||||
.infinity-10 {
|
||||
width:60px;
|
||||
display:flex;
|
||||
align-items:flex-start;
|
||||
aspect-ratio:1;
|
||||
}
|
||||
.infinity-10:before,
|
||||
.infinity-10:after {
|
||||
content:"";
|
||||
flex:1;
|
||||
aspect-ratio:1;
|
||||
--g: conic-gradient(from -90deg at 10px 10px,#fff 90deg,#0000 0);
|
||||
background: var(--g), var(--g), var(--g);
|
||||
filter:drop-shadow(30px 30px 0 #fff);
|
||||
animation:i10 1s infinite;
|
||||
}
|
||||
.infinity-10:after {
|
||||
transform:scaleX(-1);
|
||||
}
|
||||
@keyframes i10 {
|
||||
0% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
33% {background-position:10px 10px}
|
||||
66% {background-position:0 20px,10px 10px,20px 0 }
|
||||
100% {background-position:0 0, 10px 10px, 20px 20px}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { BaseElement } from '../../../shared/_base';
|
||||
import './loading-spinner.less';
|
||||
|
||||
export class LoadingSpinner extends BaseElement {
|
||||
onInit(): void {
|
||||
this.classList.add("infinity-5");
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ output-frame {
|
||||
}
|
||||
|
||||
output-frame > iframe {
|
||||
position: relative;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
|
||||
@@ -21,27 +21,37 @@ export class OutputFrame extends BaseElement {
|
||||
onUpdate(): void {
|
||||
}
|
||||
|
||||
reset(onload: ((ev: Event) => void) | null = null, resetNotificationBubbles: boolean = true) {
|
||||
reset(onload: ((ev: Event) => void) | null = null, resetNotificationBubbles: boolean = true, source: string | null = null) {
|
||||
if (this.CurrentIframeScriptRemoveResponseListener != null) {
|
||||
this.CurrentIframeScriptRemoveResponseListener();
|
||||
this.CurrentIframeScriptRemoveResponseListener = null;
|
||||
}
|
||||
|
||||
if (this.Iframe && this.hasChild(this.Iframe)) {
|
||||
this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin");
|
||||
this.removeChild(this.Iframe);
|
||||
}
|
||||
|
||||
|
||||
this.Iframe = document.createElement("iframe");
|
||||
this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin allow-scripts");
|
||||
this.Iframe.src = GetOutputFrameUrl();
|
||||
|
||||
if (onload) {
|
||||
this.Iframe.onload = ((ev) => {
|
||||
onload(ev);
|
||||
if (this.Iframe)
|
||||
this.Iframe.onload = () => { };
|
||||
});
|
||||
}
|
||||
if (source != null) {
|
||||
this.Iframe.src = source;
|
||||
}
|
||||
else {
|
||||
this.Iframe.src = GetOutputFrameUrl();
|
||||
}
|
||||
|
||||
if (source !== "") {
|
||||
this.appendChild(this.Iframe);
|
||||
}
|
||||
|
||||
if (resetNotificationBubbles) {
|
||||
var bubbles = GetNotificationBubbles();
|
||||
@@ -53,9 +63,12 @@ export class OutputFrame extends BaseElement {
|
||||
|
||||
setError() {
|
||||
this.reset(() => {
|
||||
if (this.Iframe)
|
||||
this.Iframe.src = GetOutputFrameUrl() + "execution-time-error.html";
|
||||
});
|
||||
console.log("ERROR RESET");
|
||||
if (this.Iframe) {
|
||||
// this.Iframe.contentWindow?.location.reload();
|
||||
}
|
||||
}, true, "");
|
||||
|
||||
}
|
||||
|
||||
setContent(language: string, value: string) {
|
||||
@@ -72,7 +85,8 @@ export class OutputFrame extends BaseElement {
|
||||
}
|
||||
|
||||
doPostMessage(language: string, value: string) {
|
||||
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, language, this.contents[language], language == 'javascript' ? (executeTimeInMs, exceedTimeInMs) => {
|
||||
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, language, this.contents[language], language == 'javascript' ?
|
||||
(executeTimeInMs, exceedTimeInMs) => {
|
||||
if (executeTimeInMs === -1) {
|
||||
this.setError();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,13 @@ resize-handle[dir="vertical"][place='top'] {
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
resize-handle[dir="horizontal"][place='right'] {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
#fixed-resize-overlay {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
@import url('../../../shared/theme.less');
|
||||
|
||||
session-list-item {
|
||||
color: @primary-text-color-white;
|
||||
padding: 10px;
|
||||
display: block;
|
||||
position: relative;
|
||||
border-bottom: 1px solid;
|
||||
border-color: @primary-bg-color-white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
session-list-item.selected {
|
||||
background-color: lighten(@primary-interaction-highlight-white, 30%);
|
||||
}
|
||||
|
||||
session-list-item.selected .slider-wrap {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.session-list-item-session-id::before {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.session-list-item-timestamp::before {
|
||||
content: "Created: ";
|
||||
}
|
||||
|
||||
.session-list-item-timestamp {
|
||||
font-size: 12px;
|
||||
opacity: 0.9;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
.session-list-item-session-id {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.session-list-item-session-id > span {
|
||||
display: inline-block;
|
||||
font-size: 9px;
|
||||
padding: 2px 4px;
|
||||
background-color: @editor-bg-white;
|
||||
border: 1px solid;
|
||||
border-color: darken(@editor-bg-white, 10%);
|
||||
border-radius: 3px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.session-list-item-number-of-changes {
|
||||
font-size: 12px;
|
||||
opacity: 0.6;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
.session-list-item-number-of-changes::before {
|
||||
content: "Number of changes: ";
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.slider-wrap {
|
||||
display: none;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.slider-wrap input {
|
||||
width: 100%; /* Width of the outside container */
|
||||
}
|
||||
|
||||
/* The slider itself */
|
||||
.slider-wrap input {
|
||||
-webkit-appearance: none; /* Override default CSS styles */
|
||||
appearance: none;
|
||||
width: 100%; /* Full-width */
|
||||
height: 25px; /* Specified height */
|
||||
background: @editor-bg-white; /* Grey background */
|
||||
outline: none; /* Remove outline */
|
||||
opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
|
||||
-webkit-transition: .2s; /* 0.2 seconds transition on hover */
|
||||
transition: opacity .2s;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Mouse-over effects */
|
||||
.slider-wrap input:hover {
|
||||
opacity: 1; /* Fully shown on mouse-over */
|
||||
}
|
||||
|
||||
/* The slider handle (use -webkit- (Chrome, Opera, Safari, Edge) and -moz- (Firefox) to override default look) */
|
||||
.slider-wrap input::-webkit-slider-thumb {
|
||||
-webkit-appearance: none; /* Override default look */
|
||||
appearance: none;
|
||||
width: 25px; /* Set a specific slider handle width */
|
||||
height: 25px; /* Slider handle height */
|
||||
background: @primary-interaction-highlight-white; /* Green background */
|
||||
cursor: pointer; /* Cursor on hover */
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.slider-wrap input::-moz-range-thumb {
|
||||
width: 25px; /* Set a specific slider handle width */
|
||||
height: 25px; /* Slider handle height */
|
||||
background: @primary-interaction-highlight-white; /* Green background */
|
||||
cursor: pointer; /* Cursor on hover */
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
session-list-item {
|
||||
border-color: @primary-bg-color-dark;
|
||||
color: @primary-text-color-dark;
|
||||
}
|
||||
|
||||
session-list-item.selected {
|
||||
background-color: @primary-interaction-highlight-dark;
|
||||
}
|
||||
|
||||
.slider-wrap input {
|
||||
background: @editor-bg-dark; /* Grey background */
|
||||
}
|
||||
|
||||
.session-list-item-session-id > span {
|
||||
background-color: @editor-bg-dark;
|
||||
border-color: lighten(@editor-bg-dark, 10%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
import { BaseElement } from '../../../shared/_base';
|
||||
import { CodeEditorContainer } from '../code-editor-container/code-editor-container';
|
||||
import './session-list-item.less';
|
||||
import * as sessionApi from '../../../shared/session-api';
|
||||
import { formatDate } from '../../../shared/date-helper';
|
||||
import { navigateTo } from '../../../shared/navigation';
|
||||
import { getSessionDetailsId } from '../../../shared/page';
|
||||
|
||||
export class SessionListItem extends BaseElement {
|
||||
historyIndex: number | null = null;
|
||||
|
||||
onInit(): void {
|
||||
if (this.hasAttribute("sessionId")) {
|
||||
var sessionIdEle = document.createElement("div");
|
||||
sessionIdEle.classList.add("session-list-item-session-id");
|
||||
sessionIdEle.innerHTML = "<span>" + (this.getAttribute("sessionId")?.toString() ?? "") + "</span>";
|
||||
this.appendChild(sessionIdEle);
|
||||
}
|
||||
|
||||
if (this.hasAttribute("timestamp")) {
|
||||
var timestampEle = document.createElement("div");
|
||||
timestampEle.classList.add("session-list-item-timestamp");
|
||||
timestampEle.innerHTML = formatDate(this.getAttribute("timestamp")?.toString() ?? "");
|
||||
this.appendChild(timestampEle);
|
||||
}
|
||||
|
||||
if (this.hasAttribute("numberOfChanges")) {
|
||||
var numberOfChangesEle = document.createElement("div");
|
||||
numberOfChangesEle.classList.add("session-list-item-number-of-changes");
|
||||
numberOfChangesEle.innerHTML = this.getNumberOfChanges().toString();
|
||||
this.appendChild(numberOfChangesEle);
|
||||
}
|
||||
|
||||
this.addSlider(this.getNumberOfChanges());
|
||||
|
||||
this.addEventListener("click", (evt) => {
|
||||
this.itemClicked();
|
||||
});
|
||||
|
||||
if (this.isUrlSelected()) {
|
||||
this.itemClicked();
|
||||
}
|
||||
}
|
||||
|
||||
getNumberOfChanges() {
|
||||
return parseInt(this.getAttribute("numberOfChanges")?.toString() ?? "0");
|
||||
}
|
||||
|
||||
updateNumberOfChanges(numberOfChanges: number) {
|
||||
this.setAttribute("numberOfChanges", numberOfChanges.toString());
|
||||
this.getElementsByClassName("session-list-item-number-of-changes")[0].innerHTML = (this.historyIndex !== null ? (this.historyIndex + 1) + " / " : "") + numberOfChanges.toString();
|
||||
this.updateSlider(numberOfChanges);
|
||||
}
|
||||
|
||||
private hasSliderChanges: boolean = false;
|
||||
|
||||
private addSlider(numberOfChanges: number) {
|
||||
var sliderEle = document.createElement("div");
|
||||
sliderEle.classList.add("slider-wrap");
|
||||
var sliderInput = document.createElement("input");
|
||||
sliderInput.setAttribute("min", "0");
|
||||
sliderInput.setAttribute("max", (numberOfChanges - 1).toString());
|
||||
sliderInput.setAttribute("type", "range");
|
||||
sliderInput.setAttribute("value", (numberOfChanges - 1).toString());
|
||||
sliderInput.value = (numberOfChanges - 1).toString();
|
||||
|
||||
sliderInput.addEventListener("input", (evt) => {
|
||||
this.hasSliderChanges = true;
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
evt.stopImmediatePropagation();
|
||||
this.historyIndex = parseInt((<any>evt).target.value);
|
||||
|
||||
if (this.historyIndex != null && this.historyIndex >= this.getNumberOfChanges() - 1) {
|
||||
this.historyIndex = null;
|
||||
}
|
||||
|
||||
this.updateNumberOfChanges(this.getNumberOfChanges());
|
||||
this.updateInputs(true);
|
||||
});
|
||||
|
||||
sliderEle.appendChild(sliderInput);
|
||||
this.appendChild(sliderEle);
|
||||
}
|
||||
|
||||
private updateSlider(numberOfChanges: number) {
|
||||
var sliderInput = <HTMLInputElement>this.querySelector(".slider-wrap input");
|
||||
|
||||
if (sliderInput) {
|
||||
|
||||
sliderInput.setAttribute("max", (numberOfChanges - 1).toString());
|
||||
|
||||
if (this.historyIndex == null) {
|
||||
sliderInput.setAttribute("value", (numberOfChanges - 1).toString());
|
||||
sliderInput.value = (numberOfChanges - 1).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private intervalHandle: number | null = null;
|
||||
stopUpdate() {
|
||||
this.classList.remove("selected");
|
||||
this.historyIndex = null;
|
||||
if (this.intervalHandle) {
|
||||
|
||||
this.updateNumberOfChanges(this.getNumberOfChanges());
|
||||
|
||||
if (this.isUrlSelected()) {
|
||||
navigateTo("/sessions");
|
||||
}
|
||||
|
||||
window.clearInterval(this.intervalHandle);
|
||||
this.intervalHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
isUrlSelected(): boolean {
|
||||
var selectedId = getSessionDetailsId();
|
||||
return selectedId === this.getAttribute("sessionId")?.toString()?? "";
|
||||
}
|
||||
|
||||
startUpdate() {
|
||||
this.stopUpdate();
|
||||
|
||||
this.classList.add("selected");
|
||||
|
||||
this.updateInputs();
|
||||
this.intervalHandle = window.setInterval(this.updateInputs.bind(this), 1000);
|
||||
}
|
||||
|
||||
updateInputs(fromCache: boolean = false) {
|
||||
var codeEditorHTMLContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='HTML']");
|
||||
var codeEditorCSSContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='CSS']");
|
||||
var codeEditorJavascriptContainer = <CodeEditorContainer>document.querySelector("code-editor-container[language='Javascript']");
|
||||
|
||||
this.getSessionData((js, html, css) => {
|
||||
codeEditorJavascriptContainer.setInput(js?.data ?? "");
|
||||
codeEditorHTMLContainer.setInput(html?.data ?? "");
|
||||
codeEditorCSSContainer.setInput(css?.data ?? "");
|
||||
}, fromCache);
|
||||
|
||||
}
|
||||
|
||||
private sessionDataCache: any[] = [];
|
||||
getSessionData(onGet: (javascript: any, html: any, css: any) => void, fromCache: boolean = false) {
|
||||
if (fromCache) {
|
||||
const res = this.findLastContent(this.sessionDataCache);
|
||||
onGet(res.lastJavascript, res.lastHtml, res.lastCSS);
|
||||
this.updateNumberOfChanges(this.sessionDataCache.length);
|
||||
}
|
||||
else {
|
||||
sessionApi.getSessionData(this.getAttribute("sessionId")?.toString()?? "", (data) => {
|
||||
this.sessionDataCache = data;
|
||||
const res = this.findLastContent(data);
|
||||
onGet(res.lastJavascript, res.lastHtml, res.lastCSS);
|
||||
this.updateNumberOfChanges(data.length);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private findLastContent(data: any[]) {
|
||||
var lastJavascript: any | null = null;
|
||||
var lastHtml: any | null = null;
|
||||
var lastCSS: any | null = null;
|
||||
|
||||
for (var i = (this.historyIndex != null ? (this.historyIndex + 1) : data.length) - 1; i >= 0; i--) {
|
||||
var dataPoint = data[i];
|
||||
if (!lastJavascript && dataPoint.type == 0) {
|
||||
lastJavascript = dataPoint;
|
||||
}
|
||||
else if (!lastHtml && dataPoint.type == 1) {
|
||||
lastHtml = dataPoint;
|
||||
}
|
||||
else if (!lastCSS && dataPoint.type == 2) {
|
||||
lastCSS = dataPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return { lastJavascript, lastHtml, lastCSS };
|
||||
}
|
||||
|
||||
itemClicked() {
|
||||
if (!this.hasSliderChanges) {
|
||||
if (!this.intervalHandle) {
|
||||
var containers = <HTMLElement>document.getElementsByClassName("code-editor-containers")[0];
|
||||
var outputframe = <HTMLElement>document.getElementsByClassName("output-frame-container")[0];
|
||||
|
||||
containers.style.display = "block";
|
||||
outputframe.style.display = "block";
|
||||
|
||||
navigateTo("/sessions/" + this.getAttribute("sessionId")?.toString()?? "");
|
||||
|
||||
var children = this.parentElement?.children;
|
||||
|
||||
if (children) {
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = <SessionListItem>children[i];
|
||||
if (child != this) {
|
||||
child.stopUpdate();
|
||||
}
|
||||
else {
|
||||
child.startUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.stopUpdate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.hasSliderChanges = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
@import url('../../../shared/theme.less');
|
||||
|
||||
session-list:empty::before {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
color: @primary-text-color-dark;
|
||||
content: "There is no sessions within the last 30 days";
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
session-list {
|
||||
color: @primary-text-color-white;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { BaseElement } from '../../../shared/_base';
|
||||
import './session-list.less';
|
||||
import * as sessionApi from '../../../shared/session-api';
|
||||
import { isSessionPage } from '../../../shared/page';
|
||||
|
||||
export class SessionList extends BaseElement {
|
||||
onInit(): void {
|
||||
|
||||
if (isSessionPage()) {
|
||||
var loadingSpinner = document.createElement("loading-spinner");
|
||||
this.appendChild(loadingSpinner);
|
||||
|
||||
this.setUpdate();
|
||||
|
||||
setInterval(() => {
|
||||
this.setUpdate();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
setUpdate() {
|
||||
|
||||
sessionApi.getSessions((sessions) => {
|
||||
var loadingSpinner = this.getElementsByTagName("loading-spinner")[0];
|
||||
|
||||
if (loadingSpinner) {
|
||||
this.removeChild(loadingSpinner);
|
||||
}
|
||||
|
||||
for (let session of sessions) {
|
||||
var exists = document.querySelector("session-list-item[sessionId='" + session.id + "']");
|
||||
|
||||
if (!exists) {
|
||||
var ele = document.createElement("session-list-item");
|
||||
ele.setAttribute("sessionId", session.id);
|
||||
ele.setAttribute("numberOfChanges", session.numberOfChanges);
|
||||
ele.setAttribute("timestamp", session.timestamp);
|
||||
|
||||
this.appendChild(ele);
|
||||
}
|
||||
//do this in item instead:
|
||||
else {
|
||||
(<any>exists).updateNumberOfChanges(session.numberOfChanges);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ export class WindowControlConnector extends BaseElement {
|
||||
|
||||
if (distTarget) {
|
||||
var visibleTargetChildren = this.visibleChildren(distTarget);
|
||||
console.log(visibleTargetChildren);
|
||||
|
||||
if (visibleTargetChildren.length === 0) {
|
||||
distTarget.classList.add("force-close");
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
<render-canvas></render-canvas>
|
||||
<loading-spinner></loading-spinner>
|
||||
+16
-2
@@ -7,14 +7,26 @@ import { messageListener } from '../shared/message-listener';
|
||||
import { postMessage, postResponseMessage } from '../shared/post-message';
|
||||
import { RenderCanvas } from './elements/render-canvas/render-canvas';
|
||||
import { getCenter, getHeight, getRandom, getWidth, rect, box, getRandomColor } from './injects/dom-helpers';
|
||||
import { setWindowStop } from './injects/window-stop';
|
||||
import { LoadingSpinner } from './elements/loading-spinner/loading-spinner';
|
||||
|
||||
|
||||
window.customElements.define('loading-spinner', LoadingSpinner);
|
||||
window.customElements.define('render-canvas', RenderCanvas);
|
||||
|
||||
document.body.innerHTML += bootHtml;
|
||||
console.log("BOOTING");
|
||||
|
||||
document.body.innerHTML += bootHtml;
|
||||
let consoleLimit = 10;
|
||||
watchConsole((type, value) => {
|
||||
postMessage(parent, type, value);
|
||||
if (consoleLimit > 0) {
|
||||
--consoleLimit;
|
||||
postMessage(parent, type, value.toString());
|
||||
}
|
||||
else if (consoleLimit === 0) {
|
||||
--consoleLimit;
|
||||
postMessage(parent, type, "+ more");
|
||||
}
|
||||
});
|
||||
messageListener((type, value, id) => {
|
||||
if (type == "javascript") {
|
||||
@@ -46,3 +58,5 @@ window.center = getCenter;
|
||||
window.rand = getRandom;
|
||||
//@ts-ignore
|
||||
window.randomColor = getRandomColor;
|
||||
|
||||
setWindowStop();
|
||||
@@ -0,0 +1,32 @@
|
||||
loading-spinner {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
opacity: 0.3;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
loading-spinner::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
animation-name: loadingAnimation;
|
||||
animation-duration: 1s;
|
||||
animation-iteration-count: infinite;
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
@keyframes loadingAnimation {
|
||||
0% {
|
||||
left: 0;
|
||||
}
|
||||
100% {
|
||||
left: calc(100% - 10px);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { BaseElement } from '../../../shared/_base';
|
||||
import './loading-spinner.less';
|
||||
|
||||
export class LoadingSpinner extends BaseElement {
|
||||
onInit(): void {
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
import { NotificationBubbles } from "../../codeeditor-app/elements/notification-bubbles/notification-bubbles";
|
||||
|
||||
export function watchConsole(fn: (type: 'log' | 'info' | 'warn' | 'error', value: any) => void) {
|
||||
export function watchConsole(fn: (type: 'log' | 'info' | 'warn' | 'error', ...value: any[]) => void) {
|
||||
// define a new console
|
||||
var console: any = (function (oldCons) {
|
||||
return {
|
||||
log: function (text: any) {
|
||||
oldCons.log(text);
|
||||
fn('log', text);
|
||||
log: function (...data: any[]) {
|
||||
oldCons.log(...data);
|
||||
fn('log', data);
|
||||
},
|
||||
info: function (text: any) {
|
||||
oldCons.info(text);
|
||||
fn('info', text);
|
||||
info: function (...data: any[]) {
|
||||
oldCons.info(...data);
|
||||
fn('info', data);
|
||||
},
|
||||
warn: function (text: any) {
|
||||
oldCons.warn(text);
|
||||
fn('warn', text);
|
||||
warn: function (...data: any[]) {
|
||||
oldCons.warn(...data);
|
||||
fn('warn', data);
|
||||
},
|
||||
error: function (text: any) {
|
||||
oldCons.error(text);
|
||||
fn('error', text);
|
||||
error: function (...data: any[]) {
|
||||
oldCons.error(...data);
|
||||
fn('error', data);
|
||||
}
|
||||
};
|
||||
}(window.console));
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export function setWindowStop() {
|
||||
setTimeout(() => {
|
||||
window.stop();
|
||||
console.log("window stopped");
|
||||
//throw new Error("window stopped");
|
||||
}, 4 * 1000);
|
||||
}
|
||||
@@ -6,9 +6,39 @@
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<title>output</title>
|
||||
<base href="/" />
|
||||
<style>
|
||||
body {
|
||||
font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 32px;
|
||||
text-align: center;
|
||||
opacity: 0.04;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.center {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="center">
|
||||
codeeditor
|
||||
</div>
|
||||
<script type="text/javascript" src="/output.frame.bundle.js?v=1"></script>
|
||||
</body>
|
||||
|
||||
|
||||
Generated
+5281
-3810
File diff suppressed because it is too large
Load Diff
+20
-21
@@ -13,33 +13,32 @@
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"monaco-editor-core": "0.33.0",
|
||||
"monaco-editor": "^0.33.0",
|
||||
"@types/node": "17.0.21",
|
||||
"@babel/core": "7.17.8",
|
||||
"@webcomponents/custom-elements": "1.5.0",
|
||||
"babel-loader": "8.2.3",
|
||||
"monaco-editor-core": "0.38.0",
|
||||
"monaco-editor": "0.38.0",
|
||||
"@types/node": "20.2.5",
|
||||
"@babel/core": "7.22.1",
|
||||
"@webcomponents/custom-elements": "1.6.0",
|
||||
"babel-loader": "9.1.2",
|
||||
"babel-plugin-transform-custom-element-classes": "0.1.0",
|
||||
"babel-preset-env": "1.7.0",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
"css-loader": "6.7.1",
|
||||
"extract-text-webpack-plugin": "3.0.2",
|
||||
"copy-webpack-plugin": "11.0.0",
|
||||
"css-loader": "6.8.1",
|
||||
"file-loader": "6.2.0",
|
||||
"gulp": "4.0.2",
|
||||
"html-loader": "3.1.0",
|
||||
"less": "4.1.2",
|
||||
"less-loader": "10.2.0",
|
||||
"npm": "8.5.5",
|
||||
"open": "8.4.0",
|
||||
"html-loader": "4.2.0",
|
||||
"less": "4.1.3",
|
||||
"less-loader": "11.1.1",
|
||||
"npm": "9.6.7",
|
||||
"open": "9.1.0",
|
||||
"path": "0.12.7",
|
||||
"replace-in-file-webpack-plugin": "1.0.6",
|
||||
"style-loader": "3.3.1",
|
||||
"ts-loader": "9.2.8",
|
||||
"typescript": "4.6.2",
|
||||
"webpack": "5.70.0",
|
||||
"webpack-cli": "4.9.2",
|
||||
"webpack-dev-server": "4.7.4",
|
||||
"webpack-merge": "5.8.0",
|
||||
"style-loader": "3.3.3",
|
||||
"ts-loader": "9.4.3",
|
||||
"typescript": "5.0.4",
|
||||
"webpack": "5.84.1",
|
||||
"webpack-cli": "5.1.1",
|
||||
"webpack-dev-server": "4.15.0",
|
||||
"webpack-merge": "5.9.0",
|
||||
"raw-loader": "4.0.2",
|
||||
"monaco-editor-webpack-plugin": "7.0.1"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export function formatDate(date: string): string {
|
||||
if (date == "") {
|
||||
return "No date";
|
||||
}
|
||||
var d = new Date(date);
|
||||
return pad(d.getDate()) + "-" + pad(d.getMonth() + 1) + "-" + d.getFullYear() + " " + pad(d.getHours()) + ":" + pad(d.getMinutes());
|
||||
}
|
||||
|
||||
function pad(value: number): string {
|
||||
var strVal = value.toString();
|
||||
|
||||
return strVal.length > 1 ? strVal : "0" + strVal;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
.flex-horiz {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flex-vert {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.flex-horiz > *, .flex-vert > * {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
flex-basis: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.flex-horiz .flex-grow, .flex-vert .flex-grow {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function navigateTo(url: string) {
|
||||
window.history.pushState("", "", url);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export function isSessionPage() {
|
||||
return document.URL.indexOf("/sessions") != -1;
|
||||
}
|
||||
|
||||
export function isRootPage() {
|
||||
return document.URL.indexOf("/sessions") == -1;
|
||||
}
|
||||
|
||||
export function isSessionDetailPage() {
|
||||
return document.URL.indexOf("/sessions") != -1 && document.URL.length > 40;
|
||||
}
|
||||
|
||||
export function getSessionDetailsId() {
|
||||
return document.URL.length > 40 ? document.URL.substring(document.URL.indexOf("/sessions/") + 10) : "";
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export function sanityConvert(code: string, maxLoops: number = 2000) {
|
||||
var beforeCondition = "var conditionCount = " + maxLoops + "; \n";
|
||||
var insideCondition = "\n --conditionCount; \n if (conditionCount <= 0) { break; } \n";
|
||||
|
||||
const regex = /(?<!function.*)(while|for|if)(\s*\((?:[^()]|\([^()]*\))*\)\s*)(.*?{[^}]*}|.*?;)/gs;
|
||||
const output = code.replace(regex, (match, p1, p2, p3) => {
|
||||
let statement = p3.trim();
|
||||
if (statement.startsWith('{') && statement.endsWith('}')) {
|
||||
statement = statement.replace('{', '{' + insideCondition);
|
||||
} else {
|
||||
statement = statement.endsWith(';') ? statement.slice(0, -1) : statement;
|
||||
statement = `{${insideCondition}${statement};}`;
|
||||
}
|
||||
return `${beforeCondition}${p1}${p2}${statement}`;
|
||||
});
|
||||
return output;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
var apiUrl = "https://codeeditor-api.davidssoft.com/";
|
||||
//var apiUrl = "https://codeeditor-api.azurewebsites.net/";
|
||||
|
||||
export function hasSession() {
|
||||
var localstorageSessionId = localStorage.getItem("sessionId");
|
||||
|
||||
if (!localstorageSessionId) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
var expiration = localStorage.getItem("sessionIdExpiration");
|
||||
if (expiration) {
|
||||
return !sessionIsExpired(expiration);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getSessionId() {
|
||||
var localstorageSessionId = localStorage.getItem("sessionId");
|
||||
|
||||
if (!localstorageSessionId) {
|
||||
return setNewSession();
|
||||
}
|
||||
else {
|
||||
var expiration = localStorage.getItem("sessionIdExpiration");
|
||||
|
||||
if (expiration) {
|
||||
if (sessionIsExpired(expiration)) {
|
||||
return setNewSession();
|
||||
}
|
||||
else {
|
||||
localStorage.setItem("sessionIdExpiration", (new Date()).toString());
|
||||
return localstorageSessionId;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return setNewSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sessionIsExpired(expiration: string) {
|
||||
return dateDiff(new Date(expiration), new Date()) > 120;
|
||||
}
|
||||
|
||||
function setNewSession() {
|
||||
var newSessionId = uuidv4();
|
||||
localStorage.setItem("sessionIdExpiration", (new Date()).toString());
|
||||
localStorage.setItem("sessionId", newSessionId);
|
||||
|
||||
return newSessionId;
|
||||
}
|
||||
|
||||
function dateDiff(startTime: Date, endTime: Date) {
|
||||
var difference = endTime.getTime() - startTime.getTime(); // This will give difference in milliseconds
|
||||
var resultInMinutes = Math.round(difference / 60000);
|
||||
return resultInMinutes;
|
||||
}
|
||||
|
||||
function uuidv4() {
|
||||
//@ts-ignore
|
||||
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
export function getSessions(onGet: (sessions: any[]) => void) {
|
||||
fetch(apiUrl + "session/all").then((res) => {
|
||||
res.json().then((jsonRes) => {
|
||||
onGet(jsonRes as any);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function getSessionData(sessionId: string, onGet: (sessions: any[]) => void) {
|
||||
fetch(apiUrl + "session/data/" + sessionId, { method: "GET" }).then((res) => {
|
||||
res.json().then((jsonRes) => {
|
||||
onGet(jsonRes as any);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function setSessionData(language: string, input: any, onSet?: () => void) {
|
||||
var type = 0;
|
||||
|
||||
if (language.toLowerCase() == "javascript") {
|
||||
type = 0;
|
||||
}
|
||||
else if (language.toLowerCase() == "html") {
|
||||
type = 1;
|
||||
}
|
||||
else if (language.toLowerCase() == "css") {
|
||||
type = 2;
|
||||
}
|
||||
else {
|
||||
type = 3;
|
||||
}
|
||||
|
||||
fetch(apiUrl + "session/set", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ sessionId: getSessionId(), timestamp: new Date(), type: type, data: input }) }).then((res) => {
|
||||
if (onSet) {
|
||||
onSet();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -6,11 +6,13 @@ export function IsLocalhost(): boolean {
|
||||
return location.href.indexOf("://localhost") != -1;
|
||||
}
|
||||
|
||||
export function GetOutputFrameUrl(): string {
|
||||
export function GetOutputFrameUrl(path: string = ""): string {
|
||||
var v = "?v=" + (+new Date());
|
||||
if (IsLocalhost()) {
|
||||
return "http://127.0.0.1:8021/";
|
||||
return "http://localhost:8021/" + path + v;
|
||||
}
|
||||
else {
|
||||
return "https://outputframe.davidmeincke.dk/";
|
||||
return "https://outputframe.davidmeincke.dk/" + path + v;
|
||||
//return "https://codeeditoroutput.z16.web.core.windows.net/";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user