Add dynamic, powerful inline code examples and exercises to your site.
With InlineCodeSuite, each coding editor is contained in a tab on the right-hand side. Most inline coding tools are built to handle a fixed number and arrangement of editors. Typically this is one JavaScript, one HTML, and one CSS editor.
InlineCodeSuite, on the other hand, puts no constraints on the number of editors. Two JS editors? No problem. One JS editor, two CSS editors, and two HTML editors? As long as there's enough horizontal space for the tabs, that's no problem.
The title for each tab can be specified as well, so there's no confusion about the purpose or context for each tab.
Why is this useful? It allows InlineCodeSuite to masquerade as any number of existing inline coding environments. It can emulate:
- A basic, two-pane REPL
- A coding exercise/challenge tool with separate editors for example tests
- A project-style environment with multiple script editors
Hidden Scripts
InlineCodeSuite supports hidden script content that can be executed either:
- Before each update of the preview
- On button click
Why is this useful? You can prep an exercise or example with code that the user doesn't need to see. If you want to demonstrate how event listeners work, for example, then you only need to expose the event listener code in the example while the rest of the code is hidden. Use this to show simple example code that has a cool and impressive output.
Hidden HTML & CSS
Just line scripts, HTML and CSS can be hidden as well, which allows you to create beautiful, complex examples/challenges, while only exposing to the end user the content that's immediately relevant.
In addition to a flexible number of editor tabs, InlineCodeSuite also allows both editor content and/or hidden script content to be executed via button click. There can be as many buttons as
By default, code evaluation happens client-side. This has both advantages and disadvantages. Advantages are:
- Lightning-fast preview updates, which are especially noticeable when working with HTML and CSS
- Bypass server-side security concerns
Disadvantages are:
- By default, user content isn't saved. The user's work will be lost on page close/reload. This can be addressed by adding a hidden script that saves the editor content, either via a server call or session/local storage.
InlineCodeSuite allows individual editor tabs to be set to read-only, allowing you to show code to the user without allowing the user to modify it. Example use cases:
- You want the user to experiment with a CSS concept, so you might have two editor tabs, one for CSS and one for HTML. The HTML tab could be set to read-only. This would allow the user to see (but not edit) the HTML they're writing styles for, which could help them understand the relationship between the CSS rules and the structure of the HTML.
- You want users to be able to see tests that are going to be performed on their code without being able to edit the tests.
Code execution feels fast and zippy because it's handled by web workers, which don't block the UI thread and can terminate gracefully if the script times out (i.e. if an infinite loop is accidentally created).
Run the install command:
$ npm install -S inline-code-suite
Then, use the import
command in supported environments (Babel-transpiled code or supported browsers):
import 'inline-code-suite' as InlineCodeSuite;
Or use require
in supported environments (Electron):
InlineCodeSuite = require('inline-code-suite');
Add the script to the HTML file:
<script src="https://d2atlz6q4yph1d.cloudfront.net/dist/inline-code-suite.js"></script>
You can access specific versions, as well:
<script src="https://d2atlz6q4yph1d.cloudfront.net/dist/inline-code-suite-{version}.js"></script>
Where version is the version number, minus the preceding v
, e.g. inline-code-suite-0.1.2
.
Once including/imported/required, InlineCodeSuite
is a class. Instantiate the class and pass it an object with the following properties:
name
: A string that can be used to target this instance ofInlineCodeSuite
. Adds an id ofinlineCodeSuite-{name}
to the container element, where{name}
is "slugified" ("Hello World!!" => "hello-world")root
: The DOM object that the code suite will be attached toheight
(optional): A string that defines the height of the code suite. Defaults to300px
autoRun
(optional): A boolean that defines whether code automatically runs when editor content changes. This is applies to all editor types, including HTML and CSS editor tabs. Defaults totrue
autoPreview
(optional): A boolean that defines whether the preview pane updates automatically when HTML and CSS editor tab content changes. Defaults totrue
. Use this ifautoRun
is set tofalse
to prevent script tabs from auto-running, but you still want the preview to update automatically when HTML and CSS changes are madeuseLocalStorage
(optional): A boolean that determines whether or not editor content is stored and loaded from localStorage. Defaults totrue
editors
: An array of objects. Each object declares a new editor. Each editor object accepts the following properties:name
: The text that appears in the editor's tabmode
: A string that defines a valid scripting mode. Must be one of:css
htmlmixed
javascript
jsx
ruby
value
: A string. The starting code for the editorhasPreview
(optional): A boolean that determines whether or not the editor's code should be run when the preview pane is updatedpreserveBaseIndentation
(optional): A boolean that disables the default stripping of excess left-side indentation if set totrue
runButton
(optional): A string that defines the name of the button that will execute the code on clickreadOnly
(optional): A boolean that disables the ability to edit the editor's contents if set totrue
. They can still see and select/highlight/copy the content
hasConsole
(optional): A boolean that determines whether or not there's a console tab. Defaults totrue
importScripts
(optional): An array of strings declaring relative filenames. The compiler will import these files inside the script's execution context. You can use this to define dependencies or alter the context itselfscripts
(optional): An array of objects. Each object declares a new non-editor script. Each script object accepts the following properties:type
: A string. A valid HTMLtype
attribute liketext/javascript
value
(optional): A string. The script's code. This code will execute inside of a sandboxed environment, so it won't have access to the outer scope in which the inlineCodeSuite is created. It will have access to a variable,inlineCodeSuite
, that contains editorData (see the FAQ for more details)onRun
(optional): A callback function. This function will execute in the outer scope in which the inlineCodeSuite is createdrunButton
(optional): A string that defines the name of the button that will execute the code on click
preview
(optional): An object that defines preview settings, if a preview existshtml
(optional): An object that can be used to add rendered HTML to the preview, if you want HTML code to appear in the preview but not in the HTML editorpre
(optional): HTML code to be added before the HTML editor code in the previewpost
(optional): HTML code to be added after the HTML editor code in the preview
styles
(optional): Additional styles added to the preview that are not visible to the user
Gets data about the editors, including their current content and history. Takes no parameters and returns an object. The object has a property for each editor. The editor's name is the key. The values are the same as the values that were set during initialization, plus two additional properties for each editor object:
userValue
: The current value of the editor, as defined by the user's interactionshistory
: A stack of editor values, as defined by the user's interactions
Changes the content of an editor tab. Options should be passed in as an object, with the following properties:
name
: A string. It must match the providedname
property for the editor. If no match is found, nothing will happenpreserveBaseIndentation
(optional): A boolean. Preserves the base level of indentation of the string passed to it. Defaults to the editor's value (which itself defaults totrue
), if providedclearHistory
(optional): A boolean. Clears the editor's history, preventing undo actions from undoing the change to the editor's content
Changes the preview
settings object, as outlined above. This is useful if you want to change pre- or post-HTML, or alter the styles dynamically after initialization.
preview
: An object that defines preview settings, if a preview exists.
Adds a callback function that's triggered based on specific events. Takes two arguments:
type
: A string describing the type of event. Currently, onlycompilerWillRun
andcompilerDidRun
are supportedcallback
: A callback function. It will be passed a data object with information about the code being executed and its output
The inlineCodeSuite includes a rudimentary testing suite based on Jasmine. It supports the following functions:
describe
: Groups a suite of tests together and resets test countsxdescribe
: An empty trap, convenient for temporarily disabling a test suiteit
: Defines a testxit
: Defines a pending test that doesn't runbeforeEach
: Sets a callback function to be run before each individual test. Tests are terminated early if there's an error in this callbackafterEach
: Sets a callback function to be run after each individual test. LikebeforeEach
, tests are terminated early if there's an error in this callback
It supports the following matchers:
toBe(real)
: Matches with strict equality (===
)toBeCloseTo(expected, precision)
: Matches a number down to the specified precision (number of decimals)toBeDefined()
: Returns true if the result is notundefined
toBeFalsy()
: Matches loosely tofalse
toBeGreaterThan(expected)
: Matches if the result is greater than (>
) a specified valuetoBeGreaterThanOrEqual(expected)
: Matches if the result is greater than or equal to(>=
) a specified valuetoBeLessThan(expected)
: Matches if the result is less than (<
) a specified valuetoBeLessThanOrEqual(expected)
: Matches if the result is less than or equal to(<=
) a specified valuetoBeNaN()
: Matches if the result is NaN (defined byNumber.isNaN()
)toBeNegativeInfinity()
: Matches if the result equals-Infinity
toBeNull()
: Matches if the result does not strictly equalnull
toBePositiveInfinity()
: Matches if the result equalsInfinity
toBeTruthy()
: Matches loosely totrue
toBeUndefined()
: Matches if the result strictly equalsundefined
toEqual(expected)
: Does a loose and shallow match (note that Jasmine'stoEqual
does a deep comparison, while this does not)toMatch(regex)
: matches result against a given regex
Here's an example of a simple describe
block:
describe("Your function for the final round", () => {
it("should add positive numbers", () => {
expect( add(10,1) ).toBe(11);
});
it("should add positive and negative numbers", () => {
expect( add(-2,2) ).toBe(0);
});
it("should add zero and zero", () => {
expect( add(0,0) ).toBe(0);
});
});
Here's a slightly more complex example that uses beforeEach
and demonstrates beforeEach
, as well as how each it
block receives its own empty object as this
:
describe("A spec", function() {
beforeEach(function() {
this.foo = 3;
});
it("can use the `this` to share state", function() {
expect(this.foo).toEqual(3);
this.bar = "test pollution?";
});
it("prevents test pollution by having an empty `this` created for the next spec", function() {
expect(this.foo).toEqual(3);
expect(this.bar).toBe(undefined);
});
});
Clone this repo on your local machine, run npm install
, and then npm start
. That will launch /examples/index.html
, where you can see several variations of the editor in action. Each example is defined in its own script file in /examples/sccripts
.
Or create a new HTML file and paste the following contents. This is a bare-minimum, "Hello World" example of InlineCodeSuite in action:
<!doctype html>
<html>
<head>
<title>InlineCodeSuite Hello World</title>
<meta charset="UTF-8">
</head>
<body>
<app-root></app-root>
<script src="https://d2atlz6q4yph1d.cloudfront.net/dist/inline-code-suite.js"></script>
<script>
new InlineCodeSuite({
name: 'hello-world',
root: document.querySelector('app-root'),
editors: [{
name: 'HTML',
mode: 'htmlmixed',
value: '<div>hello world!</div>'
}, {
name: 'CSS',
mode: 'css',
value: 'body { background: papayawhip }'
}, {
name: 'JS',
mode: 'js',
value: ''
}]
})
</script>
</body>
</html>
Yes, scripts have access to a variable named inlineCodeSuite
. That variable has a property, editorData
. inlineCodeSuite.editorData
is an object containing editor data, and individual editors can be accessed by the name of the editor. For example, to access the editor data for an editor named JS
, use:
inlineCodeSuite.editorData["JS"]
In addition to the initial properties passed to the editor during creation (name
, mode
, value
, hasPreview
, runButton
, and preserveBaseIndentation
), each editor also has a userValue
property that stores the current state of the editor's contents at compile time. For example, if you have an editor named CSS
, you could access its current contents from your script through:
inlineCodeSuite.editorData['CSS'].userValue
Yes, each instance of InlineCodeSuite has a getEditorData()
method that will return editor data, including a userValue
property for each editor.