RepoPilotOpen in app →

yabwe/medium-editor

Medium.com WYSIWYG editor clone. Uses contenteditable API to implement a rich text solution.

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyFailing

non-standard license (Other); last commit was 2y ago

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 24+ active contributors
  • Distributed ownership (top contributor 21% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • Stale — last commit 2y ago
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency FailingMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Earn the “Healthy” badge

Current signals for yabwe/medium-editor are Mixed. The embed flow is reserved for repos showing Healthy signals — the rest stay informational on this page so we're not putting a public call-out on your README. Address the items in the What would change the summary? dropdown above, then return to grab the embed code.

Common quick wins: green CI on default branch, no Critical CVEs in dependencies, recent commits on the default branch, a permissive license, and a published README.md with a quickstart.

Onboarding doc

Onboarding: yabwe/medium-editor

Generated by RepoPilot · 2026-05-06 · Source

Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/yabwe/medium-editor shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verdict

WAIT — Stale — last commit 2y ago

  • 24+ active contributors
  • Distributed ownership (top contributor 21% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Non-standard license (Other) — review terms

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live yabwe/medium-editor repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/yabwe/medium-editor.

What it runs against: a local clone of yabwe/medium-editor — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in yabwe/medium-editor | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | Last commit ≤ 589 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>yabwe/medium-editor</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of yabwe/medium-editor. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/yabwe/medium-editor.git
#   cd medium-editor
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of yabwe/medium-editor and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "yabwe/medium-editor(\\.git)?\\b" \\
  && ok "origin remote is yabwe/medium-editor" \\
  || miss "origin remote is not yabwe/medium-editor (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 589 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~559d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/yabwe/medium-editor"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

MediumEditor is a vanilla JavaScript WYSIWYG rich-text editor that replicates Medium.com's inline editing toolbar, using the contenteditable API to enable formatted text editing directly in the browser without external dependencies or frameworks. Modular extension-based architecture: core editor in src/ manages contenteditable state and selection, toolbar extensions live in src/extensions/ (Button.js, Toolbar.js, etc.), dist/ contains pre-built bundles and themed CSS (default.css, bootstrap.css, beagle.css), and demo/ contains 15+ isolated demo files showing different configurations (multi-editor, nested-editable, auto-link, etc).

Who it's for

Web developers building content management systems, blogging platforms, or editorial tools who need a lightweight, dependency-free rich-text editor with Medium-style UX and customizable toolbars.

Maturity & risk

Production-ready but seeking maintainers: v5.23.3 is well-established with comprehensive browser support (via SauceLabs), TravisCI/Karma test infrastructure, and coveralls coverage tracking. However, the README explicitly calls for help maintaining the project (issue #1503), suggesting the maintainer team is stretched thin despite the project's maturity.

Single-maintainer risk is explicit (README banner asking for help). While no external npm dependencies exist (pure vanilla JS), the codebase is 881KB of JavaScript with tight coupling to contenteditable API quirks, making browser compatibility a constant concern. Check last commit date before adopting for new projects.

Active areas of work

Project is in maintenance mode awaiting new maintainers. No visible active development branch indicated in the file list, but the CHANGES.md and UPGRADE-5.md suggest past releases. Check the GitHub issues board and #1503 for context on current needs.

Get running

git clone https://github.com/yabwe/medium-editor.git
cd medium-editor
npm install
git checkout the dist/ folder or npm run build (inferred from Gruntfile.js)

Daily commands:

npm install
grunt (default Gruntfile.js task likely watches and serves demo)
grunt test (runs Karma/Jasmine suite)
open demo/index.html in browser or use grunt-contrib-connect dev server

Map of the codebase

  • src/js/MediumEditor.js: Main editor class that orchestrates contenteditable management, selection handling, and event delegation for the entire editor instance
  • src/js/extensions/toolbar.js: Core toolbar extension responsible for positioning and rendering the floating formatting toolbar that appears on text selection
  • src/js/extensions/button.js: Base button extension class; all toolbar buttons (bold, italic, link, etc.) extend this to implement format commands
  • src/js/util/selection.js: Selection and range manipulation utilities; critical for tracking cursor position and applying formatting to selected text
  • src/css/medium-editor.scss: Main stylesheet defining editor container, contenteditable area styles, and toolbar appearance; compiled to dist/css/medium-editor.css
  • API.md: Complete API reference for instantiation, configuration options, methods, and events needed to integrate editor into applications
  • Gruntfile.js: Build configuration controlling browserify bundling, minification, SCSS compilation, Karma test runner, and dist output
  • demo/index.html: Primary demo showing basic editor setup; reference point for understanding expected DOM structure and instantiation patterns

How to make changes

Extension additions: create files in src/extensions/ following the Button.js or Toolbar.js pattern. Toolbar customization: OPTIONS.md details the toolbar config. Themes: create new CSS files in dist/css/themes/ following the pattern of default.css. Demos: add new .html files to demo/ directory. Tests: add .spec.js files in test/ directory following Jasmine convention (grep the existing spec files for structure).

Traps & gotchas

  1. contenteditable behavior varies significantly across browsers (see extensive browser matrix tests) — fixes often require user-agent detection. 2) Grunt build pipeline is required; the src/ directory contains uncompiled modules that must be bundled to dist/ for use. 3) The toolbar positioning logic uses absolute/fixed positioning; nested editable containers (see demo/nested-editable.html) can break toolbar placement without careful parent container setup. 4) Selection state is fragile in IE/Edge; Selection.js handles restoration across focus loss. 5) No CommonJS exports visible in src/ files — they appear to rely on browserify transforms during build.

Concepts to learn

  • contenteditable API — The fundamental browser API that enables in-place text editing and formatting; understanding its quirks (different behavior across browsers, selection restoration, undo/redo) is essential to maintaining this editor
  • Range and Selection Objects — Core to MediumEditor's ability to track cursor position, highlight text, and apply formatting; the selection.js utility wraps these APIs, and bugs here cascade to all formatting commands
  • Document.execCommand() — Legacy but still-necessary browser API that applies formatting commands (bold, italic, createLink, etc.) to selected text; MediumEditor abstracts this for cross-browser compatibility
  • Toolbar Positioning (absolute/fixed layout) — MediumEditor floats the toolbar above selected text using absolute positioning; understanding document flow, parent container context, and scroll event handling is critical to preventing toolbar placement bugs
  • Extension Plugin Pattern — MediumEditor's architecture relies on extensions (Button, Toolbar, etc.) that register handlers and lifecycle methods; understanding how extensions bind to the editor instance is necessary for adding new formatting tools
  • Cross-browser Compatibility Testing (SauceLabs/Karma) — This project uses SauceLabs + Karma to test across IE, Chrome, Firefox, Safari, Edge; understanding why each browser requires special handling (especially IE's broken Range API) is essential context for fixes
  • Browserify Module Bundling — The src/ files use CommonJS modules that must be bundled via Gruntfile.js; understanding the build pipeline is necessary to develop locally and test changes before dist/ release

Related repos

  • facebook/draft-js — React-based rich-text editor framework using immutable state model; alternative for teams already in React ecosystem who want more structured content representation
  • basecamp/trix — Basecamp's dependency-free WYSIWYG editor with similar vanilla JS philosophy but includes built-in file upload and block-level composition model
  • ProseMirror/prosemirror — Highly extensible collaborative rich-text editor with pluggable schema; heavier than MediumEditor but handles complex document structures and real-time sync
  • ckeditor/ckeditor5 — Enterprise-grade WYSIWYG editor with modular architecture; more feature-rich than MediumEditor but adds framework overhead and licensing complexity
  • yabwe/medium-editor-extensions — Community extension repository (if it exists) showing how to build custom toolbar buttons, plugins, and behaviors on top of MediumEditor

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for contenteditable edge cases in spec/content.spec.js

The repo has spec files but content.spec.js likely has gaps covering contenteditable API interactions (cursor positioning, selection ranges, paste handling across browsers). Given the README shows browser support is critical and uses Saucelabs, expanding tests for cross-browser contenteditable quirks would prevent regressions and reduce maintenance burden.

  • [ ] Review existing spec/content.spec.js to identify untested contenteditable scenarios
  • [ ] Add tests for: cursor positioning after delete/backspace, multi-line selection handling, paste event normalization across browsers
  • [ ] Add tests for nested editable elements (demo/nested-editable.html exists, but likely not covered)
  • [ ] Run tests via karma.conf.js and karma.dev.conf.js to verify across Chrome/Firefox

Implement GitHub Actions workflow to replace/supplement .travis.yml for automated testing

The repo uses .travis.yml (old Travis CI) but modern GitHub repos benefit from native GitHub Actions. The existing karma.conf.js and grunt setup support Saucelabs integration, but a new Actions workflow would provide faster feedback, better GitHub integration, and reduce reliance on external CI services.

  • [ ] Create .github/workflows/test.yml to run: npm test (grunt test via Gruntfile.js)
  • [ ] Add matrix testing for Node.js LTS versions and browser compatibility via karma-chrome-launcher and karma-firefox-launcher (already in devDependencies)
  • [ ] Integrate karma-coveralls for coverage reports within the workflow
  • [ ] Add workflow badge to README.md and document in CONTRIBUTING.md

Extract and document API for toolbar button extensions with concrete examples in spec/buttons.spec.js

The repo has demo/button-example.html and demo/extension-example.html, but spec/buttons.spec.js likely has incomplete coverage for custom button creation. Expanding this with tested patterns would help new contributors build extensions and reduce custom support requests.

  • [ ] Audit spec/buttons.spec.js for missing test cases: button lifecycle hooks, custom button registration, toolbar state management
  • [ ] Add tests for: button initialization with options, click handlers, toolbar show/hide logic, multi-instance button isolation
  • [ ] Cross-reference demo files to ensure test cases map to working examples
  • [ ] Update API.md with tested custom button signature and OPTIONS.md with button configuration schema

Good first issues

  • Add missing unit tests for src/js/util/selection.js — the selection manipulation code is critical but test coverage may have gaps; compare existing test patterns in test/ directory and identify untested edge cases in range/selection restoration.
  • Expand demo/index.html with accessibility ARIA attributes and keyboard navigation examples — the README doesn't mention a11y support, and this project should document how to use the editor with screen readers and keyboard-only users.
  • Create a TypeScript definition file (medium-editor.d.ts) for the main MediumEditor.js class and extensions — this would unlock IDE intellisense for TypeScript users and is a common low-risk contribution for mature projects.

Top contributors

Recent commits

  • d113a74 — Merge pull request #1558 from yabwe/bumper (sovkay)
  • 2c0af6b — Merge pull request #1557 from yabwe/karma (sovkay)
  • d890daf — lodash bump from 3.10.1 -> 4.17.19 (sovkay)
  • a7161c0 — Removing Extra browsers (sovkay)
  • 390fac6 — Maxm Log length resolve: Different karma conffiles (sovkay)
  • c40c286 — Safari Tests Passing (sovkay)
  • ba35736 — Added Edge and Firefox to karma config (sovkay)
  • a8c033d — Firefox Focus without Selection__Correction (sovkay)
  • 9f5f11a — Correcting Tests (sovkay)
  • 801cb74 — Tests working (sovkay)

Security observations

The medium-editor codebase has moderate security concerns, primarily around outdated dependencies with known vulnerabilities and inherent XSS risks associated with the contenteditable API implementation. While the project includes tests for exploits (exploits.spec.js), the actual implementation's sanitization practices are not visible in this analysis. Key recommendations include: (1) immediately updating all dependencies to current versions, (2) implementing comprehensive input sanitization using DOMPurify, (3) configuring security headers, and (4)

  • High · Outdated Dependencies with Known Vulnerabilities — package.json. Multiple dev dependencies have outdated versions with known security vulnerabilities. Notably: grunt (1.2.1), karma (5.1.0), jasmine (3.6.1), and connect (3.7.0) are several major versions behind current releases. The connect package specifically is used for development server and may have security issues. Fix: Update all dependencies to their latest stable versions. Run 'npm audit' to identify specific vulnerabilities and use 'npm update' or 'npm audit fix' to remediate them. Consider using automated dependency management tools like Dependabot.
  • High · contenteditable API XSS Risk — Core editor implementation (dist/js/medium-editor.js and source files). The project implements a WYSIWYG editor using the contenteditable API. This is inherently prone to XSS attacks if user input is not properly sanitized. The file structure shows spec/exploits.spec.js exists, suggesting awareness of exploit risks, but the actual implementation sanitization is not visible in this analysis. Fix: Implement comprehensive input sanitization and output encoding. Use DOMPurify or similar library to sanitize HTML content. Never trust user input directly. Validate and escape all content before inserting into the DOM. Review the exploits.spec.js test file to ensure all known XSS vectors are covered.
  • Medium · Missing Security Headers Configuration — Gruntfile.js, .travis.yml, or server configuration files (not fully visible). No visible Content Security Policy (CSP), X-Frame-Options, or other security headers configuration in the provided file structure. For a WYSIWYG editor handling user-generated content, this is a significant gap. Fix: Configure security headers including Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, and Strict-Transport-Security. If using express/connect server, implement helmet.js middleware.
  • Medium · Unverified npm Registry Configuration — .npmrc, package.json (publishConfig). The .npmrc file is present but content not visible. The package.json specifies a custom registry URL with http:// instead of https://. Fix: Ensure .npmrc uses https:// for all registry URLs. Verify npm registry credentials are not exposed. Use npm token-based authentication instead of storing plaintext credentials. Add .npmrc to .gitignore if it contains credentials.
  • Medium · Insufficient Input Validation in Demo Files — demo/*.html files. The demo directory contains multiple HTML files (demo/index.html, demo/extension-example.html, etc.) that may accept user input without proper validation. These could be used to demonstrate XSS attacks if not carefully secured. Fix: Ensure all demo files include proper input validation, sanitization, and content security policies. Add security-relevant comments to demo code. Never use dangerous patterns like innerHTML with unsanitized data.
  • Low · Build Tool Supply Chain Risk — Gruntfile.js, package.json (devDependencies). The project uses Grunt with multiple plugins for building and testing. While build tools are not production code, compromised or vulnerable build tools could inject malicious code. Fix: Regularly audit and update build dependencies. Use npm ci instead of npm install in CI/CD pipelines. Consider using npm workspaces and lockfile verification. Monitor for supply chain attacks using tools like npm audit.
  • Low · Source Maps in Production Distribution — dist/ directory. The dist/ directory contains both minified (.min.js/.min.css) and potentially source maps. If source maps are deployed to production, they expose the original source code. Fix: Exclude .map files from production builds. Configure build process to only include source maps in development environments. Add *.map to .gitignore if applicable.

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · yabwe/medium-editor — RepoPilot