Skip to content

Instantly share code, notes, and snippets.

Marijn Haverbeke marijnh

Block or report user

Report or block marijnh

Hide content and notifications from this user.

Learn more about blocking users

Contact Support about this user’s behavior.

Learn more about reporting abuse

Report abuse
View GitHub Profile
View pixel.js
# Clean UI programming in a vacuum
This app was written for Chapter 19 in the 3rd edition of Eloquent
JavaScript—it aims to demonstrate modern UI programming without
depending on a specific framework or library.
Its convention is that components have an interface like this:

(This is a response to that didn't fit in a tweet.)

CodeMirror uses a largely similar approach, with a somewhat different framing.

Firstly, it stores the mode (highlighter) state directly in the document data structure (which I probably wouldn't do again if I were to redesign this), not in a separate cache. Each line can have an optional 'highlight state after this line' field. During highlighting, a cached state is left every N lines.

The frontier is simply the line number up to which point highlighting has happened. When you edit above the frontier, it it moved back to the line before the change.

Highlighting never proceeds past the end of the viewport. So startup is cheap (only highlight the first screenful), and in the 99% case of changes happening inside the viewport, re-highlighting complexity is bounded by the size of the viewport, since only the area between the change and the end of the viewport needs to be proces

View gist:209c896ac96db277765bdb93ab3f52f3
Never see JavaDoc again
Inline documentation is great. JSDoc/JavaDoc syntax is an acquired taste that I never managed to acquire. So I want to show you an alternative tool with alternative syntax that I wrote.
marijnh / node-view.js
Created Oct 28, 2016
Demo of a ProseMirror editor that uses a nested code editor
View node-view.js
const {EditorState, Selection} = require("prosemirror-state")
const {MenuBarEditorView} = require("prosemirror-menu")
const {DOMParser, DOMSerializer, Schema} = require("prosemirror-model")
const {schema: baseSchema} = require("prosemirror-schema-basic")
const {exampleSetup} = require("prosemirror-example-setup")
const {keymap} = require("prosemirror-keymap")
const CodeMirror = require("codemirror")
let view, menuView, schema = new Schema({
marijnh / checkanchors.js
Created Oct 21, 2016
Check a page for dangling links to local anchors
View checkanchors.js
let links = document.querySelectorAll("a[href]")
let base = /^[^#]*/.exec(document.location)[0] + "#"
for (let i = 0; i < links.length; i++) {
let link = links[i], anchor
if (link.href.indexOf(base) == 0 && !document.getElementById(anchor = decodeURIComponent(link.href.slice(base.length))))
console.log("Missing anchor: " + anchor)
marijnh / changedRanges.js
Created Aug 17, 2016
Compute changed range from ProseMirror steps
View changedRanges.js
function changedRanges(history, group) {
let ranges = []
history.forEach((step, i) => {
let map = step.posMap()
ranges = => {
let from =, 1), to = Math.max(from,, -1))
return {from, to}
if (group.indexOf(i) > -1) {
let newRanges = []
marijnh / test.html
Created Apr 16, 2016
Mobile Safari keyboard issue
View test.html
<!doctype html>
<div contenteditable=true style="border: 1px solid black">Foo bar</div>
<p>Put the cursor at the start of the editable content above, so
that the keyboard is in uppercase mode. Then press <button>this
button</button> to move the cursor to the end of 'foo'. Note that the
keyboard stays in uppercase mode althrough lowercase would be
appropriate for the new context.</p>
marijnh / highlight.js
Last active Mar 13, 2017
Word highlighting in ProseMirror
View highlight.js
import {Pos} from "../src/model"
function rangeFromTransform(tr) {
let from, to
for (let i = 0; i < tr.steps.length; i++) {
let step = tr.steps[i], map = tr.maps[i]
let stepFrom = || step.pos, -1).pos
let stepTo = || step.pos, 1).pos
from = from ?, -1).pos.min(stepFrom) : stepFrom
to = to ?, 1).pos.max(stepTo) : stepTo
View merge-demo.html
<!doctype html>
<title>CodeMirror: merge view demo</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../doc/docs.css">
<link rel=stylesheet href="../lib/codemirror.css">
<link rel=stylesheet href="../addon/merge/merge.css">
<script src="//"></script>
View cocos.json
"!name": "node_modules/cocos2d/src/global.js",
"!define": {
"String.prototype._observingFunctions.<i>": {
"!span": "4511[148:60]-4552[148:101]"
"util.each.!1": {
"!type": "fn(mod: string|?, i: number)",
"!span": "9868[339:27]-10050[342:9]"
You can’t perform that action at this time.