npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

code-exercises-js

v2.1.1

Published

Create exercises for your students!

Readme

CodeExercises.js

A JavaScript library designed to facilitate the creation of coding exercises for students. It integrates with the Monaco Editor and provides methods to define validation rules and editable fields for exercises. The library currently only supports HTML-based exercises with real-time rendering in an iframe.

📦 Installation

Include the required scripts in your project:

    <script type="module">
        import * as monaco from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
        import { constrainedEditor } from 'https://cdn.jsdelivr.net/gh/Pranomvignesh/[email protected]/src/constrainedEditor.js';
        import { HtmlExcercise, EditableField } from "https://cdn.jsdelivr.net/npm/[email protected]"

        Object.assign(window, { monaco, constrainedEditor, HtmlExcercise });
    </script>

🚀 Usage

1️⃣ Setup the Editor Container

Create a div element to house the Monaco Editor:

<div id="container" style="width:800px;height:600px;border:1px solid grey; margin-right: 1rem;"></div>

2️⃣ Create an HTML Exercise

Instantiate a new HtmlExercise object with the editor container, initial content, and an optional iframe for rendering:

const editorContainer = document.getElementById("container");
const iframe = document.createElement("iframe");

const htmlExercise = new HtmlExercise(editorContainer, "<html>...</html>", iframe);

If no iframe is provided, a hidden one will be created automatically.

3️⃣ Define Validation Rules

You can chain validation rules using the provided methods:

htmlExercise.addValidationRule()
    .stopOnFail(false) // Continue validating even if a rule fails
    .required() // Ensure content is present
    .not.iframeContains(".style-me", "No '.style-me' element!")
    .contentIncludes("here") // Check if content includes "here"
    .elementIncludesText("body>div", "me") // Ensure a specific element contains text
    .elementHasAttributeColor(".style-me", "background-color", "#f00", null);

4️⃣ Define Editable Fields

Make specific parts of the exercise editable while keeping the rest read-only:

const styleField = new EditableField([11, 1, 11, 23], true);
styleField.addValidationRule()
    .endsWith("*/", "Need multiline comment!");

const divField = new EditableField([16, 9, 16, 9]);
divField.addValidationRule()
    .required();

htmlExercise.setEditableFields([styleField, divField]);

5️⃣ Read Validation Results

Listen for validation results using the onValidate event:

htmlExercise.onValidate.on(data => {
    console.log("Validation results:", data);
});

📖 Validation Methods

HtmlExercise

  • .lambda(method: (val: string, iframeDoc: Document) => boolean | Promise<boolean>, message: string): HtmlValidationRuleSet - Custom validation logic using a function.
  • .required(message?: string): HtmlValidationRuleSet - Ensures that the content is not empty.
  • .isValidHTML(message?: string): HtmlValidationRuleSet - Validates that the content is well-formed HTML. (Currently using w3c, which might stop working after a few validation attempts)
  • .stringEquals(compareTo: string, message?: string): HtmlValidationRuleSet - Checks if the content matches the given string exactly.
  • .contentIncludes(searchString: string, message?: string): HtmlValidationRuleSet - Ensures the content contains the specified substring.
  • .iframeContains(selector: string, message?: string): HtmlValidationRuleSet - Checks if an element matching the selector exists in the rendered iframe.
  • .elementHasAttributeColor(selector: string, property: string, color: string, delta?: number, message?: string): HtmlValidationRuleSet - Ensures an element has an attribute and its value matches the selected color. The DeltaE00 algorithm is used to ensure similarity.
  • .elementIncludesText(selector: string, text: string, message?: string): HtmlValidationRuleSet - Checks if an element contains the expected text.
  • .elementTextMatchesRegex(selector: string, regex: RegExp, message?: string): HtmlValidationRuleSet - Validates that the text of an element matches a regular expression.
  • .stringMatchesRegex(regex: RegExp, message?: string): HtmlValidationRuleSet - Ensures the content matches a given regular expression.

EditableField

  • .lambda(method: (val: string) => boolean, message: string): EditableFieldValidationRuleSet - Custom validation logic for editable fields.
  • .required(message?: string): EditableFieldValidationRuleSet - Ensures that the field contains a value.
  • .equals(compareTo: string, message?: string): EditableFieldValidationRuleSet - Checks if the field content matches the specified string.
  • .startsWith(prefix: string, message?: string): EditableFieldValidationRuleSet - Validates that the field content starts with a specific prefix.
  • .endsWith(suffix: string, message?: string): EditableFieldValidationRuleSet - Ensures the field content ends with a given suffix.
  • .equalsRegex(regex: RegExp, message?: string): EditableFieldValidationRuleSet - Checks if the field content matches a regular expression.

🛠 Example

<body>
    <div style="display: flex; flex-direction: row;">
        <div id="container" style="width:800px;height:600px;border:1px solid grey; margin-right: 1rem;"></div>
        <iframe id="iframe" style="width:800px;height:600px;border:1px solid grey" frameborder="0"></iframe>
    </div>
    <script type="module">
        import * as monaco from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
        import { constrainedEditor } from 'https://cdn.jsdelivr.net/gh/Pranomvignesh/[email protected]/src/constrainedEditor.js';
        import { HtmlExcercise, EditableField } from "https://cdn.jsdelivr.net/npm/[email protected]"

        Object.assign(window, { monaco, constrainedEditor, HtmlExcercise });

        const content = `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        .style-me {
            /* here */
        }
    </style>
</head>
<body>
    <div>
        Style me! 
        <br />
        background-color: red;
    </div>
</body>
</html>    
`;

        const element = document.getElementById("container");
        const iframe = document.getElementById("iframe");

        const htmlExcercise = new HtmlExcercise(element, content, iframe);

        htmlExcercise.addValidationRule()
            .required()
            .iframeContains(".style-me", "no '.Style-me'-element!")
            .elementHasAttributeColor(".style-me", "background-color", "#f00", null)
            ;


        const styleField = new EditableField([11, 1, 11, 23], true);
        styleField.addValidationRule
            .required();

        const divField = new EditableField([16, 9, 16, 9]);
        divField.addValidationRule
            .required();

        htmlExcercise.setEditableFields([styleField, divField]);

        htmlExcercise.onValidate.on(data => {
            console.log(data);
        });
    </script>
</body>

</html>

📜 License

This project is licensed under the MIT License - see the LICENSE file for details.