![Introducing Enhanced Alert Actions and Triage Functionality](https://cdn.sanity.io/images/cgdhsj6q/production/fe71306d515f85de6139b46745ea7180362324f0-2530x946.png?w=800&fit=max&auto=format)
Product
Introducing Enhanced Alert Actions and Triage Functionality
Socket now supports four distinct alert actions instead of the previous two, and alert triaging allows users to override the actions taken for all individual alerts.
corridor
Advanced tools
Readme
{json} → <html> → {json}
Bi-directional data binding without the fuss.
Your data is in JSON, but your users interact with HTML. corridor shuttles your data between your JSON and your HTML.
In a nutshell, corridor lets you turn this:
<fieldset name="project">
<input type="text" name="dependencies.foo" value="~0.1.0" />
<input type="text" name="dependencies.bar" value="~2.1.0" />
</fieldset>
Into this:
{
"project": {
"dependencies": {
"foo": "~0.1.0",
"bar": "~2.1.0"
}
}
}
And vice versa.
corridor is a runtime library, not a templating language. It runs in the browser, easily transferring your data both ways: from form fields to JSON and (importantly) back again.
corridor uses the name
attributes of your HTML elements to determine how a given input contributes to a JSON representation.
In most cases it'll just work, but if you need more flexibility, corridor's API options offer many points of customization.
Read the tutorial to get started, or skip to the API section for the details.
The corridor project philosophy boils down to these points:
Development of features, bugfixes and documentation are held to these ideals.
corridor is a single js file with no dependencies. You can get it in either of two ways:
$ npm install corridor
It would be great if users could just edit JSON directly. That way, your REST API would be all you'd need.
But unfortunately, your users interact with the Document Object Model (DOM) representation of your HTML. Which means that it's your job to figure out how to get these two views of the data to match.
The corridor library has only one function called corridor()
.
This function does one of two things:
Let's take a look at how this works by using the practical example of a package.json
file.
We'll build out a single-page web app for manipulating a package.json file.
To skip to the outcome of this walkthrough, see the example.html
file.
For a package.json
file, you need at least the following data:
And you may also want the following fields:
In all, that would produce JSON something like this (values omitted):
{
"name": "",
"version": "",
"keywords": [],
"dependencies": {}
}
Now let's put together the UI for working with this data.
Let's start with the name
field.
Here's the HTML you'd need:
<input type="text" name="name" />
Let's try it out.
Make sure you have the <input>
HTML on a page and the corridor.js
library included.
Then you can call the corridor function with no arguments to extract all the data on the page.
corridor(); // returns {"name":""} (or whatever you've typed in the box).
The first argument to corridor is the root element for the data extraction. If you don't provide one, corridor will assume you meant to search down from the document root.
By default, corridor will automatically detect the type of the value for an element.
But you can override this behavior by providing a data-type
attribute.
Let's see how this applies to the keywords
field of a package.json.
The HTML for the keywords field should look like this:
<textarea name="keywords" data-type="list"></textarea>
Here the data-type
indicates that we have a list
value.
corridor will try to parse the text in the <textarea>
as a list of items, and will output an array.
Let's give it a try!
With the above <textarea>
on a page, enter the text "abc, def"
(no quotes).
Then run corridor:
JSON.stringify(corridor(), null, 2);
// produces
{
"name": "",
"keywords": [
"abc",
"def"
]
}
Supported data types include:
If you can't set data-type
because your application already uses this attribute for something else, you can use data-opts
instead.
Here's how it would look with data-opts
:
<textarea name="keywords" data-opts='{"type":"list"}'></textarea>
The data-opts
attribute, when present, must contain valid JSON.
Note that options specified in data-opts
will override data-*
attributes.
Take this input for example:
<input type="text" name="zip" data-type="string" data-opts='{"type":"number"}' />
In this case, corridor will treat the zip as a number.
corridor will use parent elements' names to create nested structures.
For example, say we wanted to have drop-down choices for the foo
and bar
dependencies.
The corridor HTML for that would look something like this:
<fieldset>
<label>
foo:
<select name="dependencies.foo">
<option value="~1.1.0">foo: version 1</option>
<option value="~2.0.0">foo: version 2</option>
</select>
</label>
<label>
bar:
<select name="dependencies.bar">
<option value="~3.5.0">bar: version 3</option>
<option value="~4.1.0">bar: version 4</option>
</select>
</label>
</p>
Running corridor()
on this gives us:
{
"dependencies": {
"foo": "~1.1.0",
"bar": "~3.5.0"
}
}
But it doesn't end there!
Since both the foo
and bar
select boxes live under dependencies
, giving a name
to the fieldset would have the same effect:
<fieldset name="dependencies">
<label>
foo:
<select name="foo">
<option value="~1.1.0">foo: version 1</option>
<option value="~2.0.0">foo: version 2</option>
</select>
</label>
<label>
bar:
<select name="bar">
<option value="~3.5.0">bar: version 3</option>
<option value="~4.1.0">bar: version 4</option>
</select>
</label>
</p>
If you run corridor against this HTML, you'll get the same JSON listed above.
Merging works best for objects like the dependencies
object we just looked at.
But corridor can also merge arrays.
In the last section we saw a rudimentary example of how to create nested data structures. The range of supported names is quite rich.
These are best explained by example.
Let's say you wanted to add authors
to your package.json form, with a separate input for each author.
The HTML for that might look like this:
<fieldset>
<label>
first author:
<input type="text" name="authors[]" value="your name" />
</label>
<label>
second author:
<input type="text" name="authors[]" />
</label>
<label>
third author:
<input type="text" name="authors[]" />
</label>
</fieldset>
The name attribute for each author input is authors[]
.
The trailing square brackets means that the input value should contribute to an array.
Running corridor on the above would give you JSON like this:
{
authors: [
"your name"
]
}
Notice that there's only one element in this array. By default, corridor makes an intelligent decision about wether to include empty values in the extracted data. See the API documentation for how exactly it decides.
You can override the decision algorithm by specifying a data-empty
attribute.
If you set empty to include
, then the element's value will be included even if it's empty.
If you set empty to omit
, then it'll be left out of the data representation if empty.
Just like with the dependencies.foo
case from last section, here we could split up the parts of the name between the fieldset and the inputs.
E.g.
<fieldset name="authors">
<label>
first author:
<input type="text" name="[]" value="your name" />
You can mix and match dot delimited paths and square brackets to create even richer structures.
<input type="text" name="stock.ticker[]symbols" value="BCOV AMZN" data-type="list" />
Produces this:
"stock": {
"ticker": [
{
"symbols": [
"BCOV",
"AMZN"
]
}
]
}
Whitespace around key names is stripped, but whitespace inside them is preserved.
For example name=" foo bar "
would produce an object with a foo bar
property.
Merging arrays can be tricky, but in most cases corridor will make a good choice.
In the last section, we looked at an example where the authors
array contains normal string values.
But let's look at what happens when the values are more complex.
Consider this HTML:
<table data-name="company.employees[]">
<tr>
<td><input type="text" name="name" value="Bob" /></td>
<td><input type="text" name="email" value="bob@company.com" /></td>
</tr>
<tr>
<td><input type="text" name="name" value="Alice" /></td>
<td><input type="text" name="email" value="alice@company.com" /></td>
</tr>
</table>
For this, corridor()
produces the following:
{
"company": {
"employees": [{
"name": "Bob",
"email": "bob@company.com"
},{
"name": "Alice",
"email": "alice@company.com"
}]
}
}
The reason this works is that corridor checks each field under an arry to see if it can be safely merged into the last one.
So when it finds Bob's email
, it knows that it can safely add this key to the preceding Bob object without destroying data.
But when it gets to Alice's name
, it sees that it couldn't safely add the value.
If it set the last object's name
to Alice, then the name
of Bob would be lost.
So it creates a new element and sets its name
instead.
For more information on array merging, and how you can control it, see the API documentation.
You can mark sections of your UI as being toggleable using the role
option.
For example, say you wanted a checkbox to control whether keywords
were going to be included in the output.
The HTML for that might look like this:
<fieldset data-role="toggleable">
<p>
<label>
<input type="checkbox" data-role="toggle" checked/>
include keywords?
</label>
</p>
<p>
<label>
keywords (list format):
<textarea name="keywords" data-type="list"></textarea>
</label>
</p>
</fieldset>
Adding the toggleable
role to the <fieldset>
signals to corridor that this section can be turned on and off.
The checkbox with the role toggle
controls it.
You can nest toggleable sections inside each other. In each case, the toggle that controls the toggleable container is the nearest child.
So far, this tutorial has focused on explaining how data flows from HTML to JSON. But corridor is great at sending data the other way as well.
To insert data back into the DOM, call the corridor function with a root element and a data structure object.
corridor(document.body, {
name: "foo",
keywords: ["bar", "baz"]
});
corridor uses the same name
and data-*
attributes to determine where data values should be inserted.
When you send data from JSON into HTML, there's a chance that there won't be enough room. This is especilly true when working with arrays.
Consider this input JSON:
{
"company": {
"employees": [{
"name": "Bob",
"email": "bob@company.com"
},{
"name": "Alice",
"email": "alice@company.com"
}]
}
}
And this HTML:
<table>
<tr data-name="company.employees[]">
<td><input type="text" name="name" /></td>
<td><input type="text" name="email" /></td>
</tr>
</table>
If you ran corridor in insert mode in this scenario, Alice would be lost since there's only one row for company.employees
.
Fortunately, corridor can expand the DOM for you to make room for the extra elements.
If you set data-expand
to auto
on a named element, corridor will duplicate it to make room for data that otherwise wouldn't fit.
Here's the same example again, with the data-expand
attribute set:
<table>
<tr data-name="company.employees[]" data-expand="auto">
<td><input type="text" name="name" /></td>
<td><input type="text" name="email" /></td>
</tr>
</table>
After calling corridor(table, data)
, the HTML in the page will look like this:
<table>
<tr data-name="company.employees[]" data-expand="auto">
<td><input type="text" name="name" value="Bob" /></td>
<td><input type="text" name="email" value="bob@company.com" /></td>
</tr>
<tr data-name="company.employees[]" data-expand="auto">
<td><input type="text" name="name" value="Alice" /></td>
<td><input type="text" name="email" value="alice@company.com" /></td>
</tr>
</table>
Since the expand feature is more intrusive in its side-effects in the DOM, you must enable it explicitly either by setting the data-expand
option, or in the options argument to the corridor()
function.
The corridor API consists of two major parts: the corridor()
function itself, and the information in the HTML it uses to make decisions about how to operate.
The corridor function takes three parameters, all optional:
corridor([root], [data], [opts])
The parameters are:
root
— The starting DOM element to search for named fields (defaults to document
).data
— The plain JSON data object whose values are to be inserted.opts
— Additional options to inform how corridor makes decisions.The presence of the second parameter, data
, tells corridor whether it should extract data from the DOM or insert data into it.
To extract data from the DOM, call corridor()
without the second argument, or set it to null.
Examples:
corridor();
corridor(root);
corridor(root, null, opts);
corridor(null, null, opts);
In extract mode, corridor will:
root
element,This is completely safe. No side-effects are produced as a result of this operation, just data extraction.
To insert data into the DOM, call corridor()
with an object as the second argument.
Examples:
corridor(null, data);
corridor(root, data);
corridor(null, data, opts);
corridor(root, data, opts);
In insert mode, corridor will:
root
element,data
object (if a match can be found).This will modify the values of discovered named fields where they differ from the data object representation.
The opts
argument, when present, affects how corridor behaves in two ways.
First, any values you specify will override the defaults for field value calculations.
For example, say you set the type
property to binary
:
corridor(null, null, {type:'binary'});
This means that any fields without an explicit type
declared will be coerced to binary values.
Fields with an explicit type (either as data-type
or in data-opts
) will still use their specified type though.
Secondly, some options give hints to corridor's higher level behavior.
For example, the enabledOnly
property controls whether corridor will operate on fields that are disabled by a toggleable
parent.
By default enabledOnly
is set to true
, meaning only enabled fields are included.
You could set enabledOnly
to false
in the opts hash to tell corridor to ignore the effects of toggleables.
Available options are:
type
- the type of the field (auto, string, boolean, number, list, or json)empty
- whether to include the value in the output if the field is empty (auto, include, or omit)merge
- strategy to use when merging arrays (auto, concat, or extend)include
- whether a non-form element should be considered for insert/extract (auto, always, or never)extract
- strategy for pulling a value from a non-form element when extracting (auto, value, text, or html)insert
- strategy for putting a value into a non-form element when inserting (auto, value, text, or html)expand
- whether to expand the DOM to accomodate data that otherwise wouldn't fit (never, auto)role
- what role this element plays (field, toggleable, toggle, expand)enabledOnly
- only include enabled elements for consideration during insert/extract (true, false)Note that setting options via the opts
param specifically affects the execution of the corridor function just once.
Persistent options should be stored in the HTML.
The type
option indicates the kind of field this is.
The type determines how corridor converts the string value of the form element into the data representation.
The recognized types are:
auto
- automatically detect the correct type based on the value (default)string
- treat the value as a stringboolean
- coerce this value to something true/falsenumber
- parse this value as a numberjson
- leave this value as-is (will choke if it's not actually valid JSON)list
- parse this value as a list of valuesWhen automatically detecting the type, corridor uses the following algorithm:
The list type will never be auto detected.
The empty
option indicates whether the value should be included in the output if its value is empty.
Choices are:
auto
- automatically detect the appropriate behavior based on the circumstances (default)include
- include the value in the output (default)omit
- do not add the field at allWhen empty is set to auto
, corridor uses the following algorithm to between include
and omit
:
required
attribute, then choose include
, otherwise,name="authors[]"
), choose omit
, otherwise,omit
.If none of these conditions are met, then choose include
.
With this algorithim, most of the time an empty value will contribute to the output, except in cases where you probably expect it wouldn't.
The merge
option indicates which merging strategy corridor should use when merging two arrays.
Choices are:
auto
- intelligently choose whether to concatenate the arrays, or deep merge them (default)concat
- concatenate the arraysextend
- deep merge each pair of itemsWhen in auto
mode, the algorithm for choosing whether to concatenate or merge two arrays should work as follows:
concat
, otherwise,concat
(this is a strange case), otherwise,concat
.The algorithm for deciding whether an object can be safely merged into a base object is as follows:
Both auto and concat are safe operations. In neither case is data lost. However, extend is potentially (likely) unsafe—with this strategy, data is easily clobbered.
In all cases, if either the original or other object is not an array, there is no ambiguity to resolve. When at least one argument is not array-like, the merge will produce an object such that no information is lost (other than what is specifically overwritten by colliding keys).
For example, if the original object is an array (["foo"]
) and the other object is a non-array-like object ({"bar":"baz"}
). then the outcome of the merge will be an object that keeps all data in tact ({"0":"foo","bar":"baz"}
).
The include
option indicates whether a non-form element should be considered for insert/extract.
Choices are:
auto
- intelligently choose whether to include the element (default).always
- always include the element.never
- never include the element.When operating in auto mode, corridor uses the following algorithm to decide whether a non-form element should be considered for insert/extract:
input
, textarea
, select
), include it, otherwise,name
or data-name
attributes, include it, otherwise,Only elements included by this algorithm will contribute to extracted output or receive inserted data.
The extract
option indicates how a value should be extracted from an element under consideration.
Choices are:
auto
- intelligently choose the best way to get a value (default).value
- get the element's form value (value
attribute, except for <select>
elements).text
- get the element's textContent
.html
- get the element's innerHTML
.When operating in auto mode, corridor uses the following algorithm to decide how to extract a value:
<pre>
or <code>
element, use text, otherwise,If you set the extract option, it's much better to set it in the HTML specifically for a particular element. Most of the time, you'll want the auto detection.
The insert
option indicates how a value should be inserted into an element under consideration.
Choices are:
auto
- intelligently choose the best way to insert the value (default).value
- set the element's form value (value
attribute, except for <select>
elements).text
- set the element's textContent
.html
- set the element's innerHTML
.When operating in auto mode, corridor uses the following algorithm to decide how to insert a value:
<pre>
or <code>
element, use text, otherwise,If you set the insert option, it's much better to set it in the HTML specifically for a particular element. Most of the time, you'll want the auto detection.
The expand
option indicates whether corridor should make any attempt to expand the DOM to accomodate data that otherwise wouldn't fit.
Choices are:
never
- do not add any elements to the DOM (default).auto
- intelligently choose the best way to expand the DOM if necessary.When operating in auto mode, corridor uses the following algorithm to decide how to expand the DOM:
name
or data-name
attribute,data-expand
value of never
,[]
,The algorithm for finding a clone target for a set of candidate elements is:
elem
here),data-role
set to expand
, if found, use itelem
is a value'd form field:data-role
set to expand
, if found, use it, otherwise,<li>
element or a <tr>
, if found, use itelem
Known limitations:
Improving on these limitations will require a major update to the code base to include an intermediate tree structure. This tree structure would provide the rich information necessary to make more intelligent auto-expand decisions.
See Issue #39.
Options specific to the toggleable
/toggle
functionality are:
corridor inspects the Document Object Model (DOM) at runtime to figure out how to extract and insert data. Specificially, it looks at these things:
name
(or data-name
) attribute, anddata-*
(or data-opts
) attributes.The tag name influences whether corridor considers an element to have a value, and if so, how to retrieve it.
For instance, the way you extract a value from a <textarea>
differs from how you extract a value from a <select>
element.
The name
attribute is by far the most important one to corridor.
The presence of a name
attribute (or data-name
) tells corridor that an element should be considered for data insertion/extraction.
The content of this attribute tells corridor exactly how to shuttle data between the element's value and the data representation.
The data-*
attributes, when present, override the default options (see the opts section above).
corridor uses the name
attribute of an element to figure out how the value of that element relates to the data representation.
You can also use the data-name
attribute instead.
corridor will actually check the data-name
attribute first and use it if present, falling back to plain name
.
This serves two purposes.
First, strictly speaking, not all HTML5 elements allow the name
attribute.
But HTML5 doel allow data-
prefixed attributes on any element.
If you want to assign a name to a p
or a div
tag, for example, you should use data-name
.
Secondly, data-name
supplies an alternative should your application require that the name
field has a specific value.
If you need to keep name
the same, but want corridor to address it by a different name value, you'd use data-name
.
There are two formats you can use when specifying the name of an element: name format and field format.
Note: better names for "name format" and "field format" are forthcoming.
The name format is the more natural of the two formats. In name format, the value resembles how you'd access a nested value inside an object in JavaScript.
For instance, say your JSON representation is this:
{
"book": {
"title": "The Art of War"
}
}
Then an input that maps to the title
would have name="book.title"
:
<input type="text" name="book.title" value="The Art of War"/>
In name format, use periods to separate keys.
They can nest to arbitrary depth, e.g. {"a":{"b":{"c":"foo"}}}
maps to the element with name="a.b.c"
.
You can also use brackets to indicate a subkey (as opposed to using a period .
).
For example, the following are all equivalent to name="a.b.c"
:
name="[a][b][c]"
name="a[b]c"
name="a[b].c"
name="a.b[c]"
Whitespace is trimmed from the beginning and ending of keys, but not inside.
So name="a b"
is different from name="a b"
, but all of the following are equivalent to name="a.b.c"
:
name="[ a ][ b ][ c ]"
name=" a.b.c "
name="a[b]. c"
name="a. b[c]"
Finally, a pair of square brackets with nothing inside ([]
) means that the value should contribute to an array.
Consider this HTML:
<input type="text" name="book.authors[]" value="Sunzi"/>
<input type="text" name="book.authors[]" value="Giles, Lionel"/>
With corridor, this would map to the following data representation:
{
"book": {
"authors": [
"Sunzi",
"Giles, Lionel"
]
}
}
Where you're appending to an array, you'll probably want the square brackets at the end, but this isn't strictly necessary. Your name attribute can have additional keys and bracket pairs after the first. Here are a few example names and the JSON data they'd map to:
// <input name="authors[]name" value="Sunzi" />
{
"authors": [
{ "name": "Sunzi" }
]
}
// <input name="authors[][]" value="Sunzi" />
{
"authors": [
[ "Sunzi" ]
]
}
// <input name="[][author]" value="Sunzi" />
[ { "author": "Sunzi" } ]
In most cases, using name format for your name attributes will give you what you need to correctly shuttle data between your JSON and your HTML. However, if your JSON is quite complex, you may need to use field format for some of your elements.
Note: field format will probably be removed in a future version of corridor
Whereas name format resembles how you'd access an object in JavaScript, field format resembles how you describe an object in JavaScript—that is, JSON.
With field format, you specify how your data should appear as properly formatted JSON.
Except that you replace the value with the literal string $$$
.
For example, consider the name format string book.title
.
The field format version would be {"book":{"title":$$$}}
.
Any name format string can be converted to field format, but the opposite is not always true.
Here are some name format strings and their field format equivalents:
title
→ {"title":$$$}
book.title
→ {"book":{"title":$$$}}
authors[]
→ {"authors":[$$$]}
authors[]name
→ {"authors":[{"name":$$$}]}
[]
→ [$$$]
a.b.c
→ {"a":{"b":{"c":$$$}}}
You should use the name format for your name attributes.
Just as data-*
attributes override the default options, data-opts
can also be used to override options.
If present, the data-opts
attribute must contain valid JSON.
For example data-type="list"
is the same as data-opts='{"type":"list"}'
.
When both a data-*
attribute and a data-opts
key have the same name (like in this list example) corridor will use the value in data-opts
.
This way, if your application already uses a data-*
attribute that would conflict with corridor, you can use data-opts
instead.
If you find any issues with corridor, or if you'd like to request a feature, please head over to the issues page on github.
Keep in mind that the more specific you are, the more likely your issue or feature is to be addressed.
If you have a question about how to use corridor, or if you're not sure if you're doing it right, go to stackoverflow and ask a question.
Make sure you add the corridor
tag to your question.
If you're interested in developing corridor, great! Start by forking corridor on github.
Once you've forked the project, clone it using git clone
:
$ git clone git@github.com:<YOUR_USERNAME>/corridor.git
The source code for corridor itself is in the src/
directory.
corridor uses npm for packaging and deployment, so you'll need to install Node.js if you haven't already. Once you have Node, you can pull in corridor's development dependencies:
$ npm install
The corridor unit tests are in the test/
directory.
corridor's unit tests are written to run in nodeunit or with QUnit.
After installing the npm dependencies, you can run the corridor unit tests from the command line like this:
$ npm test
To run the unit tests in the browser, just open test/index.html
and they'll run automatically.
When you're satisfied with your changes, commit them and push them to your forked repository. Then open a pull request in github by hitting the big "Pull Request" button from the main project repo page.
See LICENSE
FAQs
JSON -> HTML -> JSON data corridor
The npm package corridor receives a total of 2 weekly downloads. As such, corridor popularity was classified as not popular.
We found that corridor demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket now supports four distinct alert actions instead of the previous two, and alert triaging allows users to override the actions taken for all individual alerts.
Security News
Polyfill.io has been serving malware for months via its CDN, after the project's open source maintainer sold the service to a company based in China.
Security News
OpenSSF is warning open source maintainers to stay vigilant against reputation farming on GitHub, where users artificially inflate their status by manipulating interactions on closed issues and PRs.