diff --git a/.eslintrc b/.eslintrc
index 2116a09..bace5dd 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,38 +1,43 @@
{
"env": {
- "node": true,
- "es6": true
+ "commonjs": true,
+ "es6": true,
+ "jest": true,
+ "node": true
},
+ "extends": ["eslint:recommended", "happiness"],
"rules": {
- "arrow-parens": [2, "as-needed"],
- "no-console": [1],
- "no-constant-condition": [1],
- "no-extra-semi": [1],
- "no-func-assign": [1],
- "no-obj-calls": [2],
- "no-unexpected-multiline" : [2],
- "no-unneeded-ternary": [2],
- "radix": [2],
- "no-with": [2],
- "no-eval": [2],
- "no-unreachable": [1],
- "no-irregular-whitespace": [1],
- "no-new-wrappers": [2],
- "no-new-func": [2],
- "curly" : [2, "multi-line"],
- "no-implied-eval": [2],
- "no-invalid-this": [2],
- "constructor-super": [2],
- "no-dupe-args": [2],
- "no-dupe-keys": [2],
- "no-dupe-class-members": [2],
- "no-this-before-super": [2],
- "prefer-arrow-callback": [1],
- "no-var": [2],
- "valid-jsdoc": [1],
- "strict": [2, "global"],
- "callback-return": [1],
- "object-shorthand": [1, "methods"],
- "prefer-template": [1]
- }
-}
\ No newline at end of file
+ "arrow-parens": ["error", "as-needed"],
+ "callback-return": ["warn"],
+ "constructor-super": ["error"],
+ "curly" : ["error", "multi-line"],
+ "no-case-declarations": "off",
+ "no-console": ["warn"],
+ "no-constant-condition": ["warn"],
+ "no-dupe-args": ["error"],
+ "no-dupe-class-members": ["error"],
+ "no-dupe-keys": ["error"],
+ "no-eval": ["error"],
+ "no-extra-semi": ["warn"],
+ "no-func-assign": ["warn"],
+ "no-implied-eval": ["error"],
+ "no-invalid-this": ["error"],
+ "no-irregular-whitespace": ["warn"],
+ "no-new-func": ["error"],
+ "no-new-wrappers": ["error"],
+ "no-obj-calls": ["error"],
+ "no-this-before-super": ["error"],
+ "no-unexpected-multiline" : ["error"],
+ "no-unneeded-ternary": ["error"],
+ "no-unreachable": ["warn"],
+ "no-var": ["error"],
+ "no-with": ["error"],
+ "object-shorthand": ["warn", "methods"],
+ "prefer-arrow-callback": ["warn"],
+ "prefer-template": ["warn"],
+ "radix": ["error"],
+ "strict": ["error", "global"],
+ "valid-jsdoc": ["warn"]
+ },
+ "parser": "babel-eslint"
+}
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c559a5c..410815d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,11 +1,11 @@
before_script:
# Install dependencies
- - bash test/docker_install.sh > /dev/null
- - npm install
+ - sh test/docker_install.sh > /dev/null
+ - yarn
services:
- - mysql:latest
- - postgres:latest
+ - mariadb:latest
+ - postgres:alpine
variables:
MYSQL_ROOT_PASSWORD: foo-bar-baz
@@ -22,10 +22,14 @@ cache:
paths:
- node_modules/
-test:6:
- image: node:6
- script: npm run test
+test:8:
+ image: node:8-alpine
+ script: yarn run test
+
+test:9:
+ image: node:9-alpine
+ script: yarn run test
test:latest:
- image: node:latest
- script: npm run test
+ image: node:alpine
+ script: yarn run test
diff --git a/.istanbul.yml b/.istanbul.yml
deleted file mode 100644
index 51f02d4..0000000
--- a/.istanbul.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-reporting:
- print: summary
- reports:
- - lcov
- - lcovonly
- - clover
- - html
- - text
- dir: ./coverage
\ No newline at end of file
diff --git a/API.md b/API.md
index 6e294e3..24bc502 100644
--- a/API.md
+++ b/API.md
@@ -1,49 +1,71 @@
-# NodeQuery
+### Table of Contents
+
+- [NodeQuery](#nodequery)
+ - [getQuery](#getquery)
+- [QueryBuilder](#querybuilder)
+ - [queryFile](#queryfile)
+ - [query](#query)
+ - [resetQuery](#resetquery)
+ - [truncate](#truncate)
+ - [end](#end)
+ - [select](#select)
+ - [from](#from)
+ - [like](#like)
+ - [notLike](#notlike)
+ - [orLike](#orlike)
+ - [orNotLike](#ornotlike)
+ - [having](#having)
+ - [orHaving](#orhaving)
+ - [where](#where)
+ - [orWhere](#orwhere)
+ - [whereIsNull](#whereisnull)
+ - [whereIsNotNull](#whereisnotnull)
+ - [orWhereIsNull](#orwhereisnull)
+ - [orWhereIsNotNull](#orwhereisnotnull)
+ - [whereIn](#wherein)
+ - [orWhereIn](#orwherein)
+ - [whereNotIn](#wherenotin)
+ - [orWhereNotIn](#orwherenotin)
+ - [set](#set)
+ - [join](#join)
+ - [groupBy](#groupby)
+ - [orderBy](#orderby)
+ - [limit](#limit)
+ - [groupStart](#groupstart)
+ - [orGroupStart](#orgroupstart)
+ - [orNotGroupStart](#ornotgroupstart)
+ - [groupEnd](#groupend)
+ - [get](#get)
+ - [insert](#insert)
+ - [insertBatch](#insertbatch)
+ - [update](#update)
+ - [updateBatch](#updatebatch)
+ - [delete](#delete)
+ - [getCompiledSelect](#getcompiledselect)
+ - [getCompiledInsert](#getcompiledinsert)
+ - [getCompiledUpdate](#getcompiledupdate)
+ - [getCompiledDelete](#getcompileddelete)
+- [Result](#result)
+ - [rowCount](#rowcount)
+ - [columnCount](#columncount)
+
+## NodeQuery
Class for connection management
**Parameters**
-- `config` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** connection parameters
+- `config` **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** connection parameters
-## constructor
-
-Constructor
-
-**Parameters**
-
-- `config` **[object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** connection parameters
-
-**Examples**
-
-```javascript
-let nodeQuery = require('ci-node-query')({
- driver: 'mysql',
- connection: {
- host: 'localhost',
- user: 'root',
- password: '',
- database: 'mysql'
- }
-});
-```
-
-```javascript
-let nodeQuery = require('ci-node-query')({
- driver: 'sqlite',
- connection: ':memory:'
-});
-```
-
-## getQuery
+### getQuery
Return an existing query builder instance
Returns **[QueryBuilder](#querybuilder)** The Query Builder object
-# QueryBuilder
+## QueryBuilder
**Extends QueryBuilderBase**
@@ -54,46 +76,57 @@ Main object that builds SQL queries.
- `Driver` **Driver** The syntax driver for the database
- `Adapter` **Adapter** The database module adapter for running queries
-## query
+### queryFile
+
+Run a set of queries from a file
+
+**Parameters**
+
+- `file` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The path to the sql file
+- `separator` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The character separating each query (optional, default `';'`)
+
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** The result of all the queries
+
+### query
Run an arbitrary sql query. Run as a prepared statement.
**Parameters**
-- `sql` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The sql to execute
-- `params` **\[[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)]** The query parameters
+- `sql` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The sql to execute
+- `params` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)?** The query parameters
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** Promise with result of query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** Promise with result of query
-## resetQuery
+### resetQuery
Reset the object state for a new query
Returns **void**
-## truncate
+### truncate
Empties the selected database table
**Parameters**
-- `table` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to truncate
+- `table` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to truncate
-Returns **(void | [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))** Returns a promise if no callback is supplied
+Returns **(void | [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise))** Returns a promise if no callback is supplied
-## end
+### end
Closes the database connection for the current adapter
Returns **void**
-## select
+### select
Specify rows to select in the query
**Parameters**
-- `fields` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array))** The fields to select from the current table
+- `fields` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array))** The fields to select from the current table
**Examples**
@@ -107,13 +140,13 @@ query.select(['foo', 'bar']); // Select multiple fileds with an array
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## from
+### from
Specify the database table to select from
**Parameters**
-- `tableName` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to use for the current query
+- `tableName` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to use for the current query
**Examples**
@@ -127,190 +160,190 @@ query.from('tableName t'); // Select the table with an alias
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## like
+### like
Add a 'like/ and like' clause to the query
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
-- `val` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
-- `pos` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
+- `val` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
+- `pos` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## notLike
+### notLike
Add a 'not like/ and not like' clause to the query
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
-- `val` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
-- `pos` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
+- `val` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
+- `pos` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orLike
+### orLike
Add an 'or like' clause to the query
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
-- `val` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
-- `pos` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
+- `val` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
+- `pos` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orNotLike
+### orNotLike
Add an 'or not like' clause to the query
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
-- `val` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
-- `pos` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field to compare to
+- `val` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The value to compare to
+- `pos` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The placement of the wildcard character(s): before, after, or both (optional, default `both`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## having
+### having
Add a 'having' clause
**Parameters**
-- `key` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
-- `val` **\[([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))]** The value to compare if the value of key is a string
+- `key` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
+- `val` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))?** The value to compare if the value of key is a string (optional, default `null`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orHaving
+### orHaving
Add an 'or having' clause
**Parameters**
-- `key` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
-- `val` **\[([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))]** The value to compare if the value of key is a string
+- `key` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
+- `val` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))?** The value to compare if the value of key is a string (optional, default `null`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## where
+### where
Set a 'where' clause
**Parameters**
-- `key` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
-- `val` **\[([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))]** The value to compare if the value of key is a string
+- `key` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
+- `val` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))?** The value to compare if the value of key is a string
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orWhere
+### orWhere
Set a 'or where' clause
**Parameters**
-- `key` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
-- `val` **\[([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number))]** The value to compare if the value of key is a string
+- `key` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** The name of the field and the comparision operator, or an object
+- `val` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number))?** The value to compare if the value of key is a string
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## whereIsNull
+### whereIsNull
Select a field that is Null
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field that has a NULL value
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field that has a NULL value
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## whereIsNotNull
+### whereIsNotNull
Specify that a field IS NOT NULL
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name so the field that is not to be null
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name so the field that is not to be null
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orWhereIsNull
+### orWhereIsNull
Field is null prefixed with 'OR'
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orWhereIsNotNull
+### orWhereIsNotNull
Field is not null prefixed with 'OR'
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the field
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## whereIn
+### whereIn
Set a 'where in' clause
**Parameters**
-- `key` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
-- `values` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
+- `key` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
+- `values` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orWhereIn
+### orWhereIn
Set a 'or where in' clause
**Parameters**
-- `key` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
-- `values` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
+- `key` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
+- `values` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## whereNotIn
+### whereNotIn
Set a 'where not in' clause
**Parameters**
-- `key` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
-- `values` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
+- `key` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
+- `values` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orWhereNotIn
+### orWhereNotIn
Set a 'or where not in' clause
**Parameters**
-- `key` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
-- `values` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
+- `key` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the field to search
+- `values` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the array of items to search in
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## set
+### set
Set values for insertion or updating
**Parameters**
-- `key` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object))** The key or object to use
-- `val` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The value if using a scalar key
+- `key` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** The key or object to use
+- `val` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The value if using a scalar key
**Examples**
@@ -324,85 +357,85 @@ query.set({foo:'bar'}); // Set with an object
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## join
+### join
Add a join clause to the query
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table you are joining
-- `cond` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The join condition.
-- `type` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The type of join, which defaults to inner (optional, default `'inner'`)
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table you are joining
+- `cond` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The join condition.
+- `type` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The type of join, which defaults to inner (optional, default `'inner'`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## groupBy
+### groupBy
Group the results by the selected field(s)
**Parameters**
-- `field` **([String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array))** The name of the field to group by
+- `field` **([String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array))** The name of the field to group by
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orderBy
+### orderBy
Order the results by the selected field(s)
**Parameters**
-- `field` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The field(s) to order by
-- `type` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The order direction, ASC or DESC (optional, default `'ASC'`)
+- `field` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The field(s) to order by
+- `type` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The order direction, ASC or DESC (optional, default `'ASC'`)
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## limit
+### limit
Put a limit on the query
**Parameters**
-- `limit` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** The maximum number of rows to fetch
-- `offset` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** The row number to start from
+- `limit` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** The maximum number of rows to fetch
+- `offset` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** The row number to start from
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## groupStart
+### groupStart
Adds an open paren to the current query for logical grouping
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orGroupStart
+### orGroupStart
Adds an open paren to the current query for logical grouping,
prefixed with 'OR'
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## orNotGroupStart
+### orNotGroupStart
Adds an open paren to the current query for logical grouping,
prefixed with 'OR NOT'
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## groupEnd
+### groupEnd
Ends a logical grouping started with one of the groupStart methods
Returns **[QueryBuilder](#querybuilder)** The Query Builder object, for chaining
-## get
+### get
Get the results of the compiled query
**Parameters**
-- `table` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** The table to select from
-- `limit` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** A limit for the query
-- `offset` **\[[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)]** An offset for the query
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The table to select from
+- `limit` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** A limit for the query
+- `offset` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)?** An offset for the query
**Examples**
@@ -418,27 +451,27 @@ query.get('table_name', 5); // Get 5 rows from the table
query.get(); // Get the results of a query generated with other methods
```
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
-## insert
+### insert
Run the generated insert query
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
-- `data` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** Data to insert, if not already added with the 'set' method
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
+- `data` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Data to insert, if not already added with the 'set' method
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
-## insertBatch
+### insertBatch
Insert multiple sets of rows at a time
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
-- `data` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** The array of objects containing data rows to insert
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
+- `data` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** The array of objects containing data rows to insert
**Examples**
@@ -447,91 +480,103 @@ query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}])
.then(promiseCallback);
```
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
-## update
+### update
Run the generated update query
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
-- `data` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** Data to insert, if not already added with the 'set' method
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
+- `data` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Data to insert, if not already added with the 'set' method
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
-## delete
+### updateBatch
+
+Creates a batch update sql statement
+
+**Parameters**
+
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to update
+- `data` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Batch insert data
+- `updateKey` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The field in the table to compare against for updating
+
+Returns **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of rows updated
+
+### delete
Run the generated delete query
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
-- `where` **\[[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)]** Where clause for delete statement
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The table to insert into
+- `where` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Where clause for delete statement
-Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
+Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Result](#result)>** Promise containing the result of the query
-## getCompiledSelect
+### getCompiledSelect
Return generated select query SQL
**Parameters**
-- `table` **\[[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)]** the name of the table to retrieve from
-- `reset` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Whether to reset the query builder so another query can be built (optional, default `true`)
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** the name of the table to retrieve from
+- `reset` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether to reset the query builder so another query can be built (optional, default `true`)
-Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
+Returns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
-## getCompiledInsert
+### getCompiledInsert
Return generated insert query SQL
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to insert into
-- `reset` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Whether to reset the query builder so another query can be built (optional, default `true`)
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to insert into
+- `reset` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether to reset the query builder so another query can be built (optional, default `true`)
-Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
+Returns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
-## getCompiledUpdate
+### getCompiledUpdate
Return generated update query SQL
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to update
-- `reset` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Whether to reset the query builder so another query can be built (optional, default `true`)
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to update
+- `reset` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether to reset the query builder so another query can be built (optional, default `true`)
-Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
+Returns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
-## getCompiledDelete
+### getCompiledDelete
Return generated delete query SQL
**Parameters**
-- `table` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to delete from
-- `reset` **\[[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)]** Whether to reset the query builder so another query can be built (optional, default `true`)
+- `table` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the name of the table to delete from
+- `reset` **[Boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Whether to reset the query builder so another query can be built (optional, default `true`)
-Returns **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
+Returns **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** The compiled sql statement
-# Result
+## Result
Query result object
**Parameters**
-- `rows` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the data rows of the result
-- `columns` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** the column names in the result
+- `rows` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the data rows of the result (optional, default `[]`)
+- `columns` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** the column names in the result (optional, default `[]`)
-## rowCount
+### rowCount
Get the number of rows returned by the query
-Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of rows in the result
+Returns **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of rows in the result
-## columnCount
+### columnCount
Get the number of columns returned by the query
-Returns **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of columns in the result
+Returns **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of columns in the result
diff --git a/README.md b/README.md
index 0d514c2..3beec4e 100755
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@ A node query builder for various SQL databases, based on [CodeIgniter](http://ww
### Supported databases
-* Firebird (via `node-firebird`)
* Mysql (via `mysql2`)
* PostgreSQL (via `pg`)
* Sqlite (via `dblite`)
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..d1dfc15
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,33 @@
+mariadb:
+ image: mariadb:latest
+ environment:
+ - MYSQL_USER=test
+ - MYSQL_PASSWORD=test
+ - MYSQL_DATABASE=test
+ - MYSQL_RANDOM_ROOT_PASSWORD=yes
+ ports:
+ - 3306:3306
+
+postgresql:
+ image: postgres:latest
+ environment:
+ - POSTGRES_USER=test
+ - POSTGRES_PASSWORD=test
+ - POSTGRES_DB=test
+ ports:
+ - 5432:5432
+
+sqlserver:
+ image: microsoft/mssql-server-linux
+ environment:
+ - ACCEPT_EULA=Y
+ - SA_PASSWORD=t3571ng0n1y
+ ports:
+ - 1433:1433
+
+firebird:
+ image: itherz/firebird3:latest
+ ports:
+ - 5040:5040
+ volumes:
+ - ./test:/databases
diff --git a/docs/assets/anchor.js b/docs/assets/anchor.js
index 47d871a..5c29527 100644
--- a/docs/assets/anchor.js
+++ b/docs/assets/anchor.js
@@ -1,197 +1,350 @@
/*!
- * AnchorJS - v1.2.1 - 2015-07-02
+ * AnchorJS - v4.0.0 - 2017-06-02
* https://github.com/bryanbraun/anchorjs
- * Copyright (c) 2015 Bryan Braun; Licensed MIT
+ * Copyright (c) 2017 Bryan Braun; Licensed MIT
*/
+/* eslint-env amd, node */
-function AnchorJS(options) {
+// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
+(function(root, factory) {
'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define([], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = factory();
+ } else {
+ // Browser globals (root is window)
+ root.AnchorJS = factory();
+ root.anchors = new root.AnchorJS();
+ }
+})(this, function() {
+ 'use strict';
+ function AnchorJS(options) {
+ this.options = options || {};
+ this.elements = [];
- this.options = options || {};
+ /**
+ * Assigns options to the internal options object, and provides defaults.
+ * @param {Object} opts - Options object
+ */
+ function _applyRemainingDefaultOptions(opts) {
+ opts.icon = opts.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'.
+ opts.visible = opts.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' & 'touch'
+ opts.placement = opts.hasOwnProperty('placement')
+ ? opts.placement
+ : 'right'; // Also accepts 'left'
+ opts.class = opts.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
+ // Using Math.floor here will ensure the value is Number-cast and an integer.
+ opts.truncate = opts.hasOwnProperty('truncate')
+ ? Math.floor(opts.truncate)
+ : 64; // Accepts any value that can be typecast to a number.
+ }
- this._applyRemainingDefaultOptions = function(opts) {
- this.options.icon = this.options.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'.
- this.options.visible = this.options.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always'
- this.options.placement = this.options.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left'
- this.options.class = this.options.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
- };
+ _applyRemainingDefaultOptions(this.options);
- this._applyRemainingDefaultOptions(options);
+ /**
+ * Checks to see if this device supports touch. Uses criteria pulled from Modernizr:
+ * https://github.com/Modernizr/Modernizr/blob/da22eb27631fc4957f67607fe6042e85c0a84656/feature-detects/touchevents.js#L40
+ * @returns {Boolean} - true if the current device supports touch.
+ */
+ this.isTouchDevice = function() {
+ return !!(
+ 'ontouchstart' in window ||
+ (window.DocumentTouch && document instanceof DocumentTouch)
+ );
+ };
- this.add = function(selector) {
- var elements,
+ /**
+ * Add anchor links to page elements.
+ * @param {String|Array|Nodelist} selector - A CSS selector for targeting the elements you wish to add anchor links
+ * to. Also accepts an array or nodeList containing the relavant elements.
+ * @returns {this} - The AnchorJS object
+ */
+ this.add = function(selector) {
+ var elements,
elsWithIds,
idList,
elementID,
i,
- roughText,
- tidyText,
index,
count,
+ tidyText,
newTidyText,
readableID,
- anchor;
+ anchor,
+ visibleOptionToUse,
+ indexesToDrop = [];
- this._applyRemainingDefaultOptions(this.options);
+ // We reapply options here because somebody may have overwritten the default options object when setting options.
+ // For example, this overwrites all options but visible:
+ //
+ // anchors.options = { visible: 'always'; }
+ _applyRemainingDefaultOptions(this.options);
- // Provide a sensible default selector, if none is given.
- if (!selector) {
- selector = 'h1, h2, h3, h4, h5, h6';
- } else if (typeof selector !== 'string') {
- throw new Error('The selector provided to AnchorJS was invalid.');
- }
+ visibleOptionToUse = this.options.visible;
+ if (visibleOptionToUse === 'touch') {
+ visibleOptionToUse = this.isTouchDevice() ? 'always' : 'hover';
+ }
- elements = document.querySelectorAll(selector);
- if (elements.length === 0) {
- return false;
- }
+ // Provide a sensible default selector, if none is given.
+ if (!selector) {
+ selector = 'h2, h3, h4, h5, h6';
+ }
- this._addBaselineStyles();
+ elements = _getElements(selector);
- // We produce a list of existing IDs so we don't generate a duplicate.
- elsWithIds = document.querySelectorAll('[id]');
- idList = [].map.call(elsWithIds, function assign(el) {
- return el.id;
- });
+ if (elements.length === 0) {
+ return this;
+ }
- for (i = 0; i < elements.length; i++) {
+ _addBaselineStyles();
- if (elements[i].hasAttribute('id')) {
- elementID = elements[i].getAttribute('id');
- } else {
- roughText = elements[i].textContent;
+ // We produce a list of existing IDs so we don't generate a duplicate.
+ elsWithIds = document.querySelectorAll('[id]');
+ idList = [].map.call(elsWithIds, function assign(el) {
+ return el.id;
+ });
- // Refine it so it makes a good ID. Strip out non-safe characters, replace
- // spaces with hyphens, truncate to 32 characters, and make toLowerCase.
- //
- // Example string: // '⚡⚡⚡ Unicode icons are cool--but they definitely don't belong in a URL fragment.'
- tidyText = roughText.replace(/[^\w\s-]/gi, '') // ' Unicode icons are cool--but they definitely dont belong in a URL fragment'
- .replace(/\s+/g, '-') // '-Unicode-icons-are-cool--but-they-definitely-dont-belong-in-a-URL-fragment'
- .replace(/-{2,}/g, '-') // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL-fragment'
- .substring(0, 64) // '-Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL'
- .replace(/^-+|-+$/gm, '') // 'Unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-URL'
- .toLowerCase(); // 'unicode-icons-are-cool-but-they-definitely-dont-belong-in-a-url'
+ for (i = 0; i < elements.length; i++) {
+ if (this.hasAnchorJSLink(elements[i])) {
+ indexesToDrop.push(i);
+ continue;
+ }
- // Compare our generated ID to existing IDs (and increment it if needed)
- // before we add it to the page.
- newTidyText = tidyText;
- count = 0;
- do {
- if (index !== undefined) {
- newTidyText = tidyText + '-' + count;
+ if (elements[i].hasAttribute('id')) {
+ elementID = elements[i].getAttribute('id');
+ } else if (elements[i].hasAttribute('data-anchor-id')) {
+ elementID = elements[i].getAttribute('data-anchor-id');
+ } else {
+ tidyText = this.urlify(elements[i].textContent);
+
+ // Compare our generated ID to existing IDs (and increment it if needed)
+ // before we add it to the page.
+ newTidyText = tidyText;
+ count = 0;
+ do {
+ if (index !== undefined) {
+ newTidyText = tidyText + '-' + count;
+ }
+
+ index = idList.indexOf(newTidyText);
+ count += 1;
+ } while (index !== -1);
+ index = undefined;
+ idList.push(newTidyText);
+
+ elements[i].setAttribute('id', newTidyText);
+ elementID = newTidyText;
+ }
+
+ readableID = elementID.replace(/-/g, ' ');
+
+ // The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
+ // '';
+ anchor = document.createElement('a');
+ anchor.className = 'anchorjs-link ' + this.options.class;
+ anchor.href = '#' + elementID;
+ anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID);
+ anchor.setAttribute('data-anchorjs-icon', this.options.icon);
+
+ if (visibleOptionToUse === 'always') {
+ anchor.style.opacity = '1';
+ }
+
+ if (this.options.icon === '\ue9cb') {
+ anchor.style.font = '1em/1 anchorjs-icons';
+
+ // We set lineHeight = 1 here because the `anchorjs-icons` font family could otherwise affect the
+ // height of the heading. This isn't the case for icons with `placement: left`, so we restore
+ // line-height: inherit in that case, ensuring they remain positioned correctly. For more info,
+ // see https://github.com/bryanbraun/anchorjs/issues/39.
+ if (this.options.placement === 'left') {
+ anchor.style.lineHeight = 'inherit';
}
- // .indexOf is supported in IE9+.
- index = idList.indexOf(newTidyText);
- count += 1;
- } while (index !== -1);
- index = undefined;
- idList.push(newTidyText);
+ }
- // Assign it to our element.
- // Currently the setAttribute element is only supported in IE9 and above.
- elements[i].setAttribute('id', newTidyText);
-
- elementID = newTidyText;
+ if (this.options.placement === 'left') {
+ anchor.style.position = 'absolute';
+ anchor.style.marginLeft = '-1em';
+ anchor.style.paddingRight = '0.5em';
+ elements[i].insertBefore(anchor, elements[i].firstChild);
+ } else {
+ // if the option provided is `right` (or anything else).
+ anchor.style.paddingLeft = '0.375em';
+ elements[i].appendChild(anchor);
+ }
}
- readableID = elementID.replace(/-/g, ' ');
+ for (i = 0; i < indexesToDrop.length; i++) {
+ elements.splice(indexesToDrop[i] - i, 1);
+ }
+ this.elements = this.elements.concat(elements);
- // The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
- // '';
- anchor = document.createElement('a');
- anchor.className = 'anchorjs-link ' + this.options.class;
- anchor.href = '#' + elementID;
- anchor.setAttribute('aria-label', 'Anchor link for: ' + readableID);
- anchor.setAttribute('data-anchorjs-icon', this.options.icon);
+ return this;
+ };
- if (this.options.visible === 'always') {
- anchor.style.opacity = '1';
+ /**
+ * Removes all anchorjs-links from elements targed by the selector.
+ * @param {String|Array|Nodelist} selector - A CSS selector string targeting elements with anchor links,
+ * OR a nodeList / array containing the DOM elements.
+ * @returns {this} - The AnchorJS object
+ */
+ this.remove = function(selector) {
+ var index,
+ domAnchor,
+ elements = _getElements(selector);
+
+ for (var i = 0; i < elements.length; i++) {
+ domAnchor = elements[i].querySelector('.anchorjs-link');
+ if (domAnchor) {
+ // Drop the element from our main list, if it's in there.
+ index = this.elements.indexOf(elements[i]);
+ if (index !== -1) {
+ this.elements.splice(index, 1);
+ }
+ // Remove the anchor from the DOM.
+ elements[i].removeChild(domAnchor);
+ }
+ }
+ return this;
+ };
+
+ /**
+ * Removes all anchorjs links. Mostly used for tests.
+ */
+ this.removeAll = function() {
+ this.remove(this.elements);
+ };
+
+ /**
+ * Urlify - Refine text so it makes a good ID.
+ *
+ * To do this, we remove apostrophes, replace nonsafe characters with hyphens,
+ * remove extra hyphens, truncate, trim hyphens, and make lowercase.
+ *
+ * @param {String} text - Any text. Usually pulled from the webpage element we are linking to.
+ * @returns {String} - hyphen-delimited text for use in IDs and URLs.
+ */
+ this.urlify = function(text) {
+ // Regex for finding the nonsafe URL characters (many need escaping): & +$,:;=?@"#{}|^~[`%!'<>]./()*\
+ var nonsafeChars = /[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\]/g,
+ urlText;
+
+ // The reason we include this _applyRemainingDefaultOptions is so urlify can be called independently,
+ // even after setting options. This can be useful for tests or other applications.
+ if (!this.options.truncate) {
+ _applyRemainingDefaultOptions(this.options);
}
- if (this.options.icon === '\ue9cb') {
- anchor.style.fontFamily = 'anchorjs-icons';
- anchor.style.fontStyle = 'normal';
- anchor.style.fontVariant = 'normal';
- anchor.style.fontWeight = 'normal';
- anchor.style.lineHeight = 1;
- }
+ // Note: we trim hyphens after truncating because truncating can cause dangling hyphens.
+ // Example string: // " ⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+ urlText = text
+ .trim() // "⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+ .replace(/\'/gi, '') // "⚡⚡ Dont forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
+ .replace(nonsafeChars, '-') // "⚡⚡-Dont-forget--URL-fragments-should-be-i18n-friendly--hyphenated--short--and-clean-"
+ .replace(/-{2,}/g, '-') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-short-and-clean-"
+ .substring(0, this.options.truncate) // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-"
+ .replace(/^-+|-+$/gm, '') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated"
+ .toLowerCase(); // "⚡⚡-dont-forget-url-fragments-should-be-i18n-friendly-hyphenated"
- if (this.options.placement === 'left') {
- anchor.style.position = 'absolute';
- anchor.style.marginLeft = '-1em';
- anchor.style.paddingRight = '0.5em';
- elements[i].insertBefore(anchor, elements[i].firstChild);
- } else { // if the option provided is `right` (or anything else).
- anchor.style.paddingLeft = '0.375em';
- elements[i].appendChild(anchor);
+ return urlText;
+ };
+
+ /**
+ * Determines if this element already has an AnchorJS link on it.
+ * Uses this technique: http://stackoverflow.com/a/5898748/1154642
+ * @param {HTMLElemnt} el - a DOM node
+ * @returns {Boolean} true/false
+ */
+ this.hasAnchorJSLink = function(el) {
+ var hasLeftAnchor =
+ el.firstChild &&
+ (' ' + el.firstChild.className + ' ').indexOf(' anchorjs-link ') > -1,
+ hasRightAnchor =
+ el.lastChild &&
+ (' ' + el.lastChild.className + ' ').indexOf(' anchorjs-link ') > -1;
+
+ return hasLeftAnchor || hasRightAnchor || false;
+ };
+
+ /**
+ * Turns a selector, nodeList, or array of elements into an array of elements (so we can use array methods).
+ * It also throws errors on any other inputs. Used to handle inputs to .add and .remove.
+ * @param {String|Array|Nodelist} input - A CSS selector string targeting elements with anchor links,
+ * OR a nodeList / array containing the DOM elements.
+ * @returns {Array} - An array containing the elements we want.
+ */
+ function _getElements(input) {
+ var elements;
+ if (typeof input === 'string' || input instanceof String) {
+ // See https://davidwalsh.name/nodelist-array for the technique transforming nodeList -> Array.
+ elements = [].slice.call(document.querySelectorAll(input));
+ // I checked the 'input instanceof NodeList' test in IE9 and modern browsers and it worked for me.
+ } else if (Array.isArray(input) || input instanceof NodeList) {
+ elements = [].slice.call(input);
+ } else {
+ throw new Error('The selector provided to AnchorJS was invalid.');
}
+ return elements;
}
- return this;
- };
-
- this.remove = function(selector) {
- var domAnchor,
- elements = document.querySelectorAll(selector);
- for (var i = 0; i < elements.length; i++) {
- domAnchor = elements[i].querySelector('.anchorjs-link');
- if (domAnchor) {
- elements[i].removeChild(domAnchor);
+ /**
+ * _addBaselineStyles
+ * Adds baseline styles to the page, used by all AnchorJS links irregardless of configuration.
+ */
+ function _addBaselineStyles() {
+ // We don't want to add global baseline styles if they've been added before.
+ if (document.head.querySelector('style.anchorjs') !== null) {
+ return;
}
- }
- return this;
- };
- this._addBaselineStyles = function() {
- // We don't want to add global baseline styles if they've been added before.
- if (document.head.querySelector('style.anchorjs') !== null) {
- return;
- }
-
- var style = document.createElement('style'),
+ var style = document.createElement('style'),
linkRule =
- ' .anchorjs-link {' +
- ' opacity: 0;' +
- ' text-decoration: none;' +
- ' -webkit-font-smoothing: antialiased;' +
- ' -moz-osx-font-smoothing: grayscale;' +
- ' }',
+ ' .anchorjs-link {' +
+ ' opacity: 0;' +
+ ' text-decoration: none;' +
+ ' -webkit-font-smoothing: antialiased;' +
+ ' -moz-osx-font-smoothing: grayscale;' +
+ ' }',
hoverRule =
- ' *:hover > .anchorjs-link,' +
- ' .anchorjs-link:focus {' +
- ' opacity: 1;' +
- ' }',
+ ' *:hover > .anchorjs-link,' +
+ ' .anchorjs-link:focus {' +
+ ' opacity: 1;' +
+ ' }',
anchorjsLinkFontFace =
- ' @font-face {' +
- ' font-family: "anchorjs-icons";' +
- ' font-style: normal;' +
- ' font-weight: normal;' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
- ' src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwT1MvMg8SBTUAAAC8AAAAYGNtYXAWi9QdAAABHAAAAFRnYXNwAAAAEAAAAXAAAAAIZ2x5Zgq29TcAAAF4AAABNGhlYWQEZM3pAAACrAAAADZoaGVhBhUDxgAAAuQAAAAkaG10eASAADEAAAMIAAAAFGxvY2EAKACuAAADHAAAAAxtYXhwAAgAVwAAAygAAAAgbmFtZQ5yJ3cAAANIAAAB2nBvc3QAAwAAAAAFJAAAACAAAwJAAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABEAAAAAAAAAAAAAAAAAAAAABAAADpywPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAAAAAADAAAAAwAAABwAAQADAAAAHAADAAEAAAAcAAQAOAAAAAoACAACAAIAAQAg6cv//f//AAAAAAAg6cv//f//AAH/4xY5AAMAAQAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACADEARAJTAsAAKwBUAAABIiYnJjQ/AT4BMzIWFxYUDwEGIicmND8BNjQnLgEjIgYPAQYUFxYUBw4BIwciJicmND8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFA8BDgEjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAEAAAABAACiToc1Xw889QALBAAAAAAA0XnFFgAAAADRecUWAAAAAAJTAsAAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAAlMAAQAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAACAAAAAoAAMQAAAAAACgAUAB4AmgABAAAABQBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEADgAAAAEAAAAAAAIABwCfAAEAAAAAAAMADgBLAAEAAAAAAAQADgC0AAEAAAAAAAUACwAqAAEAAAAAAAYADgB1AAEAAAAAAAoAGgDeAAMAAQQJAAEAHAAOAAMAAQQJAAIADgCmAAMAAQQJAAMAHABZAAMAAQQJAAQAHADCAAMAAQQJAAUAFgA1AAMAAQQJAAYAHACDAAMAAQQJAAoANAD4YW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzUmVndWxhcgBSAGUAZwB1AGwAYQByYW5jaG9yanMtaWNvbnMAYQBuAGMAaABvAHIAagBzAC0AaQBjAG8AbgBzRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==) format("truetype");' +
- ' }',
+ ' @font-face {' +
+ ' font-family: "anchorjs-icons";' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
+ ' src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype");' +
+ ' }',
pseudoElContent =
- ' [data-anchorjs-icon]::after {' +
- ' content: attr(data-anchorjs-icon);' +
- ' }',
+ ' [data-anchorjs-icon]::after {' +
+ ' content: attr(data-anchorjs-icon);' +
+ ' }',
firstStyleEl;
- style.className = 'anchorjs';
- style.appendChild(document.createTextNode('')); // Necessary for Webkit.
+ style.className = 'anchorjs';
+ style.appendChild(document.createTextNode('')); // Necessary for Webkit.
- // We place it in the head with the other style tags, if possible, so as to
- // not look out of place. We insert before the others so these styles can be
- // overridden if necessary.
- firstStyleEl = document.head.querySelector('[rel="stylesheet"], style');
- if (firstStyleEl === undefined) {
- document.head.appendChild(style);
- } else {
- document.head.insertBefore(style, firstStyleEl);
+ // We place it in the head with the other style tags, if possible, so as to
+ // not look out of place. We insert before the others so these styles can be
+ // overridden if necessary.
+ firstStyleEl = document.head.querySelector('[rel="stylesheet"], style');
+ if (firstStyleEl === undefined) {
+ document.head.appendChild(style);
+ } else {
+ document.head.insertBefore(style, firstStyleEl);
+ }
+
+ style.sheet.insertRule(linkRule, style.sheet.cssRules.length);
+ style.sheet.insertRule(hoverRule, style.sheet.cssRules.length);
+ style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length);
+ style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length);
}
+ }
- style.sheet.insertRule(linkRule, style.sheet.cssRules.length);
- style.sheet.insertRule(hoverRule, style.sheet.cssRules.length);
- style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length);
- style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length);
- };
-}
-
-var anchors = new AnchorJS();
+ return AnchorJS;
+});
diff --git a/docs/assets/bass.css b/docs/assets/bass.css
index 15e0dc9..2d860c5 100644
--- a/docs/assets/bass.css
+++ b/docs/assets/bass.css
@@ -457,6 +457,7 @@
min-height:0;
}
.flex-none{ -webkit-box-flex:0; -webkit-flex:none; -ms-flex:none; flex:none }
+.fs0{ flex-shrink: 0 }
.order-0{ -webkit-box-ordinal-group:1; -webkit-order:0; -ms-flex-order:0; order:0 }
.order-1{ -webkit-box-ordinal-group:2; -webkit-order:1; -ms-flex-order:1; order:1 }
diff --git a/docs/assets/fonts/source-code-pro/LICENSE.txt b/docs/assets/fonts/source-code-pro/LICENSE.txt
deleted file mode 100755
index d154618..0000000
--- a/docs/assets/fonts/source-code-pro/LICENSE.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/docs/assets/fonts/source-code-pro/README.md b/docs/assets/fonts/source-code-pro/README.md
deleted file mode 100755
index 20be1f3..0000000
--- a/docs/assets/fonts/source-code-pro/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Source Code Pro
-
-Source Code Pro is a set of OpenType fonts that have been designed to work well
-in user interface (UI) environments. In addition to a functional OpenType font, this open
-source project provides all of the source files that were used to build this OpenType font
-by using the AFDKO makeotf tool.
-
-## Font installation instructions
-
-* [Mac OS X](http://support.apple.com/kb/HT2509)
-* [Windows](http://windows.microsoft.com/en-us/windows-vista/install-or-uninstall-fonts)
-* [Linux/Unix-based systems](https://github.com/adobe-fonts/source-code-pro/issues/17#issuecomment-8967116)
-
-## Getting Involved
-
-Send suggestions for changes to the Source Code OpenType font project maintainer, [Paul D. Hunt](mailto:opensourcefonts@adobe.com?subject=[GitHub] Source Code Pro), for consideration.
-
-## Further information
-
-For information about the design and background of Source Code, please refer to the [official font readme file](http://www.adobe.com/products/type/font-information/source-code-pro-readme.html).
diff --git a/docs/assets/fonts/source-code-pro/WOFF/OTF/SourceCodePro-Regular.otf.woff b/docs/assets/fonts/source-code-pro/WOFF/OTF/SourceCodePro-Regular.otf.woff
deleted file mode 100755
index 395436e..0000000
Binary files a/docs/assets/fonts/source-code-pro/WOFF/OTF/SourceCodePro-Regular.otf.woff and /dev/null differ
diff --git a/docs/assets/fonts/source-code-pro/source-code-pro.css b/docs/assets/fonts/source-code-pro/source-code-pro.css
deleted file mode 100755
index 842b232..0000000
--- a/docs/assets/fonts/source-code-pro/source-code-pro.css
+++ /dev/null
@@ -1,15 +0,0 @@
-@font-face{
- font-family: 'Source Code Pro';
- font-weight: 400;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceCodePro-Regular.otf.woff') format('woff');
-}
-
-@font-face{
- font-family: 'Source Code Pro';
- font-weight: 500;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceCodePro-Medium.otf.woff') format('woff');
-}
diff --git a/docs/assets/fonts/source-sans-pro/LICENSE.txt b/docs/assets/fonts/source-sans-pro/LICENSE.txt
deleted file mode 100755
index 87ec82c..0000000
--- a/docs/assets/fonts/source-sans-pro/LICENSE.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/docs/assets/fonts/source-sans-pro/README.md b/docs/assets/fonts/source-sans-pro/README.md
deleted file mode 100755
index a3e1b9d..0000000
--- a/docs/assets/fonts/source-sans-pro/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Source Sans Pro
-
-Source Sans Pro is a set of OpenType fonts that have been designed to work well
-in user interface (UI) environments. In addition to a functional OpenType font, this open
-source project provides all of the source files that were used to build this OpenType font
-by using the AFDKO makeotf tool.
-
-## Font installation instructions
-
-* [Mac OS X](http://support.apple.com/kb/HT2509)
-* [Windows](http://windows.microsoft.com/en-us/windows-vista/install-or-uninstall-fonts)
-* [Linux/Unix-based systems](https://github.com/adobe-fonts/source-code-pro/issues/17#issuecomment-8967116)
-
-## Getting Involved
-
-Send suggestions for changes to the Source Sans OpenType font project maintainer, [Paul D. Hunt](mailto:opensourcefonts@adobe.com?subject=[GitHub] Source Sans Pro), for consideration.
-
-## Further information
-
-For information about the design and background of Source Sans, please refer to the [official font readme file](http://www.adobe.com/products/type/font-information/source-sans-pro-readme.html).
diff --git a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Bold.otf.woff b/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Bold.otf.woff
deleted file mode 100755
index 6700893..0000000
Binary files a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Bold.otf.woff and /dev/null differ
diff --git a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Light.otf.woff b/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Light.otf.woff
deleted file mode 100755
index 10490ec..0000000
Binary files a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Light.otf.woff and /dev/null differ
diff --git a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Regular.otf.woff b/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Regular.otf.woff
deleted file mode 100755
index 04739e7..0000000
Binary files a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Regular.otf.woff and /dev/null differ
diff --git a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Semibold.otf.woff b/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Semibold.otf.woff
deleted file mode 100755
index 17d744d..0000000
Binary files a/docs/assets/fonts/source-sans-pro/WOFF/OTF/SourceSansPro-Semibold.otf.woff and /dev/null differ
diff --git a/docs/assets/fonts/source-sans-pro/bower.json b/docs/assets/fonts/source-sans-pro/bower.json
deleted file mode 100755
index dfe14f2..0000000
--- a/docs/assets/fonts/source-sans-pro/bower.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "source-sans-pro",
- "version": "2.020R-ro/1.075R-it",
- "main": "source-sans-pro.css",
- "homepage": "https://github.com/adobe-fonts/source-sans-pro",
- "repository": {
- "type": "git",
- "url": "https://github.com/adobe-fonts/source-sans-pro.git"
- },
- "authors": [
- { "name": "Paul D. Hunt" }
- ],
- "description": "Source Sans Pro font family by Adobe",
- "license": "SIL OFL 1.1",
- "keywords": ["font", "sourcesans", "sourcesanspro", "source sans", "source sans pro"],
- "ignore": ["**/.*"]
-}
diff --git a/docs/assets/fonts/source-sans-pro/source-sans-pro.css b/docs/assets/fonts/source-sans-pro/source-sans-pro.css
deleted file mode 100755
index 6d3862c..0000000
--- a/docs/assets/fonts/source-sans-pro/source-sans-pro.css
+++ /dev/null
@@ -1,31 +0,0 @@
-@font-face{
- font-family: 'Source Sans Pro';
- font-weight: 300;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceSansPro-Light.otf.woff') format('woff');
-}
-
-@font-face{
- font-family: 'Source Sans Pro';
- font-weight: 400;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceSansPro-Regular.otf.woff') format('woff');
-}
-
-@font-face{
- font-family: 'Source Sans Pro';
- font-weight: 600;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceSansPro-Semibold.otf.woff') format('woff');
-}
-
-@font-face{
- font-family: 'Source Sans Pro';
- font-weight: 700;
- font-style: normal;
- font-stretch: normal;
- src: url('WOFF/OTF/SourceSansPro-Bold.otf.woff') format('woff');
-}
diff --git a/docs/assets/site.js b/docs/assets/site.js
index 559c65e..f86584f 100644
--- a/docs/assets/site.js
+++ b/docs/assets/site.js
@@ -5,65 +5,46 @@ anchors.options.placement = 'left';
anchors.add('h3');
// Filter UI
-var tocElements = document.getElementById('toc')
- .getElementsByTagName('li');
+var tocElements = document.getElementById('toc').getElementsByTagName('li');
-document.getElementById('filter-input')
- .addEventListener('keyup', function (e) {
-
- var i, element, children;
-
- // enter key
- if (e.keyCode === 13) {
- // go to the first displayed item in the toc
- for (i = 0; i < tocElements.length; i++) {
- element = tocElements[i];
- if (!element.classList.contains('display-none')) {
- location.replace(element.firstChild.href);
- return e.preventDefault();
- }
- }
- }
-
- var match = function () {
- return true;
- };
-
- var value = this.value.toLowerCase();
-
- if (!value.match(/^\s*$/)) {
- match = function (element) {
- return element.firstChild.innerHTML.toLowerCase().indexOf(value) !== -1;
- };
- }
+document.getElementById('filter-input').addEventListener('keyup', function(e) {
+ var i, element, children;
+ // enter key
+ if (e.keyCode === 13) {
+ // go to the first displayed item in the toc
for (i = 0; i < tocElements.length; i++) {
element = tocElements[i];
- children = Array.from(element.getElementsByTagName('li'));
- if (match(element) || children.some(match)) {
- element.classList.remove('display-none');
- } else {
- element.classList.add('display-none');
+ if (!element.classList.contains('display-none')) {
+ location.replace(element.firstChild.href);
+ return e.preventDefault();
}
}
- });
-
-var toggles = document.getElementsByClassName('toggle-step-sibling');
-for (var i = 0; i < toggles.length; i++) {
- toggles[i].addEventListener('click', toggleStepSibling);
-}
-
-function toggleStepSibling() {
- var stepSibling = this.parentNode.parentNode.parentNode.getElementsByClassName('toggle-target')[0];
- var klass = 'display-none';
- if (stepSibling.classList.contains(klass)) {
- stepSibling.classList.remove(klass);
- stepSibling.innerHTML = '▾';
- } else {
- stepSibling.classList.add(klass);
- stepSibling.innerHTML = '▸';
}
-}
+
+ var match = function() {
+ return true;
+ };
+
+ var value = this.value.toLowerCase();
+
+ if (!value.match(/^\s*$/)) {
+ match = function(element) {
+ var html = element.firstChild.innerHTML;
+ return html && html.toLowerCase().indexOf(value) !== -1;
+ };
+ }
+
+ for (i = 0; i < tocElements.length; i++) {
+ element = tocElements[i];
+ children = Array.from(element.getElementsByTagName('li'));
+ if (match(element) || children.some(match)) {
+ element.classList.remove('display-none');
+ } else {
+ element.classList.add('display-none');
+ }
+ }
+});
var items = document.getElementsByClassName('toggle-sibling');
for (var j = 0; j < items.length; j++) {
@@ -84,19 +65,36 @@ function toggleSibling() {
}
function showHashTarget(targetId) {
- var hashTarget = document.getElementById(targetId);
- // new target is hidden
- if (hashTarget && hashTarget.offsetHeight === 0 &&
- hashTarget.parentNode.parentNode.classList.contains('display-none')) {
- hashTarget.parentNode.parentNode.classList.remove('display-none');
+ if (targetId) {
+ var hashTarget = document.getElementById(targetId);
+ // new target is hidden
+ if (
+ hashTarget &&
+ hashTarget.offsetHeight === 0 &&
+ hashTarget.parentNode.parentNode.classList.contains('display-none')
+ ) {
+ hashTarget.parentNode.parentNode.classList.remove('display-none');
+ }
}
}
-window.addEventListener('hashchange', function() {
- showHashTarget(location.hash.substring(1));
-});
+function scrollIntoView(targetId) {
+ // Only scroll to element if we don't have a stored scroll position.
+ if (targetId && !history.state) {
+ var hashTarget = document.getElementById(targetId);
+ if (hashTarget) {
+ hashTarget.scrollIntoView();
+ }
+ }
+}
-showHashTarget(location.hash.substring(1));
+function gotoCurrentTarget() {
+ showHashTarget(location.hash.substring(1));
+ scrollIntoView(location.hash.substring(1));
+}
+
+window.addEventListener('hashchange', gotoCurrentTarget);
+gotoCurrentTarget();
var toclinks = document.getElementsByClassName('pre-open');
for (var k = 0; k < toclinks.length; k++) {
@@ -106,3 +104,65 @@ for (var k = 0; k < toclinks.length; k++) {
function preOpen() {
showHashTarget(this.hash.substring(1));
}
+
+var split_left = document.querySelector('#split-left');
+var split_right = document.querySelector('#split-right');
+var split_parent = split_left.parentNode;
+var cw_with_sb = split_left.clientWidth;
+split_left.style.overflow = 'hidden';
+var cw_without_sb = split_left.clientWidth;
+split_left.style.overflow = '';
+
+Split(['#split-left', '#split-right'], {
+ elementStyle: function(dimension, size, gutterSize) {
+ return {
+ 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)'
+ };
+ },
+ gutterStyle: function(dimension, gutterSize) {
+ return {
+ 'flex-basis': gutterSize + 'px'
+ };
+ },
+ gutterSize: 20,
+ sizes: [33, 67]
+});
+
+// Chrome doesn't remember scroll position properly so do it ourselves.
+// Also works on Firefox and Edge.
+
+function updateState() {
+ history.replaceState(
+ {
+ left_top: split_left.scrollTop,
+ right_top: split_right.scrollTop
+ },
+ document.title
+ );
+}
+
+function loadState(ev) {
+ if (ev) {
+ // Edge doesn't replace change history.state on popstate.
+ history.replaceState(ev.state, document.title);
+ }
+ if (history.state) {
+ split_left.scrollTop = history.state.left_top;
+ split_right.scrollTop = history.state.right_top;
+ }
+}
+
+window.addEventListener('load', function() {
+ // Restore after Firefox scrolls to hash.
+ setTimeout(function() {
+ loadState();
+ // Update with initial scroll position.
+ updateState();
+ // Update scroll positions only after we've loaded because Firefox
+ // emits an initial scroll event with 0.
+ split_left.addEventListener('scroll', updateState);
+ split_right.addEventListener('scroll', updateState);
+ }, 1);
+});
+
+window.addEventListener('popstate', loadState);
diff --git a/docs/assets/split.css b/docs/assets/split.css
new file mode 100644
index 0000000..2d7779e
--- /dev/null
+++ b/docs/assets/split.css
@@ -0,0 +1,15 @@
+.gutter {
+ background-color: #f5f5f5;
+ background-repeat: no-repeat;
+ background-position: 50%;
+}
+
+.gutter.gutter-vertical {
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=');
+ cursor: ns-resize;
+}
+
+.gutter.gutter-horizontal {
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
+ cursor: ew-resize;
+}
diff --git a/docs/assets/split.js b/docs/assets/split.js
new file mode 100644
index 0000000..2c52481
--- /dev/null
+++ b/docs/assets/split.js
@@ -0,0 +1,586 @@
+/*! Split.js - v1.3.5 */
+// https://github.com/nathancahill/Split.js
+// Copyright (c) 2017 Nathan Cahill; Licensed MIT
+
+(function(global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined'
+ ? (module.exports = factory())
+ : typeof define === 'function' && define.amd
+ ? define(factory)
+ : (global.Split = factory());
+})(this, function() {
+ 'use strict';
+ // The programming goals of Split.js are to deliver readable, understandable and
+ // maintainable code, while at the same time manually optimizing for tiny minified file size,
+ // browser compatibility without additional requirements, graceful fallback (IE8 is supported)
+ // and very few assumptions about the user's page layout.
+ var global = window;
+ var document = global.document;
+
+ // Save a couple long function names that are used frequently.
+ // This optimization saves around 400 bytes.
+ var addEventListener = 'addEventListener';
+ var removeEventListener = 'removeEventListener';
+ var getBoundingClientRect = 'getBoundingClientRect';
+ var NOOP = function() {
+ return false;
+ };
+
+ // Figure out if we're in IE8 or not. IE8 will still render correctly,
+ // but will be static instead of draggable.
+ var isIE8 = global.attachEvent && !global[addEventListener];
+
+ // This library only needs two helper functions:
+ //
+ // The first determines which prefixes of CSS calc we need.
+ // We only need to do this once on startup, when this anonymous function is called.
+ //
+ // Tests -webkit, -moz and -o prefixes. Modified from StackOverflow:
+ // http://stackoverflow.com/questions/16625140/js-feature-detection-to-detect-the-usage-of-webkit-calc-over-calc/16625167#16625167
+ var calc =
+ ['', '-webkit-', '-moz-', '-o-']
+ .filter(function(prefix) {
+ var el = document.createElement('div');
+ el.style.cssText = 'width:' + prefix + 'calc(9px)';
+
+ return !!el.style.length;
+ })
+ .shift() + 'calc';
+
+ // The second helper function allows elements and string selectors to be used
+ // interchangeably. In either case an element is returned. This allows us to
+ // do `Split([elem1, elem2])` as well as `Split(['#id1', '#id2'])`.
+ var elementOrSelector = function(el) {
+ if (typeof el === 'string' || el instanceof String) {
+ return document.querySelector(el);
+ }
+
+ return el;
+ };
+
+ // The main function to initialize a split. Split.js thinks about each pair
+ // of elements as an independant pair. Dragging the gutter between two elements
+ // only changes the dimensions of elements in that pair. This is key to understanding
+ // how the following functions operate, since each function is bound to a pair.
+ //
+ // A pair object is shaped like this:
+ //
+ // {
+ // a: DOM element,
+ // b: DOM element,
+ // aMin: Number,
+ // bMin: Number,
+ // dragging: Boolean,
+ // parent: DOM element,
+ // isFirst: Boolean,
+ // isLast: Boolean,
+ // direction: 'horizontal' | 'vertical'
+ // }
+ //
+ // The basic sequence:
+ //
+ // 1. Set defaults to something sane. `options` doesn't have to be passed at all.
+ // 2. Initialize a bunch of strings based on the direction we're splitting.
+ // A lot of the behavior in the rest of the library is paramatized down to
+ // rely on CSS strings and classes.
+ // 3. Define the dragging helper functions, and a few helpers to go with them.
+ // 4. Loop through the elements while pairing them off. Every pair gets an
+ // `pair` object, a gutter, and special isFirst/isLast properties.
+ // 5. Actually size the pair elements, insert gutters and attach event listeners.
+ var Split = function(ids, options) {
+ if (options === void 0) options = {};
+
+ var dimension;
+ var clientDimension;
+ var clientAxis;
+ var position;
+ var paddingA;
+ var paddingB;
+ var elements;
+
+ // All DOM elements in the split should have a common parent. We can grab
+ // the first elements parent and hope users read the docs because the
+ // behavior will be whacky otherwise.
+ var parent = elementOrSelector(ids[0]).parentNode;
+ var parentFlexDirection = global.getComputedStyle(parent).flexDirection;
+
+ // Set default options.sizes to equal percentages of the parent element.
+ var sizes =
+ options.sizes ||
+ ids.map(function() {
+ return 100 / ids.length;
+ });
+
+ // Standardize minSize to an array if it isn't already. This allows minSize
+ // to be passed as a number.
+ var minSize = options.minSize !== undefined ? options.minSize : 100;
+ var minSizes = Array.isArray(minSize)
+ ? minSize
+ : ids.map(function() {
+ return minSize;
+ });
+ var gutterSize = options.gutterSize !== undefined ? options.gutterSize : 10;
+ var snapOffset = options.snapOffset !== undefined ? options.snapOffset : 30;
+ var direction = options.direction || 'horizontal';
+ var cursor =
+ options.cursor ||
+ (direction === 'horizontal' ? 'ew-resize' : 'ns-resize');
+ var gutter =
+ options.gutter ||
+ function(i, gutterDirection) {
+ var gut = document.createElement('div');
+ gut.className = 'gutter gutter-' + gutterDirection;
+ return gut;
+ };
+ var elementStyle =
+ options.elementStyle ||
+ function(dim, size, gutSize) {
+ var style = {};
+
+ if (typeof size !== 'string' && !(size instanceof String)) {
+ if (!isIE8) {
+ style[dim] = calc + '(' + size + '% - ' + gutSize + 'px)';
+ } else {
+ style[dim] = size + '%';
+ }
+ } else {
+ style[dim] = size;
+ }
+
+ return style;
+ };
+ var gutterStyle =
+ options.gutterStyle ||
+ function(dim, gutSize) {
+ return (obj = {}), (obj[dim] = gutSize + 'px'), obj;
+ var obj;
+ };
+
+ // 2. Initialize a bunch of strings based on the direction we're splitting.
+ // A lot of the behavior in the rest of the library is paramatized down to
+ // rely on CSS strings and classes.
+ if (direction === 'horizontal') {
+ dimension = 'width';
+ clientDimension = 'clientWidth';
+ clientAxis = 'clientX';
+ position = 'left';
+ paddingA = 'paddingLeft';
+ paddingB = 'paddingRight';
+ } else if (direction === 'vertical') {
+ dimension = 'height';
+ clientDimension = 'clientHeight';
+ clientAxis = 'clientY';
+ position = 'top';
+ paddingA = 'paddingTop';
+ paddingB = 'paddingBottom';
+ }
+
+ // 3. Define the dragging helper functions, and a few helpers to go with them.
+ // Each helper is bound to a pair object that contains it's metadata. This
+ // also makes it easy to store references to listeners that that will be
+ // added and removed.
+ //
+ // Even though there are no other functions contained in them, aliasing
+ // this to self saves 50 bytes or so since it's used so frequently.
+ //
+ // The pair object saves metadata like dragging state, position and
+ // event listener references.
+
+ function setElementSize(el, size, gutSize) {
+ // Split.js allows setting sizes via numbers (ideally), or if you must,
+ // by string, like '300px'. This is less than ideal, because it breaks
+ // the fluid layout that `calc(% - px)` provides. You're on your own if you do that,
+ // make sure you calculate the gutter size by hand.
+ var style = elementStyle(dimension, size, gutSize);
+
+ // eslint-disable-next-line no-param-reassign
+ Object.keys(style).forEach(function(prop) {
+ return (el.style[prop] = style[prop]);
+ });
+ }
+
+ function setGutterSize(gutterElement, gutSize) {
+ var style = gutterStyle(dimension, gutSize);
+
+ // eslint-disable-next-line no-param-reassign
+ Object.keys(style).forEach(function(prop) {
+ return (gutterElement.style[prop] = style[prop]);
+ });
+ }
+
+ // Actually adjust the size of elements `a` and `b` to `offset` while dragging.
+ // calc is used to allow calc(percentage + gutterpx) on the whole split instance,
+ // which allows the viewport to be resized without additional logic.
+ // Element a's size is the same as offset. b's size is total size - a size.
+ // Both sizes are calculated from the initial parent percentage,
+ // then the gutter size is subtracted.
+ function adjust(offset) {
+ var a = elements[this.a];
+ var b = elements[this.b];
+ var percentage = a.size + b.size;
+
+ a.size = offset / this.size * percentage;
+ b.size = percentage - offset / this.size * percentage;
+
+ setElementSize(a.element, a.size, this.aGutterSize);
+ setElementSize(b.element, b.size, this.bGutterSize);
+ }
+
+ // drag, where all the magic happens. The logic is really quite simple:
+ //
+ // 1. Ignore if the pair is not dragging.
+ // 2. Get the offset of the event.
+ // 3. Snap offset to min if within snappable range (within min + snapOffset).
+ // 4. Actually adjust each element in the pair to offset.
+ //
+ // ---------------------------------------------------------------------
+ // | | <- a.minSize || b.minSize -> | |
+ // | | | <- this.snapOffset || this.snapOffset -> | | |
+ // | | | || | | |
+ // | | | || | | |
+ // ---------------------------------------------------------------------
+ // | <- this.start this.size -> |
+ function drag(e) {
+ var offset;
+
+ if (!this.dragging) {
+ return;
+ }
+
+ // Get the offset of the event from the first side of the
+ // pair `this.start`. Supports touch events, but not multitouch, so only the first
+ // finger `touches[0]` is counted.
+ if ('touches' in e) {
+ offset = e.touches[0][clientAxis] - this.start;
+ } else {
+ offset = e[clientAxis] - this.start;
+ }
+
+ // If within snapOffset of min or max, set offset to min or max.
+ // snapOffset buffers a.minSize and b.minSize, so logic is opposite for both.
+ // Include the appropriate gutter sizes to prevent overflows.
+ if (offset <= elements[this.a].minSize + snapOffset + this.aGutterSize) {
+ offset = elements[this.a].minSize + this.aGutterSize;
+ } else if (
+ offset >=
+ this.size - (elements[this.b].minSize + snapOffset + this.bGutterSize)
+ ) {
+ offset = this.size - (elements[this.b].minSize + this.bGutterSize);
+ }
+
+ // Actually adjust the size.
+ adjust.call(this, offset);
+
+ // Call the drag callback continously. Don't do anything too intensive
+ // in this callback.
+ if (options.onDrag) {
+ options.onDrag();
+ }
+ }
+
+ // Cache some important sizes when drag starts, so we don't have to do that
+ // continously:
+ //
+ // `size`: The total size of the pair. First + second + first gutter + second gutter.
+ // `start`: The leading side of the first element.
+ //
+ // ------------------------------------------------
+ // | aGutterSize -> ||| |
+ // | ||| |
+ // | ||| |
+ // | ||| <- bGutterSize |
+ // ------------------------------------------------
+ // | <- start size -> |
+ function calculateSizes() {
+ // Figure out the parent size minus padding.
+ var a = elements[this.a].element;
+ var b = elements[this.b].element;
+
+ this.size =
+ a[getBoundingClientRect]()[dimension] +
+ b[getBoundingClientRect]()[dimension] +
+ this.aGutterSize +
+ this.bGutterSize;
+ this.start = a[getBoundingClientRect]()[position];
+ }
+
+ // stopDragging is very similar to startDragging in reverse.
+ function stopDragging() {
+ var self = this;
+ var a = elements[self.a].element;
+ var b = elements[self.b].element;
+
+ if (self.dragging && options.onDragEnd) {
+ options.onDragEnd();
+ }
+
+ self.dragging = false;
+
+ // Remove the stored event listeners. This is why we store them.
+ global[removeEventListener]('mouseup', self.stop);
+ global[removeEventListener]('touchend', self.stop);
+ global[removeEventListener]('touchcancel', self.stop);
+
+ self.parent[removeEventListener]('mousemove', self.move);
+ self.parent[removeEventListener]('touchmove', self.move);
+
+ // Delete them once they are removed. I think this makes a difference
+ // in memory usage with a lot of splits on one page. But I don't know for sure.
+ delete self.stop;
+ delete self.move;
+
+ a[removeEventListener]('selectstart', NOOP);
+ a[removeEventListener]('dragstart', NOOP);
+ b[removeEventListener]('selectstart', NOOP);
+ b[removeEventListener]('dragstart', NOOP);
+
+ a.style.userSelect = '';
+ a.style.webkitUserSelect = '';
+ a.style.MozUserSelect = '';
+ a.style.pointerEvents = '';
+
+ b.style.userSelect = '';
+ b.style.webkitUserSelect = '';
+ b.style.MozUserSelect = '';
+ b.style.pointerEvents = '';
+
+ self.gutter.style.cursor = '';
+ self.parent.style.cursor = '';
+ }
+
+ // startDragging calls `calculateSizes` to store the inital size in the pair object.
+ // It also adds event listeners for mouse/touch events,
+ // and prevents selection while dragging so avoid the selecting text.
+ function startDragging(e) {
+ // Alias frequently used variables to save space. 200 bytes.
+ var self = this;
+ var a = elements[self.a].element;
+ var b = elements[self.b].element;
+
+ // Call the onDragStart callback.
+ if (!self.dragging && options.onDragStart) {
+ options.onDragStart();
+ }
+
+ // Don't actually drag the element. We emulate that in the drag function.
+ e.preventDefault();
+
+ // Set the dragging property of the pair object.
+ self.dragging = true;
+
+ // Create two event listeners bound to the same pair object and store
+ // them in the pair object.
+ self.move = drag.bind(self);
+ self.stop = stopDragging.bind(self);
+
+ // All the binding. `window` gets the stop events in case we drag out of the elements.
+ global[addEventListener]('mouseup', self.stop);
+ global[addEventListener]('touchend', self.stop);
+ global[addEventListener]('touchcancel', self.stop);
+
+ self.parent[addEventListener]('mousemove', self.move);
+ self.parent[addEventListener]('touchmove', self.move);
+
+ // Disable selection. Disable!
+ a[addEventListener]('selectstart', NOOP);
+ a[addEventListener]('dragstart', NOOP);
+ b[addEventListener]('selectstart', NOOP);
+ b[addEventListener]('dragstart', NOOP);
+
+ a.style.userSelect = 'none';
+ a.style.webkitUserSelect = 'none';
+ a.style.MozUserSelect = 'none';
+ a.style.pointerEvents = 'none';
+
+ b.style.userSelect = 'none';
+ b.style.webkitUserSelect = 'none';
+ b.style.MozUserSelect = 'none';
+ b.style.pointerEvents = 'none';
+
+ // Set the cursor, both on the gutter and the parent element.
+ // Doing only a, b and gutter causes flickering.
+ self.gutter.style.cursor = cursor;
+ self.parent.style.cursor = cursor;
+
+ // Cache the initial sizes of the pair.
+ calculateSizes.call(self);
+ }
+
+ // 5. Create pair and element objects. Each pair has an index reference to
+ // elements `a` and `b` of the pair (first and second elements).
+ // Loop through the elements while pairing them off. Every pair gets a
+ // `pair` object, a gutter, and isFirst/isLast properties.
+ //
+ // Basic logic:
+ //
+ // - Starting with the second element `i > 0`, create `pair` objects with
+ // `a = i - 1` and `b = i`
+ // - Set gutter sizes based on the _pair_ being first/last. The first and last
+ // pair have gutterSize / 2, since they only have one half gutter, and not two.
+ // - Create gutter elements and add event listeners.
+ // - Set the size of the elements, minus the gutter sizes.
+ //
+ // -----------------------------------------------------------------------
+ // | i=0 | i=1 | i=2 | i=3 |
+ // | | isFirst | | isLast |
+ // | pair 0 pair 1 pair 2 |
+ // | | | | |
+ // -----------------------------------------------------------------------
+ var pairs = [];
+ elements = ids.map(function(id, i) {
+ // Create the element object.
+ var element = {
+ element: elementOrSelector(id),
+ size: sizes[i],
+ minSize: minSizes[i]
+ };
+
+ var pair;
+
+ if (i > 0) {
+ // Create the pair object with it's metadata.
+ pair = {
+ a: i - 1,
+ b: i,
+ dragging: false,
+ isFirst: i === 1,
+ isLast: i === ids.length - 1,
+ direction: direction,
+ parent: parent
+ };
+
+ // For first and last pairs, first and last gutter width is half.
+ pair.aGutterSize = gutterSize;
+ pair.bGutterSize = gutterSize;
+
+ if (pair.isFirst) {
+ pair.aGutterSize = gutterSize / 2;
+ }
+
+ if (pair.isLast) {
+ pair.bGutterSize = gutterSize / 2;
+ }
+
+ // if the parent has a reverse flex-direction, switch the pair elements.
+ if (
+ parentFlexDirection === 'row-reverse' ||
+ parentFlexDirection === 'column-reverse'
+ ) {
+ var temp = pair.a;
+ pair.a = pair.b;
+ pair.b = temp;
+ }
+ }
+
+ // Determine the size of the current element. IE8 is supported by
+ // staticly assigning sizes without draggable gutters. Assigns a string
+ // to `size`.
+ //
+ // IE9 and above
+ if (!isIE8) {
+ // Create gutter elements for each pair.
+ if (i > 0) {
+ var gutterElement = gutter(i, direction);
+ setGutterSize(gutterElement, gutterSize);
+
+ gutterElement[addEventListener](
+ 'mousedown',
+ startDragging.bind(pair)
+ );
+ gutterElement[addEventListener](
+ 'touchstart',
+ startDragging.bind(pair)
+ );
+
+ parent.insertBefore(gutterElement, element.element);
+
+ pair.gutter = gutterElement;
+ }
+ }
+
+ // Set the element size to our determined size.
+ // Half-size gutters for first and last elements.
+ if (i === 0 || i === ids.length - 1) {
+ setElementSize(element.element, element.size, gutterSize / 2);
+ } else {
+ setElementSize(element.element, element.size, gutterSize);
+ }
+
+ var computedSize = element.element[getBoundingClientRect]()[dimension];
+
+ if (computedSize < element.minSize) {
+ element.minSize = computedSize;
+ }
+
+ // After the first iteration, and we have a pair object, append it to the
+ // list of pairs.
+ if (i > 0) {
+ pairs.push(pair);
+ }
+
+ return element;
+ });
+
+ function setSizes(newSizes) {
+ newSizes.forEach(function(newSize, i) {
+ if (i > 0) {
+ var pair = pairs[i - 1];
+ var a = elements[pair.a];
+ var b = elements[pair.b];
+
+ a.size = newSizes[i - 1];
+ b.size = newSize;
+
+ setElementSize(a.element, a.size, pair.aGutterSize);
+ setElementSize(b.element, b.size, pair.bGutterSize);
+ }
+ });
+ }
+
+ function destroy() {
+ pairs.forEach(function(pair) {
+ pair.parent.removeChild(pair.gutter);
+ elements[pair.a].element.style[dimension] = '';
+ elements[pair.b].element.style[dimension] = '';
+ });
+ }
+
+ if (isIE8) {
+ return {
+ setSizes: setSizes,
+ destroy: destroy
+ };
+ }
+
+ return {
+ setSizes: setSizes,
+ getSizes: function getSizes() {
+ return elements.map(function(element) {
+ return element.size;
+ });
+ },
+ collapse: function collapse(i) {
+ if (i === pairs.length) {
+ var pair = pairs[i - 1];
+
+ calculateSizes.call(pair);
+
+ if (!isIE8) {
+ adjust.call(pair, pair.size - pair.bGutterSize);
+ }
+ } else {
+ var pair$1 = pairs[i];
+
+ calculateSizes.call(pair$1);
+
+ if (!isIE8) {
+ adjust.call(pair$1, pair$1.aGutterSize);
+ }
+ }
+ },
+ destroy: destroy
+ };
+ };
+
+ return Split;
+});
diff --git a/docs/assets/style.css b/docs/assets/style.css
index d7e56e0..5265ea1 100644
--- a/docs/assets/style.css
+++ b/docs/assets/style.css
@@ -46,6 +46,10 @@ a:hover {
max-height: 100%;
}
+.height-viewport-100 {
+ height: 100vh;
+}
+
section:target h3 {
font-weight:700;
}
diff --git a/docs/index.html b/docs/index.html
index aec3a2a..d2f561e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -2,19 +2,19 @@
- field(String) The name of the field to compare to
+ field(String)
+ The name of the field to compare to
@@ -1061,7 +1089,8 @@
- val(String) The value to compare to
+ val(String)
+ The value to compare to
@@ -1069,9 +1098,9 @@
- pos([String]
- (default both)
- ) The placement of the wildcard character(s): before, after, or both
+ pos(String
+ = both)
+ The placement of the wildcard character(s): before, after, or both
- field(String) The name of the field to compare to
+ field(String)
+ The name of the field to compare to
@@ -1145,7 +1176,8 @@
- val(String) The value to compare to
+ val(String)
+ The value to compare to
@@ -1153,9 +1185,9 @@
- pos([String]
- (default both)
- ) The placement of the wildcard character(s): before, after, or both
+ pos(String
+ = both)
+ The placement of the wildcard character(s): before, after, or both
- field(String) The name of the field to compare to
+ field(String)
+ The name of the field to compare to
@@ -1229,7 +1263,8 @@
- val(String) The value to compare to
+ val(String)
+ The value to compare to
@@ -1237,9 +1272,9 @@
- pos([String]
- (default both)
- ) The placement of the wildcard character(s): before, after, or both
+ pos(String
+ = both)
+ The placement of the wildcard character(s): before, after, or both
- field(String) The name of the field to compare to
+ field(String)
+ The name of the field to compare to
@@ -1313,7 +1350,8 @@
- val(String) The value to compare to
+ val(String)
+ The value to compare to
@@ -1321,9 +1359,9 @@
- pos([String]
- (default both)
- ) The placement of the wildcard character(s): before, after, or both
+ pos(String
+ = both)
+ The placement of the wildcard character(s): before, after, or both
- key((String | Object)) The name of the field and the comparision operator, or an object
+ key((String | Object))
+ The name of the field and the comparision operator, or an object
@@ -1397,7 +1437,9 @@
- val([(String | Number)]) The value to compare if the value of key is a string
+ val((String | Number)?
+ = null)
+ The value to compare if the value of key is a string
@@ -1432,11 +1474,11 @@
-
+
▸
- orHaving(key, [val])
+ orHaving(key, val = null)
- key((String | Object)) The name of the field and the comparision operator, or an object
+ key((String | Object))
+ The name of the field and the comparision operator, or an object
@@ -1471,7 +1515,9 @@
- val([(String | Number)]) The value to compare if the value of key is a string
+ val((String | Number)?
+ = null)
+ The value to compare if the value of key is a string
- key((String | Object)) The name of the field and the comparision operator, or an object
+ key((String | Object))
+ The name of the field and the comparision operator, or an object
@@ -1545,7 +1593,8 @@
- val([(String | Number)]) The value to compare if the value of key is a string
+ val((String | Number)?)
+ The value to compare if the value of key is a string
- key((String | Object)) The name of the field and the comparision operator, or an object
+ key((String | Object))
+ The name of the field and the comparision operator, or an object
@@ -1619,7 +1670,8 @@
- val([(String | Number)]) The value to compare if the value of key is a string
+ val((String | Number)?)
+ The value to compare if the value of key is a string
- table(String) The table you are joining
+ table(String)
+ The table you are joining
@@ -2336,7 +2413,8 @@
- cond(String) The join condition.
+ cond(String)
+ The join condition.
@@ -2344,9 +2422,9 @@
- type([String]
- (default 'inner')
- ) The type of join, which defaults to inner
+ type(String
+ = 'inner')
+ The type of join, which defaults to inner
- table(String) The table to insert into
+ table(String)
+ The table to insert into
@@ -2944,7 +3039,8 @@ prefixed with 'OR NOT'
- data([Object]) Data to insert, if not already added with the 'set' method
+ data(Object?)
+ Data to insert, if not already added with the 'set' method
@@ -2958,7 +3054,7 @@ prefixed with 'OR NOT'
Returns
- Promise<Result>:
+ Promise<Result>:
Promise containing the result of the query
@@ -2979,7 +3075,7 @@ prefixed with 'OR NOT'
- table(String) The table to insert into
+ table(String)
+ The table to insert into
@@ -3099,7 +3200,8 @@ prefixed with 'OR NOT'
- data([Object]) Data to insert, if not already added with the 'set' method
+ data(Object?)
+ Data to insert, if not already added with the 'set' method
@@ -3113,7 +3215,7 @@ prefixed with 'OR NOT'
Returns
- Promise<Result>:
+ Promise<Result>:
Promise containing the result of the query
@@ -3134,11 +3236,97 @@ prefixed with 'OR NOT'
- table([String]) the name of the table to retrieve from
+ table(String?)
+ the name of the table to retrieve from
@@ -3247,9 +3440,9 @@ prefixed with 'OR NOT'
- reset([Boolean]
- (default true)
- ) Whether to reset the query builder so another query can be built
+ reset(Boolean
+ = true)
+ Whether to reset the query builder so another query can be built
@@ -3263,7 +3456,7 @@ prefixed with 'OR NOT'
Returns
- String:
+ String:
The compiled sql statement
@@ -3284,11 +3477,11 @@ prefixed with 'OR NOT'
- table(String) the name of the table to insert into
+ table(String)
+ the name of the table to insert into
@@ -3323,9 +3518,9 @@ prefixed with 'OR NOT'
- reset([Boolean]
- (default true)
- ) Whether to reset the query builder so another query can be built
+ reset(Boolean
+ = true)
+ Whether to reset the query builder so another query can be built
@@ -3339,7 +3534,7 @@ prefixed with 'OR NOT'
Returns
- String:
+ String:
The compiled sql statement
@@ -3360,11 +3555,11 @@ prefixed with 'OR NOT'
- table(String) the name of the table to update
+ table(String)
+ the name of the table to update
@@ -3399,9 +3596,9 @@ prefixed with 'OR NOT'
- reset([Boolean]
- (default true)
- ) Whether to reset the query builder so another query can be built
+ reset(Boolean
+ = true)
+ Whether to reset the query builder so another query can be built
@@ -3415,7 +3612,7 @@ prefixed with 'OR NOT'
Returns
- String:
+ String:
The compiled sql statement
@@ -3436,11 +3633,11 @@ prefixed with 'OR NOT'
- table(String) the name of the table to delete from
+ table(String)
+ the name of the table to delete from
@@ -3475,9 +3674,9 @@ prefixed with 'OR NOT'
- reset([Boolean]
- (default true)
- ) Whether to reset the query builder so another query can be built
+ reset(Boolean
+ = true)
+ Whether to reset the query builder so another query can be built
@@ -3491,7 +3690,7 @@ prefixed with 'OR NOT'
Returns
- String:
+ String:
The compiled sql statement
@@ -3538,8 +3737,8 @@ prefixed with 'OR NOT'
/**
+ * Class that wraps database connection libraries
+ *
+ * @private
+ * @param {Promise} instance - The connection object
+ */
+class Adapter {
+ /**
+ * Invoke an adapter
+ *
+ * @constructor
+ * @param {Promise} instance - Promise holding connection object
+ */
+ constructor (instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * Run the sql query as a prepared statement
+ *
+ * @param {String} sql - The sql with placeholders
+ * @param {Array} params - The values to insert into the query
+ * @return {Promise} - returns a promise resolving to the result of the database query
+ */
+ execute (sql, params) {
+ throw new Error('Correct adapter not defined for query execution');
+ }
+
+ /**
+ * Transform the adapter's result into a standard format
+ *
+ * @param {*} originalResult - the original result object from the driver
+ * @return {Result} - the new result object
+ */
+ transformResult (originalResult) {
+ throw new Error('Result transformer method not defined for current adapter');
+ }
+
+ /**
+ * Close the current database connection
+ * @return {void}
+ */
+ close () {
+ this.instance.then(conn => conn.end());
+ }
+}
+
+module.exports = Adapter;
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/documentation/QueryBuilder.js.html b/documentation/QueryBuilder.js.html
new file mode 100644
index 0000000..1238045
--- /dev/null
+++ b/documentation/QueryBuilder.js.html
@@ -0,0 +1,708 @@
+
+
+
+
+ JSDoc: Source: QueryBuilder.js
+
+
+
+
+
+
+
+
+
+
+
+
+
Source: QueryBuilder.js
+
+
+
+
+
+
+
+
+
const Helpers = require('./Helpers');
+const QueryBuilderBase = require('./QueryBuilderBase');
+
+/**
+ * Main object that builds SQL queries.
+ *
+ * @param {Driver} Driver - The syntax driver for the database
+ * @param {Adapter} Adapter - The database module adapter for running queries
+ * @extends QueryBuilderBase
+ */
+class QueryBuilder extends QueryBuilderBase {
+ // ----------------------------------------------------------------------------
+ // ! Miscellaneous Methods
+ // ----------------------------------------------------------------------------
+
+ /**
+ * Run a set of queries from a file
+ *
+ * @param {string} file - The path to the sql file
+ * @param {string} [separator=';'] - The character separating each query
+ * @return {Promise} - The result of all the queries
+ */
+ queryFile (file, separator = ';') {
+ return Helpers.readFile(file).then(sqlFile => {
+ const queries = sqlFile.split(separator);
+ const results = [];
+
+ queries.forEach(sql => {
+ results.push(this.query(sql));
+ });
+
+ return Promise.all(results);
+ });
+ }
+
+ /**
+ * Run an arbitrary sql query. Run as a prepared statement.
+ *
+ * @param {string} sql - The sql to execute
+ * @param {Array} [params] - The query parameters
+ * @return {Promise} - Promise with result of query
+ */
+ query (sql, params) {
+ return this.adapter.execute(sql, params);
+ }
+
+ /**
+ * Reset the object state for a new query
+ *
+ * @return {void}
+ */
+ resetQuery () {
+ this._resetState();
+ }
+
+ /**
+ * Returns the current class state for testing or other purposes
+ *
+ * @private
+ * @return {Object} - The State object
+ */
+ getState () {
+ return this.state;
+ }
+
+ /**
+ * Empties the selected database table
+ *
+ * @param {string} table - the name of the table to truncate
+ * @return {void|Promise} - Returns a promise if no callback is supplied
+ */
+ truncate (table) {
+ return this.query(this.driver.truncate(table));
+ }
+
+ /**
+ * Closes the database connection for the current adapter
+ *
+ * @return {void}
+ */
+ end () {
+ this.adapter.close();
+ }
+
+ // ------------------------------------------------------------------------
+ // ! Query Builder Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Specify rows to select in the query
+ *
+ * @param {String|Array} fields - The fields to select from the current table
+ * @example query.select('foo, bar'); // Select multiple fields with a string
+ * @example query.select(['foo', 'bar']); // Select multiple fileds with an array
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ select (fields) {
+ // Split/trim fields by comma
+ fields = (Array.isArray(fields))
+ ? fields
+ : fields.split(',').map(Helpers.stringTrim);
+
+ // Split on 'As'
+ fields.forEach((field, index) => {
+ if (/as/i.test(field)) {
+ fields[index] = field.split(/ as /i).map(Helpers.stringTrim);
+ }
+ });
+
+ const safeArray = this.driver.quoteIdentifiers(fields);
+
+ // Join the strings back together
+ safeArray.forEach((field, index) => {
+ if (Array.isArray(field)) {
+ safeArray[index] = safeArray[index].join(' AS ');
+ }
+ });
+
+ this.state.selectString += safeArray.join(', ');
+
+ return this;
+ }
+
+ /**
+ * Specify the database table to select from
+ *
+ * @param {String} tableName - The table to use for the current query
+ * @example query.from('tableName');
+ * @example query.from('tableName t'); // Select the table with an alias
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ from (tableName) {
+ // Split identifiers on spaces
+ let identArray = tableName.trim().split(' ').map(Helpers.stringTrim);
+
+ // Quote/prefix identifiers
+ identArray[0] = this.driver.quoteTable(identArray[0]);
+ identArray = this.driver.quoteIdentifiers(identArray);
+
+ // Put it back together
+ this.state.fromString = identArray.join(' ');
+
+ return this;
+ }
+
+ /**
+ * Add a 'like/ and like' clause to the query
+ *
+ * @param {String} field - The name of the field to compare to
+ * @param {String} val - The value to compare to
+ * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ like (field, val, pos) {
+ this._like(field, val, pos, ' LIKE ', 'AND');
+ return this;
+ }
+
+ /**
+ * Add a 'not like/ and not like' clause to the query
+ *
+ * @param {String} field - The name of the field to compare to
+ * @param {String} val - The value to compare to
+ * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ notLike (field, val, pos) {
+ this._like(field, val, pos, ' NOT LIKE ', 'AND');
+ return this;
+ }
+
+ /**
+ * Add an 'or like' clause to the query
+ *
+ * @param {String} field - The name of the field to compare to
+ * @param {String} val - The value to compare to
+ * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orLike (field, val, pos) {
+ this._like(field, val, pos, ' LIKE ', 'OR');
+ return this;
+ }
+
+ /**
+ * Add an 'or not like' clause to the query
+ *
+ * @param {String} field - The name of the field to compare to
+ * @param {String} val - The value to compare to
+ * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orNotLike (field, val, pos) {
+ this._like(field, val, pos, ' NOT LIKE ', 'OR');
+ return this;
+ }
+
+ /**
+ * Add a 'having' clause
+ *
+ * @param {String|Object} key - The name of the field and the comparision operator, or an object
+ * @param {String|Number} [val] - The value to compare if the value of key is a string
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ having (key, val = null) {
+ this._having(key, val, 'AND');
+ return this;
+ }
+
+ /**
+ * Add an 'or having' clause
+ *
+ * @param {String|Object} key - The name of the field and the comparision operator, or an object
+ * @param {String|Number} [val] - The value to compare if the value of key is a string
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orHaving (key, val = null) {
+ this._having(key, val, 'OR');
+ return this;
+ }
+
+ /**
+ * Set a 'where' clause
+ *
+ * @param {String|Object} key - The name of the field and the comparision operator, or an object
+ * @param {String|Number} [val] - The value to compare if the value of key is a string
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ where (key, val) {
+ this._where(key, val, 'AND');
+ return this;
+ }
+
+ /**
+ * Set a 'or where' clause
+ *
+ * @param {String|Object} key - The name of the field and the comparision operator, or an object
+ * @param {String|Number} [val] - The value to compare if the value of key is a string
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orWhere (key, val) {
+ this._where(key, val, 'OR');
+ return this;
+ }
+
+ /**
+ * Select a field that is Null
+ *
+ * @param {String} field - The name of the field that has a NULL value
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ whereIsNull (field) {
+ this._whereNull(field, 'IS NULL', 'AND');
+ return this;
+ }
+
+ /**
+ * Specify that a field IS NOT NULL
+ *
+ * @param {String} field - The name so the field that is not to be null
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ whereIsNotNull (field) {
+ this._whereNull(field, 'IS NOT NULL', 'AND');
+ return this;
+ }
+
+ /**
+ * Field is null prefixed with 'OR'
+ *
+ * @param {String} field - The name of the field
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orWhereIsNull (field) {
+ this._whereNull(field, 'IS NULL', 'OR');
+ return this;
+ }
+
+ /**
+ * Field is not null prefixed with 'OR'
+ *
+ * @param {String} field - The name of the field
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orWhereIsNotNull (field) {
+ this._whereNull(field, 'IS NOT NULL', 'OR');
+ return this;
+ }
+
+ /**
+ * Set a 'where in' clause
+ *
+ * @param {String} key - the field to search
+ * @param {Array} values - the array of items to search in
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ whereIn (key, values) {
+ this._whereIn(key, values, 'IN', 'AND');
+ return this;
+ }
+
+ /**
+ * Set a 'or where in' clause
+ *
+ * @param {String} key - the field to search
+ * @param {Array} values - the array of items to search in
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orWhereIn (key, values) {
+ this._whereIn(key, values, 'IN', 'OR');
+ return this;
+ }
+
+ /**
+ * Set a 'where not in' clause
+ *
+ * @param {String} key - the field to search
+ * @param {Array} values - the array of items to search in
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ whereNotIn (key, values) {
+ this._whereIn(key, values, 'NOT IN', 'AND');
+ return this;
+ }
+
+ /**
+ * Set a 'or where not in' clause
+ *
+ * @param {String} key - the field to search
+ * @param {Array} values - the array of items to search in
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orWhereNotIn (key, values) {
+ this._whereIn(key, values, 'NOT IN', 'OR');
+ return this;
+ }
+
+ /**
+ * Set values for insertion or updating
+ *
+ * @param {String|Object} key - The key or object to use
+ * @param {String} [val] - The value if using a scalar key
+ * @example query.set('foo', 'bar'); // Set a key, value pair
+ * @example query.set({foo:'bar'}); // Set with an object
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ set (key, val) {
+ // Set the appropriate state variables
+ this._mixedSet('setArrayKeys', 'key', key, val);
+ this._mixedSet('values', 'value', key, val);
+
+ // Use the keys of the array to make the insert/update string
+ // and escape the field names
+ this.state.setArrayKeys = this.state.setArrayKeys.map(this.driver._quote);
+
+ // Generate the "set" string
+ this.state.setString = this.state.setArrayKeys.join('=?,');
+ this.state.setString += '=?';
+
+ return this;
+ }
+
+ /**
+ * Add a join clause to the query
+ *
+ * @param {String} table - The table you are joining
+ * @param {String} cond - The join condition.
+ * @param {String} [type='inner'] - The type of join, which defaults to inner
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ join (table, cond, type) {
+ type = type || 'inner';
+
+ // Prefix/quote table name
+ table = table.split(' ').map(Helpers.stringTrim);
+ table[0] = this.driver.quoteTable(table[0]);
+ table = table.map(this.driver.quoteIdentifiers);
+ table = table.join(' ');
+
+ // Parse out the join condition
+ const parsedCondition = this.parser.compileJoin(cond);
+ const condition = `${table} ON ${parsedCondition}`;
+
+ // Append the join condition to the query map
+ this._appendMap(`\n${type.toUpperCase()} JOIN `, condition, 'join');
+
+ return this;
+ }
+
+ /**
+ * Group the results by the selected field(s)
+ *
+ * @param {String|Array} field - The name of the field to group by
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ groupBy (field) {
+ if (!Helpers.isScalar(field)) {
+ const newGroupArray = field.map(this.driver.quoteIdentifiers);
+ this.state.groupArray = this.state.groupArray.concat(newGroupArray);
+ } else {
+ this.state.groupArray.push(this.driver.quoteIdentifiers(field));
+ }
+
+ this.state.groupString = ` GROUP BY ${this.state.groupArray.join(',')}`;
+
+ return this;
+ }
+
+ /**
+ * Order the results by the selected field(s)
+ *
+ * @param {String} field - The field(s) to order by
+ * @param {String} [type='ASC'] - The order direction, ASC or DESC
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orderBy (field, type) {
+ type = type || 'ASC';
+
+ // Set the fields for later manipulation
+ field = this.driver.quoteIdentifiers(field);
+
+ this.state.orderArray[field] = type;
+
+ const orderClauses = [];
+
+ // Flatten key/val pairs into an array of space-separated pairs
+ Object.keys(this.state.orderArray).forEach(key => {
+ orderClauses.push(`${key} ${this.state.orderArray[key].toUpperCase()}`);
+ });
+
+ // Set the final string
+ this.state.orderString = ` ORDER BY ${orderClauses.join(', ')}`;
+
+ return this;
+ }
+
+ /**
+ * Put a limit on the query
+ *
+ * @param {Number} limit - The maximum number of rows to fetch
+ * @param {Number} [offset] - The row number to start from
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ limit (limit, offset) {
+ this.state.limit = limit;
+ this.state.offset = offset || null;
+
+ return this;
+ }
+
+ /**
+ * Adds an open paren to the current query for logical grouping
+ *
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ groupStart () {
+ const conj = (this.state.queryMap.length < 1) ? ' WHERE ' : ' AND ';
+ this._appendMap(conj, '(', 'groupStart');
+
+ return this;
+ }
+
+ /**
+ * Adds an open paren to the current query for logical grouping,
+ * prefixed with 'OR'
+ *
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orGroupStart () {
+ this._appendMap('', ' OR (', 'groupStart');
+
+ return this;
+ }
+
+ /**
+ * Adds an open paren to the current query for logical grouping,
+ * prefixed with 'OR NOT'
+ *
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ orNotGroupStart () {
+ this._appendMap('', ' OR NOT (', 'groupStart');
+
+ return this;
+ }
+
+ /**
+ * Ends a logical grouping started with one of the groupStart methods
+ *
+ * @return {QueryBuilder} - The Query Builder object, for chaining
+ */
+ groupEnd () {
+ this._appendMap('', ')', 'groupEnd');
+
+ return this;
+ }
+
+ // ------------------------------------------------------------------------
+ // ! Result Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get the results of the compiled query
+ *
+ * @param {String} [table] - The table to select from
+ * @param {Number} [limit] - A limit for the query
+ * @param {Number} [offset] - An offset for the query
+ * @example query.get('table_name').then(promiseCallback); // Get all the rows in the table
+ * @example query.get('table_name', 5); // Get 5 rows from the table
+ * @example query.get(); // Get the results of a query generated with other methods
+ * @return {Promise<Result>} - Promise containing the result of the query
+ */
+ get (table, limit, offset) {
+ if (table) {
+ this.from(table);
+ }
+
+ if (limit) {
+ this.limit(limit, offset);
+ }
+
+ // Run the query
+ return this._run('get', table);
+ }
+
+ /**
+ * Run the generated insert query
+ *
+ * @param {String} table - The table to insert into
+ * @param {Object} [data] - Data to insert, if not already added with the 'set' method
+ * @return {Promise<Result>} - Promise containing the result of the query
+ */
+ insert (table, data) {
+ if (data) {
+ this.set(data);
+ }
+
+ // Run the query
+ return this._run('insert', this.driver.quoteTable(table));
+ }
+
+ /**
+ * Insert multiple sets of rows at a time
+ *
+ * @param {String} table - The table to insert into
+ * @param {Array} data - The array of objects containing data rows to insert
+ * @example query.insertBatch('foo',[{id:1,val:'bar'},{id:2,val:'baz'}])
+ *.then(promiseCallback);
+ * @return {Promise<Result>} - Promise containing the result of the query
+ */
+ insertBatch (table, data) {
+ const batch = this.driver.insertBatch(table, data);
+
+ // Run the query
+ return this.query(batch.sql, batch.values);
+ }
+
+ /**
+ * Run the generated update query
+ *
+ * @param {String} table - The table to insert into
+ * @param {Object} [data] - Data to insert, if not already added with the 'set' method
+ * @return {Promise<Result>} - Promise containing the result of the query
+ */
+ update (table, data) {
+ if (data) {
+ this.set(data);
+ }
+
+ // Run the query
+ return this._run('update', this.driver.quoteTable(table));
+ }
+
+ /**
+ * Creates a batch update sql statement
+ *
+ * @param {String} table - The table to update
+ * @param {Object} data - Batch insert data
+ * @param {String} updateKey - The field in the table to compare against for updating
+ * @return {Number} Number of rows updated
+ */
+ updateBatch (table, data, updateKey) {
+ const [sql, insertData, affectedRows] = this.driver.updateBatch(table, data, updateKey);
+ this._run('', table, sql, insertData);
+ return affectedRows;
+ }
+
+ /**
+ * Run the generated delete query
+ *
+ * @param {String} table - The table to insert into
+ * @param {Object} [where] - Where clause for delete statement
+ * @return {Promise<Result>} - Promise containing the result of the query
+ */
+ delete (table, where) {
+ if (where) {
+ this.where(where);
+ }
+
+ // Run the query
+ return this._run('delete', this.driver.quoteTable(table));
+ }
+
+ // ------------------------------------------------------------------------
+ // ! Methods returning SQL
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return generated select query SQL
+ *
+ * @param {String} [table] - the name of the table to retrieve from
+ * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+ * @return {String} - The compiled sql statement
+ */
+ getCompiledSelect (table, reset = true) {
+ if (table) {
+ this.from(table);
+ }
+
+ return this._getCompile('get', table, reset);
+ }
+
+ /**
+ * Return generated insert query SQL
+ *
+ * @param {String} table - the name of the table to insert into
+ * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+ * @return {String} - The compiled sql statement
+ */
+ getCompiledInsert (table, reset = true) {
+ return this._getCompile('insert', this.driver.quoteTable(table), reset);
+ }
+
+ /**
+ * Return generated update query SQL
+ *
+ * @param {String} table - the name of the table to update
+ * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+ * @return {String} - The compiled sql statement
+ */
+ getCompiledUpdate (table, reset = true) {
+ return this._getCompile('update', this.driver.quoteTable(table), reset);
+ }
+
+ /**
+ * Return generated delete query SQL
+ *
+ * @param {String} table - the name of the table to delete from
+ * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+ * @return {String} - The compiled sql statement
+ */
+ getCompiledDelete (table, reset = true) {
+ return this._getCompile('delete', this.driver.quoteTable(table), reset);
+ }
+}
+
+module.exports = QueryBuilder;
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/documentation/Result.js.html b/documentation/Result.js.html
new file mode 100644
index 0000000..b33bc53
--- /dev/null
+++ b/documentation/Result.js.html
@@ -0,0 +1,144 @@
+
+
+
+
+ JSDoc: Source: Result.js
+
+
+
+
+
+
+
+
+
+
+
+
+
Source: Result.js
+
+
+
+
+
+
+
+
+
const Helpers = require('./Helpers');
+
+/**
+ * Query result object
+ *
+ * @param {Array} rows - the data rows of the result
+ * @param {Array} columns - the column names in the result
+ */
+class Result {
+ /**
+ * Create a result object
+ *
+ * @private
+ * @param {Array} [rows] - the data rows of the result
+ * @param {Array} [columns] - the column names in the result
+ */
+ constructor (rows = [], columns = []) {
+ this._rows = rows;
+ this._columns = columns;
+
+ // If columns aren't explicitly given,
+ // get the list from the first row's keys
+ if (
+ this._columns.length === 0 &&
+ this._rows.length > 0 &&
+ Helpers.isObject(rows[0])
+ ) {
+ this.columns = Object.keys(rows[0]);
+ }
+ }
+
+ /**
+ * Return the result rows
+ *
+ * @private
+ * @return {Array} - the data rows of the result
+ */
+ get rows () {
+ return this._rows;
+ }
+
+ /**
+ * Set the result rows for the result object
+ *
+ * @private
+ * @param {Array} rows - the data rows of the result
+ * @return {void}
+ */
+ set rows (rows) {
+ this._rows = rows;
+ }
+
+ /**
+ * Return the result columns
+ *
+ * @private
+ * @return {Array} - the column names in the result
+ */
+ get columns () {
+ return this._columns;
+ }
+
+ /**
+ * Set the result columns for the result object
+ *
+ * @private
+ * @param {Array} cols - the array of columns for the current result
+ * @return {void}
+ */
+ set columns (cols) {
+ this._columns = cols;
+ }
+
+ /**
+ * Get the number of rows returned by the query
+ *
+ * @return {Number} - the number of rows in the result
+ */
+ rowCount () {
+ return this._rows.length;
+ }
+
+ /**
+ * Get the number of columns returned by the query
+ *
+ * @return {Number} - the number of columns in the result
+ */
+ columnCount () {
+ return this._columns.length;
+ }
+}
+
+module.exports = Result;
+
const Adapter = require('../../Adapter');
+const Result = require('../../Result');
+const Helpers = require('../../Helpers');
+const mysql2 = require('mysql2/promise');
+
+class Mysql extends Adapter {
+ constructor (config) {
+ const instance = mysql2.createConnection(config);
+ super(instance);
+ }
+
+ /**
+ * Transform the adapter's result into a standard format
+ *
+ * @param {*} result - original driver result object
+ * @return {Result} - standard result object
+ */
+ transformResult (result) {
+ // For insert and update queries, the result object
+ // works differently. Just apply the properties of
+ // this special result to the standard result object.
+ if (Helpers.type(result) === 'object') {
+ let r = new Result();
+
+ Object.keys(result).forEach(key => {
+ r[key] = result[key];
+ });
+
+ return r;
+ }
+
+ return new Result(result);
+ }
+
+ /**
+ * Run the sql query as a prepared statement
+ *
+ * @param {String} sql - The sql with placeholders
+ * @param {Array} params - The values to insert into the query
+ * @return {Promise} Result of query
+ */
+ execute (sql, params) {
+ return this.instance
+ .then(conn => conn.execute(sql, params))
+ .then(result => this.transformResult(result));
+ }
+}
+
+module.exports = Mysql;
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/documentation/scripts/linenumber.js b/documentation/scripts/linenumber.js
new file mode 100644
index 0000000..8d52f7e
--- /dev/null
+++ b/documentation/scripts/linenumber.js
@@ -0,0 +1,25 @@
+/*global document */
+(function() {
+ var source = document.getElementsByClassName('prettyprint source linenums');
+ var i = 0;
+ var lineNumber = 0;
+ var lineId;
+ var lines;
+ var totalLines;
+ var anchorHash;
+
+ if (source && source[0]) {
+ anchorHash = document.location.hash.substring(1);
+ lines = source[0].getElementsByTagName('li');
+ totalLines = lines.length;
+
+ for (; i < totalLines; i++) {
+ lineNumber++;
+ lineId = 'line' + lineNumber;
+ lines[i].id = lineId;
+ if (lineId === anchorHash) {
+ lines[i].className += ' selected';
+ }
+ }
+ }
+})();
diff --git a/documentation/scripts/prettify/Apache-License-2.0.txt b/documentation/scripts/prettify/Apache-License-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/documentation/scripts/prettify/Apache-License-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/documentation/scripts/prettify/lang-css.js b/documentation/scripts/prettify/lang-css.js
new file mode 100644
index 0000000..041e1f5
--- /dev/null
+++ b/documentation/scripts/prettify/lang-css.js
@@ -0,0 +1,2 @@
+PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
+/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
diff --git a/documentation/scripts/prettify/prettify.js b/documentation/scripts/prettify/prettify.js
new file mode 100644
index 0000000..eef5ad7
--- /dev/null
+++ b/documentation/scripts/prettify/prettify.js
@@ -0,0 +1,28 @@
+var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
+(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
+[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
+l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
+q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
+q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
+"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
+a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
+for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
+H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
+J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
+I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^