Commit c2f0f7e3 authored by S Anand's avatar S Anand
Browse files

ENH: FormHandler cell click links to URL. Fixes #20. @tejesh.papineni

parent 6cce4997
Pipeline #44905 passed with stage
in 2 minutes and 10 seconds
...@@ -185,9 +185,9 @@ var data = [ ...@@ -185,9 +185,9 @@ var data = [
{"ID": "5", "product": "Light", "sales": "100", "city": "London"} {"ID": "5", "product": "Light", "sales": "100", "city": "London"}
] ]
g1.datafilter(data, [{col: 'sales', op: '>', val: 100}, g1.datafilter(data, [{col: 'sales', op: '>', val: 100},
{col: 'city', op: 'in', val: ['London', 'NY']}, {col: 'city', op: 'in', val: ['London', 'NY']},
{col: 'product', val: 'Fan'}]) {col: 'product', val: 'Fan'}])
// Returns [{"ID": "3", "product": "Fan", "sales": "120", "city": "NJ"}, {"ID": "4", "product": "Fan", "sales": "130", "city": "London"}] // Returns [{"ID": "3", "product": "Fan", "sales": "120", "city": "NJ"}, {"ID": "4", "product": "Fan", "sales": "130", "city": "London"}]
``` ```
...@@ -202,7 +202,7 @@ datafilter() contains three parameters: ...@@ -202,7 +202,7 @@ datafilter() contains three parameters:
- op: operator to be applied for filteration. default: `=` - op: operator to be applied for filteration. default: `=`
- val: value of the selected column - val: value of the selected column
- options: a dictionary that contains the below keys: - options: a dictionary that contains the below keys:
- limit: result is limited to. default: `1000` - limit: result is limited to. default: `1000`
- offset: filtering data should start from. default: `0` - offset: filtering data should start from. default: `0`
- sort: a list of objects, that will contains the below keys: - sort: a list of objects, that will contains the below keys:
- column: column to be sorted - column: column to be sorted
...@@ -212,7 +212,7 @@ datafilter() contains three parameters: ...@@ -212,7 +212,7 @@ datafilter() contains three parameters:
- not: a list of column names to be skiped in the filtered data - not: a list of column names to be skiped in the filtered data
Rules: Rules:
- the key `op` may contains any one of the below values: - the key `op` may contains any one of the below values:
- `=` - `=`
- `!=` - `!=`
...@@ -251,9 +251,9 @@ The full list of options is below. Simple options can be specified as `data-` at ...@@ -251,9 +251,9 @@ The full list of options is below. Simple options can be specified as `data-` at
- `src`: [FormHandler][formhandler] URL endpoint - `src`: [FormHandler][formhandler] URL endpoint
- `columns`: comma-separated column names to display, or a list of objects with these keys: - `columns`: comma-separated column names to display, or a list of objects with these keys:
- `name`: column name. `"*"` is a special column placeholder for "all columns" - `name`: column name. `"*"` is a special column placeholder for "all columns"
- `title`: display name of the column. Defaults to the same value as `name` - `title`: for header display. Defaults to the same value as `name`
- `type`: `text` (default) / `number` / `date`. Determines filters to be used - `type`: `text` (default) / `number` / `date`. Data type. Determines filters to be used
- `format`: string / function that changes the cell contents. - `format`: string / function that renders the cell contents.
- functions are applied to the value and the return value is used - functions are applied to the value and the return value is used
- strings specify a numeral.js format if the value is a number (you must include numeral.js) - 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) - strings specify a moment.js format if the value is a date (you must include moment.js)
...@@ -262,7 +262,13 @@ The full list of options is below. Simple options can be specified as `data-` at ...@@ -262,7 +262,13 @@ The full list of options is below. Simple options can be specified as `data-` at
- `filters`: `true` (default) / `false` / operators dict with: - `filters`: `true` (default) / `false` / operators dict with:
- `{'', 'Equals...', '!', 'Does not equal...', ...}`. - `{'', 'Equals...', '!', 'Does not equal...', ...}`.
The default list of operators is based on the auto-detected type of the column. The default list of operators is based on the auto-detected type of the column.
- `hideable`: `true` (default) / `false` - `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 string, opens a new window with the string URL interpolated as a lodash template with `row` as data.
Example: `"https://example.org/city/<%- city >"`
- If `link:` is a function, opens a new window with the URL as `fn(row)`.
Example: `function(row) { return 'https://example.org/city/' + row.city }`
- `hideable`: `true` (default) / `false`. Hides the column
- `unique`: TODO: {dict of query parameter and display value} or [list of values] or function? - `unique`: TODO: {dict of query parameter and display value} or [list of values] or function?
- `table`: Shows the table control. Can be `true` (default) / `false` - `table`: Shows the table control. Can be `true` (default) / `false`
- `count`: Shows the number of rows. Can be `true` (default) / `false` - `count`: Shows the number of rows. Can be `true` (default) / `false`
......
...@@ -107,7 +107,15 @@ Each template receives these variables: ...@@ -107,7 +107,15 @@ Each template receives these variables:
fmt === "string" && colinfo.type === "date" ? fmt === "string" && colinfo.type === "date" ?
moment(val).format(colinfo.format): moment(val).format(colinfo.format):
val %> val %>
<a class="urlfilter" href="?<%- colinfo.name %>=<%- val %>&amp;_offset="><%- disp %></a> <% if ('link' in colinfo) {
var col_link = typeof colinfo.link == 'function' ? colinfo.link(val) : _.template(colinfo.link)(row)
%>
<a href="<%- col_link %>" target="_blank"><%- disp %></a>
<% } else { %>
<a class="urlfilter" href="?<%- colinfo.name %>=<%- val %>&amp;_offset=">
<%- disp %>
</a>
<% } %>
</td> </td>
<% }) %> <% }) %>
</tr> </tr>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>formhandler tests</title> <title>formhandler tests</title>
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css"> <link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css">
<style> <style>
.position-relative { .position-relative {
position: relative; position: relative;
} }
.pos-cc {
position: absolute; .pos-cc {
top: 45%; position: absolute;
left: 45%; top: 45%;
} left: 45%;
.d-none { }
display: none !important;
} .d-none {
display: none !important;
}
</style> </style>
<script src="../node_modules/jquery/dist/jquery.min.js"></script> <script src="../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../node_modules/popper.js/dist/umd/popper.min.js"></script> <script src="../node_modules/popper.js/dist/umd/popper.min.js"></script>
...@@ -27,6 +30,7 @@ ...@@ -27,6 +30,7 @@
<script src="tape.js"></script> <script src="tape.js"></script>
</head> </head>
<body> <body>
<script> <script>
tape.onFinish(function () { window.renderComplete = true }) tape.onFinish(function () { window.renderComplete = true })
...@@ -42,16 +46,15 @@ ...@@ -42,16 +46,15 @@
<div class="fh8" data-src="formhandler.json"></div> <div class="fh8" data-src="formhandler.json"></div>
<div class="fh9" data-src="formhandler.json"></div> <div class="fh9" data-src="formhandler.json"></div>
<div class="fh10"></div> <div class="fh10"></div>
<div class="fh11"></div> <div class="fh11" data-src="formhandler.json"></div>
<div class="fh12"></div> <div class="fh12" data-src="formhandler.json"></div>
<div class="fh13"></div>
<div class="formhandler" data-src="formhandler.json" data-page-size="10"></div> <div class="formhandler" data-src="formhandler.json" data-page-size="10"></div>
<script> <script>
tape('$().formhandler() basic example works', function(t) { tape('$().formhandler() basic example works', function (t) {
$('.formhandler').formhandler({ $('.formhandler').formhandler({
pageSize: 20 pageSize: 20
}).on('load', function(e) { }).on('load', function (e) {
t.equals(e.options.pageSize, 10) t.equals(e.options.pageSize, 10)
// TODO: Review: if _limit is given in url, e.args._limit is [10] not 10 // TODO: Review: if _limit is given in url, e.args._limit is [10] not 10
t.equals(e.args._limit, 10) t.equals(e.args._limit, 10)
...@@ -60,15 +63,15 @@ ...@@ -60,15 +63,15 @@
t.end() t.end()
}) })
}) })
tape('$().formhandler() renders data from data-src, overriding options.src', function(t) { tape('$().formhandler() renders data from data-src, overriding options.src', function (t) {
$('.fh1') $('.fh1')
.formhandler({ src: 'formhandler-small.json' }) .formhandler({ src: 'formhandler-small.json' })
.on('load', function() { .on('load', function () {
t.equals($('.fh1 tbody tr').length, 50) t.equals($('.fh1 tbody tr').length, 50)
t.end() t.end()
}) })
}) })
tape('$().formhandler() uses option.src if no data-src exists', function(t) { tape('$().formhandler() uses option.src if no data-src exists', function (t) {
$('.fh2') $('.fh2')
.formhandler({ src: 'formhandler-small.json' }) .formhandler({ src: 'formhandler-small.json' })
.on('load', function () { .on('load', function () {
...@@ -76,15 +79,15 @@ ...@@ -76,15 +79,15 @@
t.end() t.end()
}) })
}) })
tape('$().formhandler() shows default controls if meta is present', function(t) { tape('$().formhandler() shows default controls if meta is present', function (t) {
$('.fh3') $('.fh3')
.formhandler({ .formhandler({
src: 'formhandler-small.json', src: 'formhandler-small.json',
transform: function(obj) { transform: function (obj) {
obj.meta.count = obj.meta.limit = obj.data.length obj.meta.count = obj.meta.limit = obj.data.length
} }
}) })
.on('load', function() { .on('load', function () {
t.equal($('.fh3 tbody tr').length, 2) t.equal($('.fh3 tbody tr').length, 2)
t.equal($('.fh3 .count').length, 1) t.equal($('.fh3 .count').length, 1)
t.ok($('.fh3 .count').text().match(/2 rows/)) t.ok($('.fh3 .count').text().match(/2 rows/))
...@@ -104,15 +107,15 @@ ...@@ -104,15 +107,15 @@
}) })
}) })
tape('$().formhandler() disables controls via data-attributes', function(t) { tape('$().formhandler() disables controls via data-attributes', function (t) {
$('.fh4') $('.fh4')
.formhandler({ .formhandler({
src: 'formhandler-small.json', src: 'formhandler-small.json',
transform: function(obj) { transform: function (obj) {
obj.meta.count = obj.meta.limit = obj.data.length obj.meta.count = obj.meta.limit = obj.data.length
} }
}) })
.on('load', function() { .on('load', function () {
t.equal($('.fh4 .table').html(), '') t.equal($('.fh4 .table').html(), '')
t.equal($('.fh4 .count').html(), '') t.equal($('.fh4 .count').html(), '')
t.equal($('.fh4 .page').html(), '') t.equal($('.fh4 .page').html(), '')
...@@ -192,7 +195,7 @@ ...@@ -192,7 +195,7 @@
$('.fh9') $('.fh9')
.formhandler({ .formhandler({
columns: [ columns: [
{ name: 'Continent', format: function(o) {return o.toUpperCase()}} { name: 'Continent', format: function (o) { return o.toUpperCase() } }
] ]
}) })
.on('load', function () { .on('load', function () {
...@@ -201,56 +204,62 @@ ...@@ -201,56 +204,62 @@
t.equal($('.fh9 tbody tr:first-of-type td:first-of-type a').text().trim(), "EUROPE") t.equal($('.fh9 tbody tr:first-of-type td:first-of-type a').text().trim(), "EUROPE")
t.end() t.end()
}) })
}) })
tape('$().formhandler() applies format option (date type) option mentioned in options.columns', function (t) { tape('$().formhandler() applies format option (date type) option mentioned in options.columns', function (t) {
$('.fh10') $('.fh10')
.formhandler({ .formhandler({
src: 'formhandler-types.json', src: 'formhandler-types.json',
columns: [ columns: [
{ name: 'Amount', type: 'number', format: '$0,0.00' }, { name: 'Amount', type: 'number', format: '$0,0.00' },
{ name: 'Date', type: 'date', format: 'DD-MM-YYYY'} { name: 'Date', type: 'date', format: 'DD-MM-YYYY' }
] ]
}) })
.on('load', function () { .on('load', function () {
// check if number is given, applied filters display name must be Greater than, Lesser than // check if number is given, applied filters display name must be Greater than, Lesser than
// check if date is give, applied filters display name must be Before, After // check if date is give, applied filters display name must be Before, After
// check if format is applied to number type using numeraljs // check if format is applied to number type using numeraljs
t.equal($('.fh10 tbody tr:first-of-type td:nth-of-type(1) a').text().trim(), '$3,500.00') t.equal($('.fh10 tbody tr:first-of-type td:nth-of-type(1) a').text().trim(), '$3,500.00')
// check if format is applied to date type using momentjs // check if format is applied to date type using momentjs
t.equal($('.fh10 tbody tr:first-of-type td:nth-of-type(2) a').text().trim(), '08-02-2013') t.equal($('.fh10 tbody tr:first-of-type td:nth-of-type(2) a').text().trim(), '08-02-2013')
t.end() t.end()
}) })
})
tape('$().formhandler() link attr will let user goto that link instead of applying filter', function (t) {
$('.fh11')
.formhandler({
columns: [
{
name: 'Continent',
link: 'https://en.wikipedia.org/wiki/<%= Continent.split(" ").join(" ") %>'
}
]
})
.on('load', function () {
// no. of columns in meta data must be same as rendered columns
t.equal($('.fh11 tbody tr:first-of-type td:nth-of-type(1) a').attr('href'), 'https://en.wikipedia.org/wiki/' + $('.fh11 tbody tr:first-of-type td:nth-of-type(1) a').text().split(" ").join(" "))
t.end()
})
})
tape('$().formhandler() link attr will let user goto that link instead of applying filter using function', function (t) {
$('.fh12')
.formhandler({
columns: [
{
name: 'Continent',
link: function (row) { return 'https://en.wikipedia.org/wiki/' + row.split(" ").join(" ") }
}
]
})
.on('load', function () {
// no. of columns in meta data must be same as rendered columns
t.equal($('.fh11 tbody tr:first-of-type td:nth-of-type(1) a').attr('href'), 'https://en.wikipedia.org/wiki/' + $('.fh11 tbody tr:first-of-type td:nth-of-type(1) a').text().split(" ").join(" "))
t.end()
})
}) })
// tape('$(fh11).formhandler() must show error message if input data is invalid json', function (t) {
// $('.fh11')
// .formhandler({
// src: 'formhandler-invalid.json'
// })
// .on('load', function () {
// t.equal($('.fh11 p').text().trim(), 'Invalid data or no data found')
// t.end()
// })
// })
// tape('$().formhandler() must show error message if formhandler url is missing', function (t) {
// $('.fh12')
// .formhandler({
// })
// .on('load', function () {
// t.equal($('.fh11 p').text().trim(), 'Invalid data or no data found')
// t.end()
// })
// })
// tape('$().formhandler() must show error message if formhandler returns HTTP status 500/403/400', function (t) {
// $('.fh13')
// .formhandler({
// })
// .on('load', function () {
// t.end()
// })
// })
</script> </script>
</body> </body>
</html> </html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment