• This repository has been archived on 31/Dec/2022
  • Stars
    star
    286
  • Rank 139,475 (Top 3 %)
  • Language
    JavaScript
  • Created over 14 years ago
  • Updated almost 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple-logic templates

grips Templating Engine

Try Grips Online

grips is a simple-logic templating engine written in JavaScript. It's designed to work either/both in the browser or on the server, with the same code-base and the same template files.

grips will "compile" requested templates into JavaScript functions, which takes JSON data as input and returns the rendered string output. The compilation of templates can either be on-demand, or they can be pre-compiled in a build process and used later.

The design philosophy behind grips is not to be remarkable for what it can do, but to be remarkable for what it cannot do. That is to say, grips is as restrained in functionality as is necessary to accomplish all reasonable templating tasks.

If you find yourself needing to do something in templating that you cannot do with the features that grips provides, there's a good chance you're doing something you shouldn't be doing in templating. The goal is a minimal but capable set of logic for templating which in its limitations enforces (and encourages) responsible separation-of-concerns.

Examples

The examples/ directory has several sample template files. Take a look at "tmpl.master.html" and "tmpl.index.html" in particular for good general real-world looking examples. "test.html" is more esoteric and shows off more complexities of the syntax nuances.

Templating syntax

Template tags (as defined below) have a short/terse form and a long/friendlier form. You can mix and match the forms as you see fit. Examples may use the short form (for conciseness), but there's no reason to infer a preference either way. Some people prefer less templating cruft in their templates, others prefer more readable and less cryptic templates. To each his/her own. Just a matter of taste.

NOTE: For simplicity sake, when the engine prints a debug error message where it references a template tag, it always uses the short form for the tag, regardless of what it encountered in the original template.

Define a named template section (aka, "partial")

Long-form:

{$define "#xxx" }
	...
	...
{$}

Short-form:

{$: "#xxx" }
	...
	...
{$}

Define a named template section (partial), with local variable assignment(s)

$ is the data object (context) passed into the partial.

{$: "#xxx" |
	x = $.val_1 |
	y = $.val_2
}
	...
	...
{$}

Conditional Assignments

{$: "#bar" |
	baz = $.baz ? "yes" : ""
}
	baz: {$= baz $}
{$}

The else condition of a conditional can be omitted and defaults to "".

{$: "#bar" |
	baz = $.baz ? "yes"
}
	baz: {$= baz $}
{$}

Let-local Assignments

The Let tag provides a way to make a local variable assignment that only exists for the block it creates, which contains the assignment to a more limited scope than the Define tag and Loop tag assignments.

Long-form:

{$let foo = "foo" | bar = "bar" }
	...
{$}

Short-form:

{$# foo = "foo" | bar = "bar" }
	...
{$}

Insert/print data property or variable

Long-form:

{$insert $.val_1 $}     {$insert myval $}
{$print $.val_1 $}      {$print myval $}

Short-form:

{$= $.val_1 $}     {$= myval $}

Include template partial, by static literal

Long-form:

{$partial "#yyy" $}     {$insert @"#yyy" $}

Short-form:

{$= @"#yyy" $}

Template partials can be referenced either by only the (relative) #partial-ID, or by a full canonical collection-ID#partial-ID reference. If no collection-ID is specified, the current containing collection will be assumed.

NOTE: The short-form (and {$insert ... $}) requires the @ symbol to distinguish a partial include from a data insertion. The long-form {$partial ... $} makes it more explicit in this case.

Include template partial, by variable

Long-form:

{$partial $.val_1 $}     {$partial myval $}

Short-form:

{$= @$.val_1 $}     {$= @myval $}

Manually specify data context for template partial include

{$= @"#yyy" | $.user $}

Escaping (html, string, url) at the block-level

You can wrap a block-level escape tag around an arbitrary set of template content (inside a partial, of course), and it will cause the output of that section to be escaped according to which escaping rule(s) you specify.

There are 3 types of escaping rules you can choose from: h for html encoding, s for string (JavaScript, etc) escaping, and u for URL encoding/escaping. You can specify more than one rule together, but in most cases you'll probably just use one. If you specify no rule, the default is s (string).

The long-form of the rule(s) flag is escape or escape h or escape hus, etc. The short-form of the rule(s) flag is ~ or ~h or ~hus, etc.

Long-form:

{$: "#yyy" }
	Here is {$escape}string "escaped" content (by default){$}
	And here is {$escape h}html <em>encoded</em> content{$}
	Then, http://some.com/?a={$escape u}http://other.com{$}
	Finally, multiple {$escape hu}rules "can" be <a href="http://some.com">combined</a>.{$}
{$}

Short-form:

{$: "#yyy" }
	Here is {$~}string "escaped" content (by default){$}
	And here is {$~h}html <em>encoded</em> content{$}
	Then, http://some.com/?a={$~u}http://other.com{$}
	Finally, multiple {$~hu}rules "can" be <a href="http://some.com">combined</a>.{$}
{$}

Escaping (html, string, url) at the tag-level

You can apply escaping/encoding rules to a {$insert .. $} or {$partial .. $} tag directly, without needing to wrap it in a block-level escaping tag. You have the same 3 rule choices as for block-level escaping rules (see above).

The form of the rule(s) flag is ~ or ~h or ~hus, etc, regardless of whether the tag is long-form or short-form. NOTE: the "long-form" of the rule(s) flag (escape ..) itself is not supported for tag-level escaping.

Used with long-form tags:

{$: "#yyy" }
	Here's a tag-level (string) escaping: <script>var foo = "{$insert~ $.foo $}";</script>
	Here's more tag-level (html) escaping with a partial include: {$partial~h "#zzz" $}
{$}

Used with short-form tags:

{$: "#yyy" }
	Here's a tag-level (string) escaping: <script>var foo = "{$=~ $.foo $}";</script>
	Here's more tag-level (html) escaping with a partial include: {$=~h @"#zzz" $}
{$}

Loop on data variable (array or plain key/value object)

_ is the current iteration binding, and it includes:

  • index (numeric: zero-based positional index)
  • key (string: for object iteration, the property name; for array iteration, the index)
  • value (actual item value)
  • first
  • last
  • odd
  • even

Long-form:

{$loop $.val_1 }
	...
	key: {$insert _.key $}    value: {$insert _.value $}
	...
{$}

Short-form:

{$* $.val_1 }
	...
	key: {$= _.key $}    value: {$= _.value $}
	...
{$}

Loop on data variable, with loop iteration local variable assignment(s)

{$* $.val_1 |
	rowtype = _.odd ? "#oddrow" : "#evenrow" |
    someprop = _.value.someProp ? "#hassomeprop"
}
	...
	{$= @rowtype $}
	...
	{$= @someprop $}
	...
{$}

Range Literals

{$* [2..7] } <!-- let's count from 2 to 7 -->
	counting: {$= _.value $}
{$}
{$* [4..-3] } <!-- count down from 4 to -3 -->
	counting: {$= _.value $}
{$}

Set Literals

{$* ["Jan", "Feb", "Mar"] } <!-- show the months in Q1 -->
	month: {$= _.value $}
{$}

Precomputing hash literals

Hash literals can be pre-computed against a defined set or range of values. In the below examples, the value of $.myradio will be compared to all values in the range/set (0,1,2 or "low","medium","high"). The results of the comparison and conditional assignment are stored in a local variable hash, keyed by the comparison values. For instance, in the below example, one of the three pre-computation comparisons/assignments the syntax implies is: checked[1] = ($.myradio === 1) ? "checked" : "" (same for values 0 and 2).

{$: "#bar" |
	checked[0..2] = $.myradio ? "checked"
}
	<input type="radio" name="myradio" value="0" {$= checked[0] $}>
	<input type="radio" name="myradio" value="1" {$= checked[1] $}>
	<input type="radio" name="myradio" value="2" {$= checked[2] $}>
{$}

Using a loop the above can be even more terse:

{$: "#bar" |
	checked[0..2] = $.myradio ? "checked"
}
	{$* [0..2] }
		<input type="radio" name="myradio" value="{$= _.value $}" {$= checked[_.value] $}>
	{$}
{$}

Here's a "trick" for even more terseness, by iterating over the pre-computed comparison hash:

{$: "#bar" |
	options[0..2] = $.myradio ? "checked"
}
	{$* options }
		<input type="radio" name="myradio" value="{$= _.key $}" {$= _.value $}>
	{$}
{$}

Pre-computation with a set-literal:

{$: "#bar" |
	checked["low","medium","high"] = $.myradio ? "checked"
}
	<input type="radio" name="myradio" value="low" {$= checked["low"] $}>
	<input type="radio" name="myradio" value="medium" {$= checked["medium"] $}>
	<input type="radio" name="myradio" value="high" {$= checked["high"] $}>
{$}

"Extend" (inherit from) another template collection

Long-form:

{$extend "collection-ID" $}

Short-form:

{$+ "collection-ID" $}

Template collections are an arbitrary grouping of one or more template partials. Usually a template collection corresponds to a file. A template collection can "extend" another template collection, in a similar way you'd be used to having one class extend another class.

A template collection that extends another collection means that it "inherits" the template partials from the collection it extends. You can reference those template partials in template-includes, even if they don't exist in the current template collection. You can also override a template partial that was inherited, simply by defining it in the current collection.

If you reference a partial for inclusion, the engine will start at the appropriate collection level and look for the partial there, and if not found, will walk up the extension chain, if any, looking for a matching partial.

For example, collection "foo":

{$: "#baz" } baz {$}
{$: "#bam" } bam {$}

And collection "bar":

{$+ "foo" $}

{$: "#baz" }
	Foobar {$= @"foo#baz" $} {$= @"#bam" $}
{$}

In this example, bar extends foo, and #baz and #bam are inherited from foo into bar. #baz is redefined in bar, but the original inherited version can be referenced by giving the full foo#baz template reference. Finally, since #bam was inherited, it can be referenced even without the full template reference.

Raw unparsed section

Long-form:

{$raw
	this stuff {$= won't be parsed $}, just passed through raw
%$}

Short-form:

{$%
	this stuff {$= won't be parsed $}, just passed through raw
%$}

Template comment block

Long-form:

{$comment comments get removed
	in parsing /$}

Short-form:

{$/ comments get removed
	in parsing /$}

Debug vs. Non-Debug

grips can either be used in debug mode or non-debug mode, controlled by which version of the library file/module you include. The debug version of the library has friendly error handling, and also produces compiled templates with friendly error handling, whereas the non-debug library (and templates compiled by it) will simply throw a generic "Unknown error" for any errors encountered.

It is recommended that during development you use the debug version of the library, as it will greatly assist in understanding grips template syntax and behavior. But once you deploy grips and/or compiled templates to production, use the non-debug version of the library, because both the library and the compiled templates will be significantly smaller with debug bits stripped.

For browser usage (either basic or AMD-style), choose the appropriate file with or without the "-debug" in the filename. For node.js module usage, you select which version of the library you want to use directly on the included module.

var grips_nondebug = require("grips").grips,
    grips_debug = require("grips").debug;

Full Compiler vs. Runtime

For browser usage (either basic of AMD-style), you can choose to include the full compiler, or just the runtime bits. The runtime is all that's required if you only plan to render pre-compiled templates. If you need to actually compile templates in the browser (usually pretty rare), include the full lib. Otherwise, you should include the much smaller runtime only.

The most typical production usage pattern would be to have a build process (see the grips CLI tool section below) that precompiles your templates, and includes them all together in a single script file (ex: "template-bundle.js"). In that scenario, you'd most likely want to prepend the runtime library file to the beginning of that template bundle file, so you'd only need to load that one combined file in the browser.

Installing, Deploying

If you plan to use grips only in a browser, simply download the appropriate file(s) from the "deploy" directory of this repository, and use them in your page using a standard <script src="..."> type include, bundle the file(s) with your other code, or load them with a dynamic script loader or dependency manager.

If you plan to use grips on the server (in node.js), install it with npm:

npm install grips

If you want to use the grips CLI tool and the grips-build build tool from your command line, and you want those binaries added to your normal system bin path, you can instead install grips globally, by adding a "-g" to your npm install command.

Once installed with npm, you will have a "./node_modules/grips/deploy" directory, and there is where you will find the files you need to deploy for browser usage, as just described.

To use the grips module in a node.js script, you simply call require("grips"), and on that module object, you choose either the debug version of the library with require("grips").debug or the non-debug version with require("grips").grips.

API

The JavaScript API is accessible in a couple of different ways. The raw library can be loaded in a traditional fashion in a browser, and will produce a single global symbol called grips. It can be loaded as an AMD module, using the "amd-*.js" versions of the files (assuming they were built with the grips-build tool). And finally, you can use the "grips" module in node.js code (see above).

Regardless of how you include the library and get access to the core grips API, the following methods and signatures are all available. The only caveat is that if you load the runtime version of the library (which has the compiler stripped), only the runtime parts (initialize, render, etc) of the API are available.

The two most typical tasks for the JavaScript API are compileCollection() and render().

grips organizes template partials by grouping them together in collections. A single collection is an arbitrary grouping of one or more partials, but it usually will correspond to a single template file. The collection-ID is arbitrary, but again, will usually be the filename of the template file.

You will render an individual partial, but you will compile a collection of one or more partials.

Compiling a collection

To compile a collection of partials, call compileCollection(templateStr, collectionID, [initialize=true]).

templateStr is the string representation of your collection of template partials. collectionID should be the same as any other references to the collection by ID, such as other absolute template includes, or template extend directives, in other collections.

initialize, which defaults to true, is an optional boolean flag. If true, it will evaluate the compiled template function representation, so that it's ready to render. You'd pass false for this parameter if you were only doing pre-compilation of templates, for instance in a build process, and didn't need them to be intialized for rendering at that time.

compileCollection() returns you the string value of that compiled template function, so you can choose to store it in a file during a build process, etc.

A collection-ID is the first part of a canonical template-ID (foo in "foo#bar", whereas #bar is the partial-ID). The {$+ ... $} collection extend tag takes only the collection-ID (like foo), without any partial-ID.

grips.compileCollection("{$: '#bar' } Hello {$= $.name $}! {$}", "foo");

For convenience, if you want to compile several collections at once, use compile(sources, [initialize=true]). The sources parameter is an object whose keys are used as the collection names and whose values are the collection template sources.

grips.compile({
	foo: "{$: '#bar' } Hello {$= $.name $}! {$}"
});

Rendering a partial

If one or more collections have been compiled and initialized, they can then be rendered by calling render(templateID, data).

To render a partial using the JavaScript API, you must refer canonically to its full templateID by both the partial-ID and the collection-ID of the collection in which it lives. For example, for "foo#bar", foo is the collection-ID and #bar is the partial-ID.

var markup = grips.render("foo#bar", {
	name: "World"
});

Other methods

Since you can pre-compile templates during a build process and store them in files for later use in production, you can call initializeCollection() (or initialize()) to evaluate the source of a compiled template collection's functions.

For instance, if you had the compiled functions for the foo collection in source form (from a file), you can initialize them (so they're ready for rendering) by either eval()ing them yourself, or with initializeCollection(collectionID, compiledSource).

eval(fooCompiledSource);

// or

grips.initializeCollection("foo", fooCompiledSource);

And if you have two or more collections in one big string (like one file), you can just call initialize(compiledSourceBundle).

eval(compiledSource);

// or

grips.initialize(compiledSource);

Using the grips CLI

grips comes with a node.js tool called grips (I know, creative, right!?), in the "bin/" directory, which is a CLI tool for compiling, initializing, and rendering templates.

Here are the options for the CLI tool:

usage: grips opt [, ..opt]

options:
--help                                    show this help

--nodebug                                 use the non-debug library
--keep-paths                              for --compile, keep the full path in the collection-ID, instead of just the filename
--minify                                  minify compiled templates with uglify.js

--compile=file                            compile a template file (using {file} as the collection-ID)
--initialize=file                         initializes an already compiled template collection from a file
--render='{collection-ID}#{partial-ID}'   render the specified partial, using data from stdin

The --compile flag can be passed multiple times, once for each file you want to compile. By default, only the filename itself will be used as the collection-ID, however if you pass --keep-paths, then the full path you specify for a file will be used as the collection-ID. NOTE: a collection-ID (filename, file path) must not include a # character, as that is the separator between collection-ID and partial-ID.

If a --render flag is not passed, the output from the compilation (--compile) will be printed to the stdout. Otherwise, the output will be the rendered output.

If you want to initialize (to prepare for rendering) an already compiled collection (in one or more files), use --initialize.

If you have compiled templates, or initialized already compiled templates, then you can render one or more partials using --render. You must specify both the collection-ID and the partial-ID. --render also requires that you provide the JSON data for your template rendering via stdin.

bin/grips --compile=templates/foo.bar.html --compile=templates/baz.html > tmpl-bundle.js
echo "{\"some\":\"data\"}" | bin/grips --initialize=tmpl-bundle.js --render='baz.html#foobar'
..
echo "{\"some\":\"data\"}" | bin/grips --compile=templates/foo.bar.html --compile=templates/baz.html --render= 'baz.html#foobar'

Building grips

grips comes with a node.js tool called grips-build, in the "bin/" directory, which when run will generate the files you need to use grips, in a directory called "deploy".

There are a few simple options for the grips-build tool:

usage: grips-build [opt, ...]

options:
--help       show this help
--verbose    display progress

--full       builds only the full compiler+runtime package
--runtime    builds only the stripped down (no compiler) runtime separately
--debug      builds all files only with debug code included (graceful error handling, etc)
--nodebug    builds all files only with debug code stripped (smaller files, but with less graceful error handling)

--amd        also builds AMD style files (amd-*.js files)
--node       also builds node.js compatible module files
--minify     also minifies all built files with uglify.js (*.min.js files)

--all        build all possible files/options

Defaults:
If you pass neither --full nor --runtime, --full will be assumed.
If you pass neither --debug nor --nodebug, --debug will be assumed.

By default, the grips-build tool is silent, meaning it outputs nothing to the console unless there are errors. If you'd like verbose output, pass the --verbose flag.

--full builds the full compiler+runtime together. --runtime builds only the stripped down (no compiler) runtime separately. Both flags can be passed to build both options. If you pass neither --full nor --runtime, --full will be assumed.

--debug includes debug code (graceful error handling, etc) in both the library and the compiled templates it will produce. --nodebug strips all debug code from the library (and thus from any compiled templates it will produce). Both flags can be passed to build both options. If you pass neither --debug nor --nodebug, --debug will be assumed. For production usage, it is strongly recommended to use the --nodebug built files.

--amd also builds the AMD style version of any built files. --node also builds the node.js modules. --minify also minifies all built files (using "uglify.js").

Finally, --all will build all files and option combinations.

Linting grips templates

The grips-lint tool is a work in progress, but aims to be a simple linting tool to help you check your templates for a variety of bad practices and potential pitfalls. Right now, it only performs a few simple checks, but of course, there will be plenty more checks coming.

Also, right now, there's only one level of warning, but grips-lint will eventually let you configure specific warnings into different levels, and set thresholds for which warnings you want to see. To effectively disable a warning, you'll be able to set it to a level that is below the allowed threshold, thereby hiding it.

Right now, the options for grips-lint tool are pretty limited. More will be added as this tool matures.

usage: grips-lint opt [, ..opt]

options:
--help                                    show this help
--verbose                                 display progress

--file=file                               specify a collection file to be checked

Performance Benchmarks

Performance optimization is not really a primary design-goal of grips. If you were simply wanting the fastest performance possible, raw JavaScript written specifically to produce your desired strings would be the limit. Any "templating" logic involved would be boilerplate which couldn't help but "get in the way" and slow it down, even just a little bit.

grips is far more concerned with creating a proper and responsible templating language and environment. However, performance cannot be ignored, because a templating engine which is impractically slow for real-world usage does no good.

As such, grips participates in some of the performance benchmarking by which other engines are tested, to make sure that its performance is acceptable and balanced against its feature set.

Revision 46 of the "JavaScript Templating Shootoff" includes grips tests. In general, grips is performing well, comparable to other well known engines like Dust.js.

grips performance is a grips-specific performance test (using the same template snippet from the "shootoff"), which is used for regression testing as grips is improved going forward.

The main takeaway from these numbers is that, in general, grips can render thousands of partials in just a few milliseconds, which means that it almost certainly will never be a performance bottleneck in your client-side application.

The grips-perf tool runs the templating scenario from grips performance test in node.js (using benchmark.js) and reports benchmark numbers for 3 different tests: "compilation", "direct-partial" (from partials cache), and "render()".

License

grips (c) 2012-2014 Kyle Simpson | http://getify.mit-license.org/

More Repositories

1

You-Dont-Know-JS

A book series on JavaScript. @YDKJS on twitter.
175,600
star
2

Functional-Light-JS

Pragmatic, balanced FP in JavaScript. @FLJSBook on twitter.
JavaScript
16,458
star
3

LABjs

Loading And Blocking JavaScript: On-demand parallel loader for JavaScript with execution order dependencies
HTML
2,278
star
4

asynquence

Asynchronous flow control (promises, generators, observables, CSP, etc)
JavaScript
1,739
star
5

CAF

Cancelable Async Flows (CAF)
JavaScript
1,323
star
6

monio

The most powerful IO monad implementation in JS, possibly in any language!
JavaScript
1,038
star
7

TNG-Hooks

Provides React-inspired 'hooks' like useState(..) for stand-alone functions
JavaScript
1,012
star
8

native-promise-only

A polyfill for native ES6 Promises as close as possible (no extensions) to the strict spec definitions.
JavaScript
725
star
9

A-Tale-Of-Three-Lists

Comparing various async patterns for a single demo
JavaScript
651
star
10

fasy

FP iterators that are both eager and asynchronous
JavaScript
544
star
11

FPO

FP library for JavaScript. Supports named-argument style methods.
JavaScript
449
star
12

youperiod.app

YouPeriod.app -- the privacy-first period tracking app
JavaScript
439
star
13

JSON.minify

Simple minifier for JSON to remove comments and whitespace
400
star
14

TypL

The Type Linter for JS
JavaScript
368
star
15

h5ive-DEPRECATED

**DEPRECATED** A collection of thin facade APIs wrapped around HTML5 JavaScript features.
JavaScript
324
star
16

eslint-plugin-proper-arrows

ESLint rules to ensure proper arrow function definitions
JavaScript
304
star
17

foi-lang

Foi: a different kind of functional programming language
JavaScript
301
star
18

moduloze

Convert CommonJS (CJS) modules to UMD and ESM formats
JavaScript
205
star
19

ES-Feature-Tests

Feature Tests for JavaScript
JavaScript
199
star
20

let-er

DEPRECATED: Transpile non-ES6 let-blocks into ES6 (or ES3)
JavaScript
190
star
21

Incomplete-JS

"The Incomplete Guide to JavaScript" (book). @IncompleteJS on twitter.
190
star
22

revocable-queue

Specialized async queue data structure, supports revocation of values
JavaScript
175
star
23

deePool

highly-efficient pool for JavaScript objects
JavaScript
115
star
24

concrete-syntax-tree

Defining a standard JavaScript CST (concrete syntax tree) to complement ASTs
106
star
25

getify.github.io

JavaScript
105
star
26

eslint-plugin-proper-ternary

ESLint rules to ensure proper usage of ternary/conditional expressions
JavaScript
95
star
27

cloud-sweeper

A casual game built for the web.
JavaScript
92
star
28

BikechainJS

JavaScript VM engine (powered by V8); server-side environment modules; server-side synchronous web app controllers
C++
80
star
29

wepuzzleit

Demo PoC game for various advanced HTML5 js APIs
JavaScript
78
star
30

workshop-periodic-table

60
star
31

elasi

EL/ASI: Encrypt Locally, Account Secure Interchange
JavaScript
60
star
32

remote-csp-channel

Remote bridge for CSP channels
JavaScript
55
star
33

ScanTree

Scan a JS file tree to build an ordered and grouped dependency listing
JavaScript
51
star
34

dwordly-game

A game where words dwindle down to the shortest possible
JavaScript
42
star
35

stable-timers

timers with less race conditions
JavaScript
38
star
36

emdash

Simple blogging with node/iojs + GitHub.
36
star
37

domio

DOM and Event helpers for Monio
JavaScript
30
star
38

eslint-plugin-no-optional-call

ESLint plugin to disallow the optional-call operator
JavaScript
30
star
39

eslint-plugin-arrow-require-this

DEPRECATED: ESLint rule to require arrow functions to reference the 'this' keyword
JavaScript
28
star
40

gum-try-hd

Try to enforce HD (16:9) camera aspect ratio for web-video calls
JavaScript
25
star
41

Mock-DOM-Resources

A mock of (parts of) the DOM API to simulate resource preloading and loading
JavaScript
25
star
42

import-remap

Rewrite ES module import specifiers using an import-map.
JavaScript
24
star
43

make-a-game

some project files for a tutorial on making a simple web game
JavaScript
24
star
44

mpAjax

framework plugin for handling multi-part Ajax responses
JavaScript
23
star
45

asyncGate.js

DEPRECATED. asynchronous gate for javascript
JavaScript
21
star
46

tic-tac-toe-workshop

Workshop files for building tic-tac-toe in JS and <canvas>
21
star
47

esre

esre: fully configurable JS code formatting
20
star
48

workshop-chess-diagonals

17
star
49

featuretests.io

JavaScript Feature Tests... as a service
JavaScript
16
star
50

FoilScript

FoilScript: a new dialect of JS that fixes the sucky parts but still looks and feels like JS
16
star
51

literalizer

Specialized heuristic lexer for JS to identify complex literals
JavaScript
15
star
52

normalize-selector

Normalize CSS selectors
JavaScript
14
star
53

DOMEventBridge

Bridge DOM events to a JS event hub (for pubsub)
JavaScript
14
star
54

pong-around-workshop

Workshop files for building a pong-variant game in JS and <canvas>
12
star
55

shortie.me

Proof-of-concept demo for server-side JavaScript driven "middle-end" architecture
JavaScript
11
star
56

workshop-wordy-unscrambler

10
star
57

middleend-boilerplate

Boilerplate Starting Point for Middle-end Web Architecture
JavaScript
8
star
58

workshop-knights-dialer

7
star
59

demo-app-weatheround

JavaScript
7
star
60

the-economy-of-keystrokes-slides

Slides code built for "The Economy of Keystrokes" talk
JavaScript
6
star
61

santa-connect-app

Santa Connect: keeping track of your kids' nice/naughty status
JavaScript
5
star
62

nyc-bug-demo

bug demo for NYC code coverage tool
JavaScript
4
star
63

unnamed

unnamed (for now). nothing to see here. ;-)
JavaScript
2
star
64

my-lifesheets

CSS
1
star
65

breakthewebforward.com

JavaScript
1
star