diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88e7721cc30b9743dc3db07676d1e127b39ebd1c..e62308e44baefead580498999b21541f53431c84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,23 @@
# Change log
+- `0.15.0`:
+ - [$.formhandler](docs/formhandler.md) now supports client-side validation
+ and sorting by multiple columns. A bug related to encoding special
+ characters is also fixed.
+
+- `0.14.0`:
+ - [$.formhandler](docs/formhandler.md) uses a `onhashchange: false` to
+ disable changing the URL when elements are selected. This is useful when
+ simply viewing tables and not drilling down.
+ - [$.formhandler](docs/formhandler.md) bugfixes: allows column names with
+ spaces. Clear all removes all filters.
+ - [$.urlfilter](docs/urlfilter.md) supports checkboxes, inputs and forms
+ (but has a few known bugs)
+ - Interactive documentation added for [$.template](docs/template.md) and
+ [$.urlfilter](docs/urlfilter.md)
+ - [$.urlchange](docs/urlchange.md) documents how to listen to multiple
+ changes, and when the hash is reset
+
- `0.13.1`:
- Fixes a critical bug. Multiple g1 modules could not be loaded on the same page.
diff --git a/README.md b/README.md
index 91896c64c999a63a30e110cf11510d916573e301..8c436e19a6197b36dd28cdf05f0bf720ad41f5dd 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@ To use all features, add this to your HTML:
- [g1.url.parse](docs/url.md) parses a URL into a structured object
- [url.join](docs/url.md#urljoin) joins two URLs
- [url.update](docs/url.md#urlupdate) updates a URL's query parameters
+- [g1.fuzzysearch](docs/fuzzysearch.md) searches for text with fuzzy matching
- [$.ajaxchain](docs/ajaxchain.md) chains AJAX requests, loading multiple items in sequence
- [L.TopoJSON](docs/topojson.md) loads TopoJSON files just like GeoJSON. Requires [topojson](https://github.com/topojson/topojson)
- [$.dispatch](docs/dispatch.md) is like [trigger](https://api.jquery.com/trigger/) but sends a native event (triggers non-jQuery events too)
@@ -72,14 +73,6 @@ For debugging, use [dist/g1.js](dist/g1.js) -- an un-minified version.
[CHANGELOG](CHANGELOG.md) mentions all release changes.
-Brief notes with examples are described in Gramex releases. For example:
-
-- [v0.12](https://learn.gramener.com/guide/release/1.49/#g1-animated-templates)
-- [v0.11](https://learn.gramener.com/guide/release/1.47/#g1)
-- [v0.10.1](https://learn.gramener.com/guide/release/1.45/#g1)
-- [v0.10.0](https://learn.gramener.com/guide/release/1.44/#g1)
-- [v0.9.0](https://learn.gramener.com/guide/release/1.41/#g1)
-
## Browser support
Every release is tested on the current versions of Chrome, Edge and Firefox.
diff --git a/docs/dropdown.md b/docs/dropdown.md
index 0a0e361432229dd7ff674522178251af6cd7197d..fd24d9fe0c8a6addad1c2e5e24331334938cb367 100644
--- a/docs/dropdown.md
+++ b/docs/dropdown.md
@@ -3,9 +3,14 @@
`$.dropdown()` creates dropdowns that integrate well with
[$.urlfilter](#urlfilter) and [$.urlchange](#urlchange).
-It requires the [bootstrap-select](https://silviomoreto.github.io/bootstrap-select/examples/)
+It requires the [bootstrap-select](https://developer.snapappointments.com/bootstrap-select/)
library and its dependencies.
+```html
+
+
+```
+
Example:
```html
diff --git a/docs/formhandler.md b/docs/formhandler.md
index 65c0f08f93d36e838482eb80350a4684a160f8e3..c09c0b618687f0562d78523c4638ae1031cba836 100644
--- a/docs/formhandler.md
+++ b/docs/formhandler.md
@@ -30,75 +30,70 @@ The full list of options is below. Simple options can be specified as `data-` at
- `title`: for header display. Defaults to the same value as `name`
- `type`: `text` (default) / `number` / `date`. Data type. Determines filters to be used
- `format`: string / function that returns formatted cell display value.
- - function accepts an object with these keys:
- - `name`: column name
- - `value`: cell data value
- - `row`: row data
- - `index`: row index
- - `data`: the dataset from `src`
- - strings specify a numeral.js format if the value is a number (you must include numeral.js)
- - strings specify a moment.js format if the value is a date (you must include moment.js)
- - `editable`: `true` (default) / `false`. When `true`, edit and save buttons appears at end of each row.
- - To bind UI input element such as dropdown, datepicker, radio etc., `editable` accepts an object with these keys.
+ - function accepts an object with these keys:
+ - `name`: column name
+ - `value`: cell data value
+ - `row`: row data
+ - `index`: row index
+ - `data`: the dataset from `src`
+ - strings specify a numeral.js format if the value is a number (you must include numeral.js)
+ - strings specify a moment.js format if the value is a date (you must include moment.js)
+ - `editable`: `true` (default) / `false`. When `true`, edit and save buttons appears at end of each row. To bind UI input element such as dropdown, datepicker, radio etc., `editable` accepts an object with these keys.
- `input`: **Mandatory**. The type of input element to use. The valid values are checkbox, radio, range, select, and any other legal [HTML form input type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
- `options`: An array of options to select from. **Mandatory** if `input` is either of `select` or `radio`
- - `attrs`: To place common attributes such as max, min, placeholder, name etc., on the `input` element.
-
- Example:
- `input: 'number', attrs: {step: 10, placeholder: '0 - 1000', name: 'some_name'}` would render as
-
- ``
-
+ - `attrs`: To place common attributes such as max, min, placeholder, name etc., on the input.
+ Example: `{placeholder: "Age", max:100}` renders ``
+ - `validationMessage`: The message to be shown when invalid input is entered.
+ Example: `"Age must be less than 100"`
- `template`: string template / function that renders the cell.
- - function accepts an object with these keys:
- - `name`: column name
- - `value`: cell data value
- - `format`: formatted cell display value
- - `link`: cell link value (if applicable)
- - `index`: row index
- - `row`: row data
- - `data`: the dataset from `src`
- - string template can use the above variables
+ - function accepts an object with these keys:
+ - `name`: column name
+ - `value`: cell data value
+ - `format`: formatted cell display value
+ - `link`: cell link value (if applicable)
+ - `index`: row index
+ - `row`: row data
+ - `data`: the dataset from `src`
+ - string template can use the above variables
- `sort`: `true` / `false` / operators dict with:
- - `{'': 'Sort ascending', '-': 'Sort descending'}` (default)
+ - `{'': 'Sort ascending', '-': 'Sort descending'}` (default)
- `filters`: `true` (default) / `false` / operators dict with:
- - `{'', 'Equals...', '!', 'Does not equal...', ...}`.
- The default list of operators is based on the auto-detected type of the column.
+ - `{'', 'Equals...', '!', 'Does not equal...', ...}`. The default list of operators is based on the auto-detected type of the column.
- `link`: string / function that generates a link for this each cell.
- - If no `link:` is specified, clicking on the cell filters by that cell.
- - If `link:` is a function, opens a new window with the URL as `fn(args)`.
- - function accepts an object with these keys:
- - `name`: column name
- - `value`: cell data value
- - `format`: formatted cell display value
- - `index`: row index
- - `row`: row data
- - `data`: the dataset from `src`
- Example: `function(args) { return 'https://example.org/city/' + args.value }`
- - If `link:` is a string, opens a new window with the string URL interpolated as a lodash template with an object (mentioned above) as data.
- Example: `"https://example.org/city/<%- value >"`
+ - If no `link:` is specified, clicking on the cell filters by that cell.
+ - If `link:` is a function, opens a new window with the URL as `fn(args)`.
+ - function accepts an object with these keys:
+ - `name`: column name
+ - `value`: cell data value
+ - `format`: formatted cell display value
+ - `index`: row index
+ - `row`: row data
+ - `data`: the dataset from `src`
+ - Example: `function(args) { return 'https://example.org/city/' + args.value }`
+ - If `link:` is a string, opens a new window with the string URL interpolated as a lodash template with an object (mentioned above) as data.
+ Example: `"https://example.org/city/<%- value >"`
- `hideable`: `true` (default) / `false`. Show or hide `Hide` option in header dropdown
- `hide`: `true` / `false` (default). Hides the column
- `unique`: list of values. Adds a list of checkboxes of unique values to filter on, in the column header dropdown.
- `edit`: Shows the Edit control. Can be `true` / `false` (default). Can also pass an object.
- - `done`: function that gets called after saving the edited row.
+ - `done`: function that gets called after saving the edited row.
- `add`: Show the Add control. Can be `true` / `false` (default). Can also pass an object.
- - `done`: function that gets called after saving the new row.
+ - `done`: function that gets called after saving the new row.
- `actions`: A list of objects. you need not add it to actions
- - `{{action}}`: a function() that gets triggered on clicking the element with `data-action='{{action}}` attribute. The value of `data-action` attribute must match with key `{{action}}` in `actions`.
- - function accepts an object with these keys:
- - `row`: row data
- - `index`: index of the row in the dataset from `src`
- - `notify(message)`: a function that shows a notification
- - If the return value can be a jQuery deferred (e.g. `$.ajax`), it shows a loading indicator and a success / failure message when the deferred is resolved. Example:
- - `highlight_row`: `function(obj) { $(obj.row).addClass('.yellow_color')}`. Either a new column can be defined in `columns:` (example: {`name`: `Additional Col`}) with cell_template having an element with data attribute as `data-action='highlight_row'` or can use an existing column but with custom template that has an element with data attribute as `data-action='highlight_row'`.
- - Note: DELETE operation is executed on a row if an element has data attribute `data-action='delete'`. If `delete` action is given in `actions`, the function given for `delete` is executed on click of an element with `data-action='delete'` instead od executing DELETE operation.
+ - `{{action}}`: a function() that gets triggered on clicking the element with `data-action='{{action}}` attribute. The value of `data-action` attribute must match with key `{{action}}` in `actions`.
+ - function accepts an object with these keys:
+ - `row`: row data
+ - `index`: index of the row in the dataset from `src`
+ - `notify(message)`: a function that shows a notification
+ - If the return value can be a jQuery deferred (e.g. `$.ajax`), it shows a loading indicator and a success / failure message when the deferred is resolved. Example:
+ - `highlight_row`: `function(obj) { $(obj.row).addClass('.yellow_color')}`. Either a new column can be defined in `columns:` (example: {`name`: `Additional Col`}) with cell_template having an element with data attribute as `data-action='highlight_row'` or can use an existing column but with custom template that has an element with data attribute as `data-action='highlight_row'`.
+ - Note: DELETE operation is executed on a row if an element has data attribute `data-action='delete'`. If `delete` action is given in `actions`, the function given for `delete` is executed on click of an element with `data-action='delete'` instead od executing DELETE operation.
- `onhashchange`: `true` re-renders table on hashchange based on filters in URL
hash. Set `false` to disable listening to hashchange (default `true`)
- `table`: Shows the table control. Can be:
- - `true`: displays a table (default)
- - `'grid'`: renders a grid instead of a table
- - `false`: disables the table (and shows nothing for the main content)
+ - `true`: displays a table (default)
+ - `'grid'`: renders a grid instead of a table
+ - `false`: disables the table (and shows nothing for the main content)
- `count`: Shows the number of rows. Can be `true` (default) / `false`
- `page`: Shows the page control. Can be `true` (default) / `false`.
- `pageSize`: page size. Defaults to 100
@@ -115,13 +110,13 @@ The full list of options is below. Simple options can be specified as `data-` at
- returns a dict with modified values of `data` and `meta`
- `icon`: if `table: 'grid'` is used, display an icon. string / function that renders the cell.
- function accepts an object with these keys:
- - `row`: row data
- - `data`: the dataset from `src`
- - `index`: index of the row in the dataset from `src`
- Example:
- - `icon: 'fa fa-home fa-3x'` renders a FontAwesome home icon
- - `icon: './path/to/image.png'` renders the image specified
- - `icon: function(args) { return args.row['image_link'] }` renders an image with `src` attribute as the value from column name `image_link`
+ - `row`: row data
+ - `data`: the dataset from `src`
+ - `index`: index of the row in the dataset from `src`
+ - Example:
+ - `icon: 'fa fa-home fa-3x'` renders a FontAwesome home icon
+ - `icon: './path/to/image.png'` renders the image specified
+ - `icon: function(args) { return args.row['image_link'] }` renders an image with `src` attribute as the value from column name `image_link`
**Advanced**. Each component can have a target which specifies a selector. For
e.g., to render the export button somewhere else, use
@@ -141,6 +136,7 @@ targets are:
`data-search-template=""` will replace the search template
with a simple input. Available template strings are:
- `tableTemplate`
+- `table_gridTemplate`
- `countTemplate`
- `pageTemplate`
- `sizeTemplate`
@@ -174,7 +170,7 @@ Features to be implemented:
## $.formhandler examples
-Render a table using the FormHandler at `./data`:
+### Render from a FormHandler
```html
@@ -183,22 +179,20 @@ Render a table using the FormHandler at `./data`:
```
-
-Get data inside formhandler table:
+### Access data inside formhandler
```html
```
-
-Customize cell rendering to display a chart in a cell:
+## Draw chart in cell
```html
@@ -217,7 +211,7 @@ Customize cell rendering to display a chart in a cell:
```
-In edit mode, show HTML input bindings like Dropdown, Datepicker, Number fields.. :
+### Customize inputs in edit mode
```html
@@ -241,11 +235,14 @@ In edit mode, show HTML input bindings like Dropdown, Datepicker, Number fields.
name: 'c1',
editable: {
input: 'number',
- attrs: { // keys and values in `attrs` will be added as
+ // keys and values in `attrs` will be added as
+ //
+ attrs: {
min: 10,
max: 100,
- placeholder: '0 - 100'
- }
+ placeholder: 'Age'
+ },
+ validationMessage: 'Age must be between 0-100'
}
},
{
diff --git a/docs/fuzzysearch.md b/docs/fuzzysearch.md
new file mode 100644
index 0000000000000000000000000000000000000000..1634f96cef9b1953c378cb28b848be6dda206296
--- /dev/null
+++ b/docs/fuzzysearch.md
@@ -0,0 +1,47 @@
+# g1.fuzzysearch
+
+`g1.fuzzysearch(data, options)` returns a fuzzy search function that filteres
+the data based on the text.
+
+For example:
+
+```js
+var data = [
+ {"product": "Cider Apple Vinegar"},
+ {"product": "JBL In-Ear Headphones"},
+ {"product": "Vaseline Body Lotion"},
+ {"product": "Redux Men's Watch"},
+ {"product": "Omega3 Fish Oil"},
+]
+
+var search = g1.fuzzysearch(data, {
+ keys: ['product'], // Search within these keys
+ limit: 2, // Return only the top 2 results
+})
+
+search('omega')
+// Returns {product: "Omega3 Fish Oil", ...} since it's the only one
+search('red')
+// Returns {product: "Redux Men's Watch"} and {product: "JBL In-Ear Headphones"}
+// The second matches r (in "Ear"), followed by e then d in "Headphones"
+```
+
+It matches with the following priority. For example, if the string is "alpha
+beta", then:
+
+1. Match the exact phrase ("alpha beta")
+2. Match all words in the same order ("alp bet")
+3. Match words in any order ("bet alp")
+4. Match partial words in any order ("ba aph")
+5. Match letters in order ("abt")
+
+It accepts an `options` dict with these keys:
+
+- `keys`: a list of keys to search in. The keys are calculated and joined with a
+ space. (Default: assumes that data is a string list.) Each key can be either:
+ - a string (e.g. `"name"`, `"title"`) picks keys from the objects in the
+ `data` list.
+ - a function (e.g. `function (v) { return v['key'] })`) runs the function on
+ each element in the `data` list
+- `limit`: the maximum number of results to return. (Default: `100`)
+- `case`: `true` for case-sensitive comparisons. (Default: `false`)
diff --git a/docs/template.html b/docs/template.html
new file mode 100644
index 0000000000000000000000000000000000000000..581bb46cd20b263daf90ec49a97fb761d6f47d4b
--- /dev/null
+++ b/docs/template.html
@@ -0,0 +1,3 @@
+This is the contents of the file "template.html".
+
+It is rendered as a template. 1 + 2 = <%- 1 + 2 %>.
diff --git a/docs/template.md b/docs/template.md
index 35d9c3a44f5e22cddd608c07332c131aa218d7c4..8ccceb6b531ecba18382d10e41622cf824816e85 100644
--- a/docs/template.md
+++ b/docs/template.md
@@ -20,14 +20,15 @@ This displays `Your platform is ...` and shows the userAgent just below the scri
The template can use all global variables. You can pass additional variables
using as `.template({var1: value, var2: value, ...})`. For example:
+
```html
-
```
@@ -45,21 +46,22 @@ for this to work.
For example, this shows a circle in SVG bouncing around smoothly.
+
```html
-
-
+
```
@@ -77,42 +79,60 @@ To re-use the template or render the same template on a different DOM node,
run `.template(data, {target: selector})`. This allows you to declare templates
once and apply them across the body. For example:
-```js
-$('script.chart')
- .template({heading: 'Dashboard 1'}, {target: '.dashboard1'})
- .template({heading: 'Dashboard 2'}, {target: '.dashboard2'})
- .template({}, {target: '.no-heading'})
+
+```html
+
+
+
+
```
-The target can also be specified via a `data-target=".dashboard1"` on the script
-template. This is the same as specifying `{target: '.dashboard'}`. For example:
+The target can also be specified via a `data-target=".panel1"` on the script
+template. This is the same as specifying `{target: '.panel'}`. For example:
```html
-
-
+
+
```
## $.template append
-To append instead of replacing, run `.template(data, {append: true})`. Every
-time `.template` is called, it appends rather than replaces. For example:
+To append instead of replacing, use `data-append="true"`. Every time `.template`
+is called, it appends rather than replaces. For example:
-```js
+
+```html
+
+
```
-You can also specify this as `
-
+
Existing item
+
```
@@ -120,10 +140,11 @@ an existing target. For example:
Template containers can have an `src=` attribute that loads the template from a file:
+
```html
-
+
```
@@ -135,36 +156,43 @@ as a template. The template can use:
For example:
+
```html
-
```
## $.template selector
-`$().template()` renders all `script[type="text/html"]` nodes in or under the
+`$(...).template()` renders all `script[type="text/html"]` nodes in or under the
selected node. Use `data-selector=` attribute to change the selector. For
example:
+
```html
-
-
+
+
+
```
-You can also render a template by selecting it directly. For example:
+You can also use the `selector: ...` option. For example:
+
```html
+
+
+
```
@@ -177,12 +205,17 @@ You can also render a template by selecting it directly. For example:
For example:
-```js
-$('script[type="text/html"]')
- .on('template', function(e) { // Returns nodes rendered by the template
- e.target // Get the target nodes
- .filter('div') // Filter all
elements inside
- .attr('class', 'item') // Change their class
+
+```html
+
+
```
diff --git a/docs/urlchange.md b/docs/urlchange.md
index d9651e5682f651929b3eb5b20e40cfd441b5234b..efac8c3ec50ec359539380defd46320963673952 100644
--- a/docs/urlchange.md
+++ b/docs/urlchange.md
@@ -52,6 +52,10 @@ Examples:
- When the URL changes from `#a` to `#b`, it triggers 2 events on `window`:
- `.on('#', function(e) { e.hash.pathname == 'b' }`
- `.on('#/', function(e, val) { val == 'b' && e.old == 'a' }`
+- Combinations of keys can be listened to simultaneously
+ - `.on('#?x #?y', function(e){})` will only be triggered if both x and y change
+- When the hashkey is reset, `location.hash=''`
+ - `.on('#', function(e){})` as the location.hash is now `{}`
## $.urlchange events
diff --git a/docs/urlfilter.md b/docs/urlfilter.md
index dc6bbc0a4a6f8918c572fa80dae8aa1e3914856b..e7a273c96b0d71ac0acaa6461bc00a92f79a6eb0 100644
--- a/docs/urlfilter.md
+++ b/docs/urlfilter.md
@@ -4,8 +4,9 @@
Example: Let's say the following HTML is on the page `/?city=NY`.
+
```html
-Link
+Add ?name=John to URL
@@ -26,21 +27,51 @@ current page URL instead of replacing it.
For example:
+
```html
- Change ?city= to NY
- Add ?city= to NY
- Remove NY from ?city=
- Toggle NY in ?city=
-
-Change ?city= to NY using pushState
- Change location.hash, i.e. #?city= to NY
- Change iframe URL ?city= NY
-
- Use AJAX to load ?city=NY into .block
-
-
+