Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two new editor workloads #81

Merged
merged 15 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/node_modules

/resources/tentative
**/dist
/resources/tentative/*
!/resources/tentative/editors
/resources/todomvc
26 changes: 26 additions & 0 deletions resources/tentative/editors/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

node_modules

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
27 changes: 27 additions & 0 deletions resources/tentative/editors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Description

Lots of people edit text content in the browser. Lots of that content, like WYSIWYG content or code, is too rich or complex to represent well with a `<textarea>`. Sites typically rely on advanced editor libraries for this, and we should make sure browsers perform well common patterns used by them.

## Screenshot

![screenshot](./screenshot.jpg)

## What are we testing

- Basic DOM and editing
- Virtualization (DOM content changing during scroll)
- Basic flex layout with SVG icons

## How are we testing

The test simulates a real-world user flow by loading a number of popular editor libraries. After the initial load is complete, the following steps are timed:

- Setting to a fairly large value
- "Formatting" the text - in code editors this means turning on syntax highlighting, and in WYSISWYG this means bolding all of the contents
- Scrolling to the bottom of the editor

## Developer Documentation

The app was created with `npm create vite@latest editors`, and can be previewed with `npm run dev`. In order to update the files run in the harness you have to use `npm run build` which will recreate the `dist/` directory.

The built test can be loaded within the harness using i.e. http://localhost:7000/?suite=Editor-CodeMirror&startAutomatically=true, or the static versions at http://localhost:7000/resources/tentative/editors/dist/.
136 changes: 136 additions & 0 deletions resources/tentative/editors/bigtext.js

Large diffs are not rendered by default.

200 changes: 200 additions & 0 deletions resources/tentative/editors/codemirror.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<title>CodeMirror Test</title>
</head>
<body>
<div id="app">
<div id="controls">
<button id="create">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-square-plus" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"></path>
<path d="M9 12l6 0"></path>
<path d="M12 9l0 6"></path>
</svg>
Create
</button>
&nbsp;
<button id="big">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-arrow-big-up-lines-filled"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path
d="M10.586 3l-6.586 6.586a2 2 0 0 0 -.434 2.18l.068 .145a2 2 0 0 0 1.78 1.089h2.586v2a1 1 0 0 0 1 1h6l.117 -.007a1 1 0 0 0 .883 -.993l-.001 -2h2.587a2 2 0 0 0 1.414 -3.414l-6.586 -6.586a2 2 0 0 0 -2.828 0z"
stroke-width="0"
fill="currentColor"
></path>
<path d="M15 20a1 1 0 0 1 .117 1.993l-.117 .007h-6a1 1 0 0 1 -.117 -1.993l.117 -.007h6z" stroke-width="0" fill="currentColor"></path>
<path d="M15 17a1 1 0 0 1 .117 1.993l-.117 .007h-6a1 1 0 0 1 -.117 -1.993l.117 -.007h6z" stroke-width="0" fill="currentColor"></path>
</svg>
Big text
</button>
<button id="small">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-arrow-big-down-lines-filled"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path
d="M9 8l-.117 .007a1 1 0 0 0 -.883 .993v1.999l-2.586 .001a2 2 0 0 0 -1.414 3.414l6.586 6.586a2 2 0 0 0 2.828 0l6.586 -6.586a2 2 0 0 0 .434 -2.18l-.068 -.145a2 2 0 0 0 -1.78 -1.089l-2.586 -.001v-1.999a1 1 0 0 0 -1 -1h-6z"
stroke-width="0"
fill="currentColor"
></path>
<path d="M15 2a1 1 0 0 1 .117 1.993l-.117 .007h-6a1 1 0 0 1 -.117 -1.993l.117 -.007h6z" stroke-width="0" fill="currentColor"></path>
<path d="M15 5a1 1 0 0 1 .117 1.993l-.117 .007h-6a1 1 0 0 1 -.117 -1.993l.117 -.007h6z" stroke-width="0" fill="currentColor"></path>
</svg>
Small text
</button>
&nbsp;
<button id="highlight">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-highlight" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 19h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4"></path>
<path d="M12.5 5.5l4 4"></path>
<path d="M4.5 13.5l4 4"></path>
<path d="M21 15v4h-8l4 -4z"></path>
</svg>
Highlight
</button>
<button id="unhighlight">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-highlight-off"
width="24"
height="24"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M9 9l-6 6v4h4l6 -6m2 -2l2.503 -2.503a2.828 2.828 0 1 0 -4 -4l-2.497 2.497"></path>
<path d="M12.5 5.5l4 4"></path>
<path d="M4.5 13.5l4 4"></path>
<path d="M19 15h2v2m-2 2h-6l3 -3"></path>
<path d="M3 3l18 18"></path>
</svg>
Unhighlight
</button>
&nbsp;
<button id="scroll">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-line-height" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M3 8l3 -3l3 3"></path>
<path d="M3 16l3 3l3 -3"></path>
<path d="M6 5l0 14"></path>
<path d="M13 6l7 0"></path>
<path d="M13 12l7 0"></path>
<path d="M13 18l7 0"></path>
</svg>
Scroll
</button>
&nbsp;
<button id="layout">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-refresh-dot" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4"></path>
<path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"></path>
<path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
</svg>
</button>
</div>
<div id="editor"></div>
</div>
<script type="module">
import { code as smalltext } from "./smalltext.js";
import { code as bigtext } from "./bigtext.js";
import editor from "./codemirror.js";

let editorContainer = document.querySelector("#editor");
let editorInstance = null;
let editorPromise = null;

let buttons = {
create: document.querySelector("#create"),
highlight: document.querySelector("#highlight"),
unhighlight: document.querySelector("#unhighlight"),
big: document.querySelector("#big"),
small: document.querySelector("#small"),
scroll: document.querySelector("#scroll"),
layout: document.querySelector("#layout"),
};
buttons.scroll.addEventListener("click", scroll);
buttons.highlight.addEventListener("click", highlight);
buttons.unhighlight.addEventListener("click", unhighlight);
buttons.big.addEventListener("click", big);
buttons.small.addEventListener("click", small);
buttons.layout.addEventListener("click", layout);

buttons.create.addEventListener("click", (e) => {
if (!editorPromise) {
editorPromise = editor(editorContainer);
editorPromise.then((instance) => {
editorInstance = instance;
editorInstance.ready.then(() => {
buttons.unhighlight.classList.add("active", "true");
buttons.create.setAttribute("disabled", "true");
});
});
}
});

function layout() {
// Todo - is this necessary with the runner?
const body = document.body.getBoundingClientRect();
layout.e = document.elementFromPoint((body.width / 2) | 0, (body.height / 2) | 0);
}

function highlight() {
buttons.unhighlight.classList.toggle("active", false);
buttons.highlight.classList.toggle("active", true);
editorInstance.format(true);
}
function unhighlight() {
buttons.unhighlight.classList.toggle("active", true);
buttons.highlight.classList.toggle("active", false);
editorInstance.format(false);
}
function big() {
buttons.small.classList.toggle("active", false);
buttons.big.classList.toggle("active", true);
editorInstance.setValue(bigtext);
}
function small() {
buttons.small.classList.toggle("active", true);
buttons.big.classList.toggle("active", false);
editorInstance.setValue(smalltext);
}

function scroll() {
let isTop = editorInstance.getScrollTop() == 0;
editorInstance.setScrollTop(isTop ? editorInstance.getScrollHeight() : 0);
}
</script>
</body>
</html>
47 changes: 47 additions & 0 deletions resources/tentative/editors/codemirror.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// https://codemirror.net/examples/bundle/
import { EditorView, basicSetup } from "codemirror";
import { StateEffect } from "@codemirror/state";
import { javascript } from "@codemirror/lang-javascript";

let lang = javascript();
let extensions = [basicSetup, EditorView.lineWrapping];

export default async function (element, value) {
let view = new EditorView({
extensions,
parent: element,
doc: value,
wordWrapColumn: 80,
});

return {
editor: view,
// Anything before this promise resolves will happen before timing starts
ready: Promise.resolve(),
getScrollHeight() {
return element.scrollHeight;
},
getScrollTop() {
return element.scrollTop;
},
setScrollTop(value) {
element.scrollTop = value;
},
setValue: (value) =>
view.dispatch({
changes: { from: 0, to: view.state.doc.length, insert: value },
}),
format(on) {
// https://codemirror.net/examples/config/
// https://discuss.codemirror.net/t/cm6-dynamically-switching-syntax-theme-w-reconfigure/2858/6
if (on && extensions.length == 2) {
extensions.push(lang);
} else if (!on && extensions.length == 3) {
extensions.pop();
}
view.dispatch({
effects: StateEffect.reconfigure.of(extensions),
});
},
};
}
23 changes: 23 additions & 0 deletions resources/tentative/editors/dist/assets/codemirror-69dbb079.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions resources/tentative/editors/dist/assets/index-1f3d4316.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading