added html and css editors
This commit is contained in:
+17
-3
@@ -1,11 +1,25 @@
|
|||||||
<div class="flex-vert">
|
<div class="flex-vert">
|
||||||
<div class="flex-shrink section top">
|
<div class="flex-shrink section top">
|
||||||
code editor
|
<h1>code editor</h1>
|
||||||
|
<window-control>
|
||||||
|
<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>
|
||||||
<div class="flex-horiz">
|
<div class="flex-horiz">
|
||||||
<code-editor style="min-width: 50%; max-width: 50%;"></code-editor>
|
<div class="code-editor-containers resize-target flex-vert" style="min-width: 50%; max-width: 50%;">
|
||||||
|
<code-editor-container language="Javascript" dir="vertical">
|
||||||
|
</code-editor-container>
|
||||||
|
|
||||||
|
<code-editor-container language="HTML" dir="vertical" style="display: none;">
|
||||||
|
</code-editor-container>
|
||||||
|
|
||||||
|
<code-editor-container language="CSS" dir="vertical" style="display: none;">
|
||||||
|
</code-editor-container>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<resize-handle></resize-handle>
|
<resize-handle target=".resize-target" dir="horizontal"></resize-handle>
|
||||||
<output-frame></output-frame>
|
<output-frame></output-frame>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,10 +8,12 @@ html, body {
|
|||||||
background: @median-bg-white;
|
background: @median-bg-white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.flex-horiz {
|
.flex-horiz {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-vert {
|
.flex-vert {
|
||||||
@@ -28,6 +30,10 @@ html, body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.animate .flex-horiz > *, .animate .flex-vert > * {
|
||||||
|
transition: all 280ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
|
.flex-horiz .flex-shrink, .flex-vert .flex-shrink {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
@@ -60,6 +66,16 @@ body {
|
|||||||
|
|
||||||
.section.top {
|
.section.top {
|
||||||
border-bottom: 1px solid @primary-border-color-white;
|
border-bottom: 1px solid @primary-border-color-white;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section.top h1 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: @primary-font-family;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 18px;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section.bottom {
|
.section.bottom {
|
||||||
@@ -69,6 +85,15 @@ body {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-editor-containers {
|
||||||
|
background: @editor-bg-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-editor-containers.force-close {
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
background: @median-bg-dark;
|
background: @median-bg-dark;
|
||||||
@@ -86,4 +111,8 @@ body {
|
|||||||
.section.bottom {
|
.section.bottom {
|
||||||
border-color: @primary-bg-color-dark;
|
border-color: @primary-bg-color-dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-editor-containers {
|
||||||
|
background: @editor-bg-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,9 @@ import { OutputFrame } from './elements/output-frame/output-frame';
|
|||||||
import { NotificationBubbles } from './elements/notification-bubbles/notification-bubbles';
|
import { NotificationBubbles } from './elements/notification-bubbles/notification-bubbles';
|
||||||
import { NotificationBubble } from './elements/notification-bubbles/notification-bubble';
|
import { NotificationBubble } from './elements/notification-bubbles/notification-bubble';
|
||||||
import { ResizeHandle } from './elements/resize-handle/resize-handle';
|
import { ResizeHandle } from './elements/resize-handle/resize-handle';
|
||||||
|
import { CodeEditorContainer } from './elements/code-editor-container/code-editor-container';
|
||||||
|
import { WindowControl } from './elements/window-control/window-control';
|
||||||
|
import { WindowControlConnector } from './elements/window-control/window-control connector';
|
||||||
|
|
||||||
window.customElements.define('app-root', AppRoot);
|
window.customElements.define('app-root', AppRoot);
|
||||||
window.customElements.define('code-editor', CodeEditor);
|
window.customElements.define('code-editor', CodeEditor);
|
||||||
@@ -13,6 +16,9 @@ window.customElements.define('output-frame', OutputFrame);
|
|||||||
window.customElements.define('notification-bubbles', NotificationBubbles);
|
window.customElements.define('notification-bubbles', NotificationBubbles);
|
||||||
window.customElements.define('notification-bubble', NotificationBubble);
|
window.customElements.define('notification-bubble', NotificationBubble);
|
||||||
window.customElements.define('resize-handle', ResizeHandle);
|
window.customElements.define('resize-handle', ResizeHandle);
|
||||||
|
window.customElements.define('code-editor-container', CodeEditorContainer);
|
||||||
|
window.customElements.define('window-control', WindowControl);
|
||||||
|
window.customElements.define('window-control-connector', WindowControlConnector);
|
||||||
|
|
||||||
|
|
||||||
document.body.innerHTML += bootHtml;
|
document.body.innerHTML += bootHtml;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
@import url('../../../shared/theme.less');
|
||||||
|
|
||||||
|
div > code-editor-container.active:last-child {
|
||||||
|
min-height: auto !important;
|
||||||
|
max-height: none !important;
|
||||||
|
min-width: auto !important;
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-editor-header {
|
||||||
|
padding: 10px 18px;
|
||||||
|
background: lighten(@editor-bg-white, 1%);
|
||||||
|
color: @primary-text-color-white;
|
||||||
|
font-size: 13px;
|
||||||
|
border-style: solid none;
|
||||||
|
border-color: @primary-bg-color-white;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.code-editor-header {
|
||||||
|
background: lighten(@editor-bg-dark, 1%);
|
||||||
|
color: @primary-text-color-dark;
|
||||||
|
border-color: @primary-bg-color-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { BaseElement } from "../../../shared/_base";
|
||||||
|
import { CodeEditor } from "../code-editor/code-editor";
|
||||||
|
import { ResizeHandle } from "../resize-handle/resize-handle";
|
||||||
|
import './code-editor-container.less';
|
||||||
|
|
||||||
|
export class CodeEditorContainer extends BaseElement {
|
||||||
|
onInit(): void {
|
||||||
|
var language = this.getAttribute("language");
|
||||||
|
this.classList.add("flex-vert");
|
||||||
|
if (language) {
|
||||||
|
this.setHeader(language);
|
||||||
|
this.createCodeEditor(language, this.getAttribute("dir")?.toLowerCase().indexOf("v") === 0 ? 'vertical' : 'horizontal');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setHeader(title: string) {
|
||||||
|
var div = document.createElement("div");
|
||||||
|
div.classList.add("code-editor-header");
|
||||||
|
div.classList.add("flex-shrink");
|
||||||
|
div.innerText = title;
|
||||||
|
|
||||||
|
this.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
createCodeEditor(language: string, expandDir: 'vertical' | 'horizontal') {
|
||||||
|
var codeEditor = <CodeEditor>document.createElement("code-editor");
|
||||||
|
codeEditor.setAttribute("language", language);
|
||||||
|
var resizeHandle = <ResizeHandle>document.createElement("resize-handle");
|
||||||
|
resizeHandle.setAttribute("dir", expandDir);
|
||||||
|
|
||||||
|
this.appendChild(codeEditor);
|
||||||
|
this.appendChild(resizeHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,24 +2,29 @@ import { BaseElement } from "../../../shared/_base";
|
|||||||
import './code-editor.less';
|
import './code-editor.less';
|
||||||
import * as monaco from 'monaco-editor';
|
import * as monaco from 'monaco-editor';
|
||||||
import { OutputFrame } from "../output-frame/output-frame";
|
import { OutputFrame } from "../output-frame/output-frame";
|
||||||
import initScript from '!!raw-loader!./injects/editor-init.js';
|
import initJs from '!!raw-loader!./injects/editor-init.js';
|
||||||
|
import initHtml from '!!raw-loader!./injects/editor-init.html';
|
||||||
|
import initCss from '!!raw-loader!./injects/editor-init.css';
|
||||||
import spiralBoxesSolutionScript from '!!raw-loader!./injects/spiral-boxes-solution.js';
|
import spiralBoxesSolutionScript from '!!raw-loader!./injects/spiral-boxes-solution.js';
|
||||||
import { debounceManager } from "../../../shared/ensure-debounce";
|
import { debounceManager } from "../../../shared/ensure-debounce";
|
||||||
import declarations from '!!raw-loader!./injects/declarations.d.ts';
|
import declarations from '!!raw-loader!./injects/declarations.d.ts';
|
||||||
|
|
||||||
export class CodeEditor extends BaseElement {
|
export class CodeEditor extends BaseElement {
|
||||||
|
|
||||||
public input: string = initScript;
|
public input: string = "";
|
||||||
|
public language: string = "";
|
||||||
|
|
||||||
onInit(): void {
|
onInit(): void {
|
||||||
|
|
||||||
this.initWorkers();
|
this.initWorkers();
|
||||||
|
this.language = this.getAttribute("language")?.toLocaleLowerCase() ?? "javascript";
|
||||||
|
this.input = this.setInitInput(this.language);
|
||||||
|
|
||||||
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
|
||||||
var editor = monaco.editor.create(this, {
|
var editor = monaco.editor.create(this, {
|
||||||
value: this.input,
|
value: this.input,
|
||||||
language: 'javascript',
|
language: this.language,
|
||||||
automaticLayout: true,
|
automaticLayout: true,
|
||||||
contextmenu: false,
|
contextmenu: false,
|
||||||
minimap: {
|
minimap: {
|
||||||
@@ -29,12 +34,45 @@ export class CodeEditor extends BaseElement {
|
|||||||
theme: prefersDarkScheme.matches ? 'vs-dark' : 'vs-light'
|
theme: prefersDarkScheme.matches ? 'vs-dark' : 'vs-light'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var debounce = debounceManager(1000);
|
||||||
|
editor.onDidChangeModelContent((e) => {
|
||||||
|
this.input = editor.getValue();
|
||||||
|
debounce.ensureDebounce(() => {
|
||||||
|
this.outputFrame.setScript(this.language, this.input);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.waitFor(this.outputFrame, () => {
|
||||||
|
this.outputFrame.setScript(this.language, this.input);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setInitInput(language: string | null) {
|
||||||
|
if (language) {
|
||||||
|
if (language.toLowerCase() === "javascript") {
|
||||||
|
this.initJs();
|
||||||
|
return initJs;
|
||||||
|
}
|
||||||
|
else if (language.toLowerCase() === 'html') {
|
||||||
|
return initHtml;
|
||||||
|
}
|
||||||
|
else if (language.toLowerCase() === 'css') {
|
||||||
|
return initCss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
initJs() {
|
||||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(declarations, 'ts:filename/declarations.d.ts');
|
monaco.languages.typescript.javascriptDefaults.addExtraLib(declarations, 'ts:filename/declarations.d.ts');
|
||||||
|
|
||||||
monaco.languages.registerCompletionItemProvider("javascript", {
|
monaco.languages.registerCompletionItemProvider("javascript", {
|
||||||
triggerCharacters: ["."],
|
provideCompletionItems: (model, position, context, token) => {
|
||||||
provideCompletionItems: (model, position, context, token) => (
|
return {
|
||||||
{
|
|
||||||
suggestions: [
|
suggestions: [
|
||||||
{
|
{
|
||||||
label: 'for',
|
label: 'for',
|
||||||
@@ -60,24 +98,11 @@ export class CodeEditor extends BaseElement {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var debounce = debounceManager(1000);
|
|
||||||
editor.onDidChangeModelContent((e) => {
|
|
||||||
this.input = editor.getValue();
|
|
||||||
debounce.ensureDebounce(() => {
|
|
||||||
this.outputFrame.setScript(this.input);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.waitFor(this.outputFrame, () => {
|
|
||||||
this.outputFrame.setScript(this.input);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
initWorkers() {
|
initWorkers() {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
self.MonacoEnvironment = {
|
self.MonacoEnvironment = {
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
body {
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<div>
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,17 @@
|
|||||||
|
//create a box
|
||||||
box(10, 10, 20, 20);
|
box(10, 10, 20, 20);
|
||||||
|
|
||||||
|
//use random:
|
||||||
box(50, rand(100, 200), 20, 20);
|
box(50, rand(100, 200), 20, 20);
|
||||||
|
|
||||||
|
//use random color:
|
||||||
box(160, 50, 20, 20, randomColor());
|
box(160, 50, 20, 20, randomColor());
|
||||||
box(center(), center(), 20, 20);
|
|
||||||
|
//center method for center of canvas:
|
||||||
|
box(center() - 10, center() - 10, 20, 20);
|
||||||
|
|
||||||
|
//width and height gives canvas size:
|
||||||
|
box(width() - 20, height() - 20, 20, 20);
|
||||||
|
|
||||||
|
//rect will not be connected to boxes:
|
||||||
|
rect(300, 200, 40, 40, "green");
|
||||||
@@ -4,7 +4,7 @@ import { NotificationBubble } from "./notification-bubble";
|
|||||||
import './notification-bubbles.less';
|
import './notification-bubbles.less';
|
||||||
|
|
||||||
export class NotificationBubbles extends BaseElement {
|
export class NotificationBubbles extends BaseElement {
|
||||||
add(text: string, type: 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'script' | 'time' | 'response') {
|
add(text: string, type: 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'script' | 'time' | 'response' | string) {
|
||||||
|
|
||||||
if (text && type) {
|
if (text && type) {
|
||||||
var bubble = <NotificationBubble>document.createElement("notification-bubble");
|
var bubble = <NotificationBubble>document.createElement("notification-bubble");
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import { postMessage } from "../../../shared/post-message";
|
|||||||
|
|
||||||
export class OutputFrame extends BaseElement {
|
export class OutputFrame extends BaseElement {
|
||||||
public Iframe: HTMLIFrameElement | null = null;
|
public Iframe: HTMLIFrameElement | null = null;
|
||||||
public CurrentIframeScriptRemoveResponseListener: Function | null = null;
|
private CurrentIframeScriptRemoveResponseListener: Function | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private scripts: any = {};
|
||||||
|
|
||||||
onInit(): void {
|
onInit(): void {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
@@ -19,7 +21,7 @@ export class OutputFrame extends BaseElement {
|
|||||||
onUpdate(): void {
|
onUpdate(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(resetNotificationBubbles: boolean = true) {
|
reset(onload: ((ev: Event) => void) | null = null, resetNotificationBubbles: boolean = true) {
|
||||||
if (this.CurrentIframeScriptRemoveResponseListener != null) {
|
if (this.CurrentIframeScriptRemoveResponseListener != null) {
|
||||||
this.CurrentIframeScriptRemoveResponseListener();
|
this.CurrentIframeScriptRemoveResponseListener();
|
||||||
this.CurrentIframeScriptRemoveResponseListener = null;
|
this.CurrentIframeScriptRemoveResponseListener = null;
|
||||||
@@ -32,6 +34,13 @@ export class OutputFrame extends BaseElement {
|
|||||||
this.Iframe = document.createElement("iframe");
|
this.Iframe = document.createElement("iframe");
|
||||||
this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin allow-scripts");
|
this.Iframe.setAttribute("sandbox", "allow-pointer-lock allow-same-origin allow-scripts");
|
||||||
this.Iframe.src = GetOutputFrameUrl();
|
this.Iframe.src = GetOutputFrameUrl();
|
||||||
|
|
||||||
|
if (onload) {
|
||||||
|
this.Iframe.onload = ((ev) => {
|
||||||
|
onload(ev);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.appendChild(this.Iframe);
|
this.appendChild(this.Iframe);
|
||||||
|
|
||||||
if (resetNotificationBubbles) {
|
if (resetNotificationBubbles) {
|
||||||
@@ -43,41 +52,34 @@ export class OutputFrame extends BaseElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setError() {
|
setError() {
|
||||||
this.reset();
|
this.reset(() => {
|
||||||
if (this.Iframe) {
|
if (this.Iframe)
|
||||||
this.Iframe.src = GetOutputFrameUrl() + "execution-time-error.html";
|
this.Iframe.src = GetOutputFrameUrl() + "execution-time-error.html";
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preventInfiniteLoop(value: string) {
|
|
||||||
return value.replace("while (true)", "while (false)");
|
|
||||||
}
|
|
||||||
|
|
||||||
setScript(value: string) {
|
|
||||||
this.reset();
|
|
||||||
this.onIframeLoaded(() => {
|
|
||||||
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, "script", value, (executeTimeInMs, exceedTimeInMs) => {
|
|
||||||
if (executeTimeInMs === -1) {
|
|
||||||
this.setError();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var bubbles = GetNotificationBubbles();
|
|
||||||
bubbles.add("code executed in: " + executeTimeInMs + "ms", "info");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onIframeLoaded(fn: Function) {
|
setScript(language: string, value: string) {
|
||||||
if (this.Iframe) {
|
this.scripts[language] = value;
|
||||||
this.Iframe.onload = () => {
|
this.reset(() => {
|
||||||
fn();
|
for (const lang in this.scripts) {
|
||||||
|
if (lang != "javascript")
|
||||||
|
this.doPostMessage(lang, this.scripts[lang]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
if (this.scripts["javascript"])
|
||||||
this.waitFor(this.Iframe, () => {
|
this.doPostMessage("javascript", this.scripts["javascript"]);
|
||||||
this.onIframeLoaded(fn);
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
doPostMessage(language: string, value: string) {
|
||||||
|
this.CurrentIframeScriptRemoveResponseListener = postMessage(this.Iframe?.contentWindow, language, this.scripts[language], language == 'javascript' ? (executeTimeInMs, exceedTimeInMs) => {
|
||||||
|
if (executeTimeInMs === -1) {
|
||||||
|
this.setError();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var bubbles = GetNotificationBubbles();
|
||||||
|
bubbles.add(language + " executed in: " + executeTimeInMs + "ms", "info");
|
||||||
|
}
|
||||||
|
} : undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,20 +2,42 @@
|
|||||||
|
|
||||||
resize-handle {
|
resize-handle {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
position: absolute;
|
position: absolute !important;
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 8px;
|
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
transition: 1s ease-in;
|
transition: 1s ease-in;
|
||||||
|
flex: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
resize-handle:hover {
|
resize-handle[dir="horizontal"] {
|
||||||
|
cursor: ew-resize;
|
||||||
|
width: 8px;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
resize-handle[dir="vertical"] {
|
||||||
|
cursor: ns-resize;
|
||||||
|
height: 8px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
resize-handle:hover, resize-handle.active {
|
||||||
background: @primary-interaction-highlight-white;
|
background: @primary-interaction-highlight-white;
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#fixed-resize-overlay {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
|
|
||||||
resize-handle:hover {
|
resize-handle:hover {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import './resize-handle.less';
|
|||||||
|
|
||||||
export class ResizeHandle extends BaseElement {
|
export class ResizeHandle extends BaseElement {
|
||||||
|
|
||||||
public isDowned = false;
|
|
||||||
|
|
||||||
onInit(): void {
|
onInit(): void {
|
||||||
this.setDragEvents();
|
this.setDragEvents();
|
||||||
@@ -12,54 +11,120 @@ export class ResizeHandle extends BaseElement {
|
|||||||
|
|
||||||
setDragEvents() {
|
setDragEvents() {
|
||||||
this.addEventListener("mousedown", (evt: MouseEvent) => {
|
this.addEventListener("mousedown", (evt: MouseEvent) => {
|
||||||
this.isDowned = true;
|
evt.preventDefault();
|
||||||
this.getIframe().style.display = "none";
|
evt.stopPropagation();
|
||||||
});
|
this.setOverlay({
|
||||||
|
x: evt.pageX,
|
||||||
|
y: evt.pageY
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener("mousemove", (evt: MouseEvent) => {
|
|
||||||
if (this.isDowned) {
|
|
||||||
this.setPosition(evt.pageX);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("mouseup", (evt: MouseEvent) => {
|
|
||||||
if (this.isDowned) {
|
|
||||||
this.getIframe().style.display = "block";
|
|
||||||
this.isDowned = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addEventListener("touchstart", (evt: TouchEvent) => {
|
this.addEventListener("touchstart", (evt: TouchEvent) => {
|
||||||
this.isDowned = true;
|
evt.preventDefault();
|
||||||
this.getIframe().style.display = "none";
|
evt.stopPropagation();
|
||||||
});
|
this.setOverlay({
|
||||||
|
x: evt.touches[0].pageX,
|
||||||
window.addEventListener("touchmove", (evt: TouchEvent) => {
|
y: evt.touches[0].pageY
|
||||||
if (this.isDowned) {
|
});
|
||||||
this.setPosition(evt.touches[0].pageX);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("touchend", (evt: TouchEvent) => {
|
|
||||||
if (this.isDowned) {
|
|
||||||
this.getIframe().style.display = "block";
|
|
||||||
this.isDowned = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPosition(x: number) {
|
setSize(x: number, y: number) {
|
||||||
var t = this.getTarget();
|
var t = this.getTarget();
|
||||||
|
|
||||||
t.style.minWidth = x + "px";
|
if (t) {
|
||||||
t.style.maxWidth = x + "px";
|
if (this.directionIsHorizontal()) {
|
||||||
|
t.style.minWidth = x + "px";
|
||||||
|
t.style.maxWidth = x + "px";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t.style.minHeight = y + "px";
|
||||||
|
t.style.maxHeight = y + "px";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTarget() {
|
getTarget() {
|
||||||
return <CodeEditor>this.find("code-editor");
|
var targetAttr = this.getAttribute("target");
|
||||||
|
if (targetAttr) {
|
||||||
|
var target = <HTMLElement>document.querySelector(targetAttr);
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
directionIsHorizontal() {
|
||||||
|
var attr = this.getAttribute("dir");
|
||||||
|
|
||||||
|
if (attr) {
|
||||||
|
if (attr.toLowerCase().indexOf('v') === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getIframe() {
|
getIframe() {
|
||||||
return <HTMLIFrameElement>this.find("iframe");
|
return <HTMLIFrameElement>this.find("iframe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOverlay(start: { x: number, y: number }) {
|
||||||
|
var overlay = document.createElement("div");
|
||||||
|
overlay.setAttribute("id", "fixed-resize-overlay");
|
||||||
|
|
||||||
|
var targetStartSize = { width: 0, height: 0 };
|
||||||
|
|
||||||
|
var target = this.getTarget();
|
||||||
|
if (target) {
|
||||||
|
var bounds = target.getBoundingClientRect();
|
||||||
|
|
||||||
|
targetStartSize = {
|
||||||
|
width: bounds.width,
|
||||||
|
height: bounds.height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay.addEventListener("mousemove", (evt: MouseEvent) => {
|
||||||
|
this.getIframe().style.pointerEvents = "none";
|
||||||
|
this.classList.add("active");
|
||||||
|
this.setSize(targetStartSize.width + (evt.pageX - start.x), targetStartSize.height + (evt.pageY - start.y));
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.addEventListener("mouseup", (evt: MouseEvent) => {
|
||||||
|
this.getIframe().style.pointerEvents = "all";
|
||||||
|
this.classList.remove("active");
|
||||||
|
this.removeOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.addEventListener("touchmove", (evt: TouchEvent) => {
|
||||||
|
this.getIframe().style.pointerEvents = "none";
|
||||||
|
this.classList.add("active");
|
||||||
|
this.setSize(targetStartSize.width + (start.x - evt.touches[0].pageX), targetStartSize.height + (start.y - evt.touches[0].pageY));
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.addEventListener("touchend", (evt: TouchEvent) => {
|
||||||
|
this.getIframe().style.pointerEvents = "all";
|
||||||
|
this.classList.remove("active");
|
||||||
|
this.removeOverlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.classList.remove("animate");
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeOverlay() {
|
||||||
|
var overlay = document.getElementById("fixed-resize-overlay");
|
||||||
|
|
||||||
|
if (overlay) {
|
||||||
|
overlay.parentElement?.removeChild(overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.classList.add("animate");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { BaseElement } from "../../../shared/_base";
|
||||||
|
import { CodeEditorContainer } from "../code-editor-container/code-editor-container";
|
||||||
|
import './window-control-connector.less';
|
||||||
|
|
||||||
|
export class WindowControlConnector extends BaseElement {
|
||||||
|
|
||||||
|
onInit(): void {
|
||||||
|
this.addEventListener("click", () => {
|
||||||
|
this.toggle();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle() {
|
||||||
|
if (this.classList.contains("active")) {
|
||||||
|
this.deactivate();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activate() {
|
||||||
|
this.classList.add("active");
|
||||||
|
var target = this.getTarget();
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
target.classList.add("active");
|
||||||
|
target.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.distributeEvenly();
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate() {
|
||||||
|
this.classList.remove("active");
|
||||||
|
var target = this.getTarget();
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
target.classList.remove("active");
|
||||||
|
target.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.distributeEvenly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private distributeEvenly() {
|
||||||
|
var elements = <CodeEditorContainer[]>this.findVisible("code-editor-container");
|
||||||
|
var containers = document.getElementsByClassName("code-editor-containers")[0];
|
||||||
|
|
||||||
|
if (elements.length === 0) {
|
||||||
|
containers.classList.add("force-close");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
containers.classList.remove("force-close");
|
||||||
|
var size = (100 / elements.length) + "%";
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
const element = elements[i];
|
||||||
|
|
||||||
|
element.style.minHeight = size;
|
||||||
|
element.style.maxHeight = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTarget() {
|
||||||
|
var attr = this.getAttribute("target");
|
||||||
|
if (attr) {
|
||||||
|
return <HTMLElement>document.querySelector(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
@import url('../../../shared/theme.less');
|
||||||
|
|
||||||
|
window-control {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
window-control-connector {
|
||||||
|
position: relative;
|
||||||
|
font-size: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
background: lighten(@editor-bg-white, 1%);
|
||||||
|
padding: 6px;
|
||||||
|
padding-right: 16px;
|
||||||
|
transition: all 200ms;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
window-control-connector::after {
|
||||||
|
position: absolute;
|
||||||
|
content: "❌";
|
||||||
|
font-size: 8px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
filter: grayscale();
|
||||||
|
top: 4px;
|
||||||
|
right: 4px;
|
||||||
|
transition: all 200ms;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
window-control-connector.active {
|
||||||
|
transform: translateY(7px);
|
||||||
|
}
|
||||||
|
|
||||||
|
window-control-connector.active::after {
|
||||||
|
transform: rotate(0);
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
window-control-connector {
|
||||||
|
background: lighten(@editor-bg-dark, 1%);
|
||||||
|
color: @primary-text-color-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { BaseElement } from "../../../shared/_base";
|
||||||
|
import { WindowControlConnector } from "./window-control connector";
|
||||||
|
|
||||||
|
export class WindowControl extends BaseElement {
|
||||||
|
|
||||||
|
setActive(element: WindowControlConnector) {
|
||||||
|
for (let i = 0; i < this.children.length; i++) {
|
||||||
|
const child = <WindowControlConnector>this.children[i];
|
||||||
|
|
||||||
|
if (element == child) {
|
||||||
|
child.activate();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
child.deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<base href="/" />
|
<base href="/" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body class="animate">
|
||||||
<script type="text/javascript" src="/main.bundle.js?v=1"></script>
|
<script type="text/javascript" src="/main.bundle.js?v=1"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import './app.less';
|
|||||||
import bootHtml from './app.html';
|
import bootHtml from './app.html';
|
||||||
import { watchConsole } from './injects/watch-console';
|
import { watchConsole } from './injects/watch-console';
|
||||||
import { setOnErrorListener } from './injects/on-error';
|
import { setOnErrorListener } from './injects/on-error';
|
||||||
import { createScript } from '../shared/create-script';
|
import { createCss, createHtml, createScript } from '../shared/create-script';
|
||||||
import { messageListener } from '../shared/message-listener';
|
import { messageListener } from '../shared/message-listener';
|
||||||
import { postMessage, postResponseMessage } from '../shared/post-message';
|
import { postMessage, postResponseMessage } from '../shared/post-message';
|
||||||
import { RenderCanvas } from './elements/render-canvas/render-canvas';
|
import { RenderCanvas } from './elements/render-canvas/render-canvas';
|
||||||
@@ -17,10 +17,16 @@ watchConsole((type, value) => {
|
|||||||
postMessage(parent, type, value);
|
postMessage(parent, type, value);
|
||||||
});
|
});
|
||||||
messageListener((type, value, id) => {
|
messageListener((type, value, id) => {
|
||||||
if (type == "script") {
|
if (type == "javascript") {
|
||||||
createScript(value);
|
createScript(value);
|
||||||
postResponseMessage(parent, id, value);
|
postResponseMessage(parent, id, value);
|
||||||
}
|
}
|
||||||
|
else if (type == "html") {
|
||||||
|
createHtml(value);
|
||||||
|
}
|
||||||
|
else if (type == "css") {
|
||||||
|
createCss(value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
setOnErrorListener((type, value) => {
|
setOnErrorListener((type, value) => {
|
||||||
postMessage(parent, type, value);
|
postMessage(parent, type, value);
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ export class RenderCanvas extends BaseElement {
|
|||||||
width: 400,
|
width: 400,
|
||||||
height: 400
|
height: 400
|
||||||
}
|
}
|
||||||
public drawCount: number = 0;
|
private drawCount: number = 0;
|
||||||
public drawQueue: { points: { x: number, y: number }[], color?: string }[] = [];
|
private drawQueue: { points: { x: number, y: number }[], color?: string, connected?: boolean }[] = [];
|
||||||
|
|
||||||
public prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
private prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
|
||||||
private theme: any;
|
private theme: any;
|
||||||
|
|
||||||
@@ -44,10 +44,12 @@ export class RenderCanvas extends BaseElement {
|
|||||||
this.canvas.style.height = smallest + "px";
|
this.canvas.style.height = smallest + "px";
|
||||||
this.canvas.setAttribute("width", smallest.toString());
|
this.canvas.setAttribute("width", smallest.toString());
|
||||||
this.canvas.setAttribute("height", smallest.toString());
|
this.canvas.setAttribute("height", smallest.toString());
|
||||||
|
|
||||||
|
this.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawPoly(points: { x: number, y: number }[], color?: string | CanvasGradient) {
|
private drawPoly(points: { x: number, y: number }[], color?: string | CanvasGradient) {
|
||||||
if (this.ctx && this.canvas) {
|
if (this.ctx && this.canvas) {
|
||||||
this.canvas.style.display = "block";
|
this.canvas.style.display = "block";
|
||||||
if (color instanceof CanvasGradient) {
|
if (color instanceof CanvasGradient) {
|
||||||
@@ -77,7 +79,7 @@ export class RenderCanvas extends BaseElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
centerOf(points: { x: number, y: number }[]) {
|
private centerOf(points: { x: number, y: number }[]) {
|
||||||
var x = 0,
|
var x = 0,
|
||||||
y = 0,
|
y = 0,
|
||||||
i,
|
i,
|
||||||
@@ -99,7 +101,7 @@ export class RenderCanvas extends BaseElement {
|
|||||||
return { x: x / f, y: y / f };
|
return { x: x / f, y: y / f };
|
||||||
};
|
};
|
||||||
|
|
||||||
areaOf(points: { x: number, y: number }[]) {
|
private areaOf(points: { x: number, y: number }[]) {
|
||||||
var area = 0,
|
var area = 0,
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
@@ -117,50 +119,42 @@ export class RenderCanvas extends BaseElement {
|
|||||||
return area;
|
return area;
|
||||||
};
|
};
|
||||||
|
|
||||||
angleBetweenPoints(point1: { x: number, y: number }, point2: { x: number, y: number }) {
|
private angleBetweenPoints(point1: { x: number, y: number }, point2: { x: number, y: number }) {
|
||||||
// angle in radians
|
|
||||||
var angleRadians = Math.atan2(point2.y - point1.y, point2.x - point1.x);
|
|
||||||
|
|
||||||
// angle in degrees
|
|
||||||
return Math.atan2(point2.y - point1.y, point2.x - point1.x) * 180 / Math.PI;
|
return Math.atan2(point2.y - point1.y, point2.x - point1.x) * 180 / Math.PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
executeDrawQueue() {
|
draw() {
|
||||||
let prevShape: any | null = null;
|
let prevConnectedShape: any | null = null;
|
||||||
for (let i = 0; i < this.drawQueue.length; i++) {
|
for (let i = 0; i < this.drawQueue.length; i++) {
|
||||||
const shape = this.drawQueue[i];
|
const shape = this.drawQueue[i];
|
||||||
|
|
||||||
if (prevShape != null && this.ctx) {
|
if (shape.connected && prevConnectedShape != null && this.ctx) {
|
||||||
var prevCenter = this.centerOf(prevShape.points);
|
var prevCenter = this.centerOf(prevConnectedShape.points);
|
||||||
var thisCenter = this.centerOf(shape.points);
|
var thisCenter = this.centerOf(shape.points);
|
||||||
|
|
||||||
var middle = {
|
|
||||||
x: (prevCenter.x + thisCenter.x) / 2,
|
|
||||||
y: (prevCenter.y + thisCenter.y) / 2
|
|
||||||
};
|
|
||||||
|
|
||||||
var grd = this.ctx.createLinearGradient(this.unitsToPx(prevCenter.x), this.unitsToPx(prevCenter.y), this.unitsToPx(thisCenter.x), this.unitsToPx(thisCenter.y));
|
var grd = this.ctx.createLinearGradient(this.unitsToPx(prevCenter.x), this.unitsToPx(prevCenter.y), this.unitsToPx(thisCenter.x), this.unitsToPx(thisCenter.y));
|
||||||
grd.addColorStop(0, prevShape?.color ?? this.getColor());
|
grd.addColorStop(0, prevConnectedShape?.color ?? this.getColor());
|
||||||
grd.addColorStop(1, shape?.color ?? this.getColor());
|
grd.addColorStop(1, shape?.color ?? this.getColor());
|
||||||
|
|
||||||
this.drawPoly([prevCenter, thisCenter], grd);
|
this.drawPoly([prevCenter, thisCenter], grd);
|
||||||
|
|
||||||
//this.drawPoly([prevCenter, middle], prevShape.color);
|
|
||||||
//this.drawPoly([middle, thisCenter], shape.color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevShape = shape;
|
if (shape.connected) {
|
||||||
|
prevConnectedShape = shape;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this.drawQueue.length; i++) {
|
for (let i = 0; i < this.drawQueue.length; i++) {
|
||||||
const shape = this.drawQueue[i];
|
const shape = this.drawQueue[i];
|
||||||
this.drawPoly(shape.points, shape.color);
|
this.drawPoly(shape.points, shape.color);
|
||||||
var thisCenter = this.centerOf(shape.points);
|
var thisCenter = this.centerOf(shape.points);
|
||||||
this.drawText(thisCenter.x, thisCenter.y, (i + 1).toString(), this.unitsToPx((shape.points[1].x - shape.points[0].x) * 0.6), shape.color);
|
if (shape.connected) {
|
||||||
|
this.drawText(thisCenter.x, thisCenter.y, (i + 1).toString(), this.unitsToPx((shape.points[1].x - shape.points[0].x) * 0.6), shape.color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawText(x: number, y: number, text: string, size: number = 20, color?: string) {
|
private drawText(x: number, y: number, text: string, size: number = 20, color?: string) {
|
||||||
if (this.ctx && this.canvas) {
|
if (this.ctx && this.canvas) {
|
||||||
this.ctx.moveTo(x, y);
|
this.ctx.moveTo(x, y);
|
||||||
this.ctx.fillStyle = this.getColor(color);
|
this.ctx.fillStyle = this.getColor(color);
|
||||||
@@ -171,27 +165,23 @@ export class RenderCanvas extends BaseElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getColor(color?: string) {
|
private getColor(color?: string) {
|
||||||
return color ? color : (this.prefersDarkScheme.matches ? this.theme["@draw-color-dark"] : this.theme["@draw-color-white"]);
|
return color ? color : (this.prefersDarkScheme.matches ? this.theme["@draw-color-dark"] : this.theme["@draw-color-white"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBackgroundColor() {
|
private getBackgroundColor() {
|
||||||
return this.prefersDarkScheme.matches ? this.theme["@median-bg-dark"] : this.theme["@median-bg-white"];
|
return this.prefersDarkScheme.matches ? this.theme["@median-bg-dark"] : this.theme["@median-bg-white"];
|
||||||
}
|
}
|
||||||
|
|
||||||
drawRect(x: number, y: number, width: number, height: number, color?: string) {
|
poly(points: { x: number, y: number }[], color?: string) {
|
||||||
this.drawPoly([{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color);
|
|
||||||
}
|
|
||||||
|
|
||||||
queuePoly(points: { x: number, y: number }[], color?: string) {
|
|
||||||
this.drawQueue.push({ points: points, color: color });
|
this.drawQueue.push({ points: points, color: color });
|
||||||
}
|
}
|
||||||
|
|
||||||
queueRect(x: number, y: number, width: number, height: number, color?: string) {
|
rect(x: number, y: number, width: number, height: number, color?: string, connected?: boolean) {
|
||||||
this.drawQueue.push({ points: [{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color: color });
|
this.drawQueue.push({ points: [{ x: x, y: y }, { x: x + width, y: y }, { x: x + width, y: y + height }, { x: x, y: y + height }], color: color, connected: connected });
|
||||||
}
|
}
|
||||||
|
|
||||||
unitsToPx(unitNumber: number) {
|
private unitsToPx(unitNumber: number) {
|
||||||
var newPPU = Math.min(this.width, this.height) / this.units.width;
|
var newPPU = Math.min(this.width, this.height) / this.units.width;
|
||||||
return Math.floor(unitNumber * newPPU);
|
return Math.floor(unitNumber * newPPU);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ export function clear() {
|
|||||||
|
|
||||||
export function rect(x: number, y: number, width: number, height: number, color?: string): void {
|
export function rect(x: number, y: number, width: number, height: number, color?: string): void {
|
||||||
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
||||||
renderCanvas.drawRect(x, y, width, height, color);
|
renderCanvas.rect(x, y, width, height, color, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function box(x: number, y: number, width: number, height: number, color?: string): void {
|
export function box(x: number, y: number, width: number, height: number, color?: string): void {
|
||||||
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
||||||
renderCanvas.queueRect(x, y, width, height, color);
|
renderCanvas.rect(x, y, width, height, color, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWidth(): number {
|
export function getWidth(): number {
|
||||||
@@ -35,7 +35,7 @@ export function getRandom(min: number, max: number): number {
|
|||||||
|
|
||||||
export function executeDrawQueue(): void {
|
export function executeDrawQueue(): void {
|
||||||
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
var renderCanvas = <RenderCanvas>document.getElementsByTagName("render-canvas")[0];
|
||||||
renderCanvas.executeDrawQueue();
|
renderCanvas.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRandomColor(): string {
|
export function getRandomColor(): string {
|
||||||
|
|||||||
@@ -68,6 +68,22 @@ export class BaseElement extends HTMLElement {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findVisible(tagName: string) {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
var elements = document.getElementsByTagName(tagName);
|
||||||
|
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
const element = <HTMLElement>elements[i];
|
||||||
|
|
||||||
|
if (element.style.display !== "none") {
|
||||||
|
result.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
hasChild(element: Element, startsWidth: boolean = false): boolean {
|
hasChild(element: Element, startsWidth: boolean = false): boolean {
|
||||||
var ele = this;
|
var ele = this;
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,17 @@ export function createScript(value: string) {
|
|||||||
|
|
||||||
executeDrawQueue();
|
executeDrawQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createHtml(value: string) {
|
||||||
|
var div: HTMLDivElement = document.createElement("div");
|
||||||
|
div.innerHTML = value;
|
||||||
|
|
||||||
|
document.body.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createCss(value: string) {
|
||||||
|
var style: HTMLStyleElement = document.createElement("style");
|
||||||
|
style.innerHTML = value;
|
||||||
|
|
||||||
|
document.body.appendChild(style);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export function messageListener(fn: (type: 'script' | 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'time' | 'response', value: string, id: number) => void): Function {
|
export function messageListener(fn: (type: 'script' | 'log' | 'info' | 'warn' | 'error' | 'syntax-error' | 'time' | 'response' | string, value: string, id: number) => void): Function {
|
||||||
|
|
||||||
var evt = function(e: any) {
|
var evt = function(e: any) {
|
||||||
if (!e.data || e.data === '' || e.data.type === 'webpackOk') {
|
if (!e.data || e.data === '' || e.data.type === 'webpackOk') {
|
||||||
|
|||||||
Reference in New Issue
Block a user