Commit a66118ca authored by Tejesh's avatar Tejesh 🖖
Browse files

ENH: dropdown component integrated with urlfilter, fixes #40

parent d13d85e0
Pipeline #56604 passed with stage
in 2 minutes and 21 seconds
......@@ -278,6 +278,105 @@ function. For example, `<body data-selector=".link">` is the same as
- `load` is fired on the target when the URL is loaded -- only if the `data-target=` is a selector. Attributes:
- `url`: the new URL
## $.dropdown
Dropdown component that integrates well with g1.urlfilter
$.dropdown requires `bootstrap-select` library and its dependencies.
Examples:
```html
<div class="container1"></div>
<script>
$('.container1').dropdown({data: ['Red', 'Green', 'Blue'] })
</script>
```
The above code snippet renders a dropdown using [bootstrap-select](https://silviomoreto.github.io/bootstrap-select/examples/) library. The rendered dropdown has 3 options namely Red, Green, Blue.
```html
<div class="container2"></div>
<script>
$('.container2').dropdown({ key: 'colors', data: ['Red', 'Green', 'Blue'] })
</script>
```
`key` enables urlfilter for dropdown. If Red option is selected from dropdown, URL is appended with `?colors=Red`
By default, the selected dropdown values are appended to URL query string. To append to the hash instead, use `target: '#'`.
```html
<div class="container3"></div>
<script>
$('.container3').dropdown(
{ key: 'colors',
data: ['Red', 'Green', 'Blue'],
target: '#'
})
</script>
```
To change URL without reloading the page, use `target: 'pushState'`.
```html
<div class="container4"></div>
<script>
$('.container4').dropdown(
{ key: 'colors',
data: ['Red', 'Green', 'Blue'],
target: 'pushState'
})
</script>
```
To use bootstrap-select options, use `options:`
```html
<div class="container5"></div>
<script>
$('.container5').dropdown({
data: ['Red', 'Green', 'Blue'], key: 'colors',
options: {
style: 'btn-primary',
liveSearch: true
}
})
</script>
```
### $.dropdown events
- `load` is triggered after dropdown is rendered
- `change` is triggered whenever dropdown value is changed
```html
<div class="container5"></div>
<script>
$('.container5')
.on('load', function() {
// Your code here
})
.on('change', function() {
// Your code here
})
.dropdown({
key: 'colors',
data: ['Red', 'Green', 'Blue']
})
</script>
```
### $.dropdown options
- `data`: Array of values.
- `url`: End point that returns the `data`. If `data:` is also given, `data` takes priority.
- `target`: defines how URL is updated. Can be `''` (Default), `#` or `pushState`
- `key`: key with which URL is updated.
- `multiple`: To render a dropdown that supports multi-select. Can be `true` or `false` (Default).
- `options`: Supports same options as [bootstrap-select options](https://silviomoreto.github.io/bootstrap-select/options/)
## $.highlight
Highlight elements when hovering on or clicking another element.
......
......@@ -7,3 +7,10 @@ url:
kwargs:
url: test/formhandler.csv
id: ID
dropdown-data:
pattern: /data-list
handler: FunctionHandler
kwargs:
function: json.dumps(['bengaluru', 'hyderabad', 'mumbai', 'delhi'])
headers:
Content-Type: application/json
export { version } from './src/package.js'
import { dropdown } from './src/dropdown.js'
if (typeof jQuery != 'undefined') {
jQuery.extend(jQuery.fn, {
dropdown: dropdown
})
}
......@@ -7,5 +7,6 @@ export { sanddance } from './src/sanddance.js'
import './index-highlight.js'
import './index-template.js'
import './index-formhandler.js'
import './index-dropdown.js'
import './index-event.js'
import './index-leaflet.js'
{
"name": "g1",
"version": "0.4.0",
"version": "0.8.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -325,11 +325,16 @@
}
},
"bootstrap": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0-beta.3.tgz",
"integrity": "sha512-/Qe1Q2d1muLEZRX2iCteMQHZBBAm6ZIjJ9FcBYK/xLr05+HvDtBOVBN+Cz7mCNZuy0zr+y5artZHM05W7mIz6g==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.1.tgz",
"integrity": "sha512-SpiDSOcbg4J/PjVSt4ny5eY6j74VbVSjROY4Fb/WIUXBV9cnb5luyR4KnPvNoXuGnBK1T+nJIWqRsvU3yP8Mcg==",
"dev": true
},
"bootstrap-select": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.13.1.tgz",
"integrity": "sha1-9ZwCkm+1rGNWudHNvFOEwvAT2bo="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
......@@ -3970,12 +3975,6 @@
"inherits": "2.0.3"
}
},
"rollup": {
"version": "0.52.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-0.52.3.tgz",
"integrity": "sha512-cw+vb9NqaTXlwJyb8G+Ve+uhhlVTcl1NKBkfANdeQqVcpZFilQgeNnAnNiu7MwfeXrqiKEGz+3R03a3zeFkmEQ==",
"dev": true
},
"rollup-plugin-uglify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-2.0.1.tgz",
......
......@@ -24,7 +24,6 @@
"babel-plugin-transform-runtime": "6",
"babel-preset-env": "1",
"babelrc-rollup": "3",
"bootstrap": "4",
"browserify": "14",
"component-emitter": "1",
"d3": "4",
......@@ -61,5 +60,9 @@
"topojson": "3",
"uglify-js": "3",
"unfetch": "3"
},
"dependencies": {
"bootstrap": "^4.1.3",
"bootstrap-select": "^1.13.1"
}
  • Should bootstrap version be tightly synced with gramex uicomponents i.e 4?

  • Hmm, aren't these included from UI Components anyway? We are anyway not shipping these with g1. For testing purposes, these could go into devdependencies instead?

    @tejesh.p @s.anand -- please look into.

  • @pratap.vardhan will remove it as part of next release. Do not see a strong reason in doing so, given g1 has multiple components in itself which are partly dependant on few external libraries.

Please register or sign in to reply
}
......@@ -12,13 +12,21 @@ const babelConfig = {
export default [
{
input: "index",
plugins: [htmlparts('src/formhandler.template.html')],
output: { file: "dist/g1.js", format: "umd", name: "g1" }
plugins: [resolve(), commonjs(), htmlparts('src/formhandler.template.html'), htmlparts('src/dropdown.template.html')],
output: {
file: "dist/g1.js",
format: "umd",
name: "g1"
}
},
{
input: "index",
plugins: [htmlparts('src/formhandler.template.html'), uglify()],
output: { file: "dist/g1.min.js", format: "umd", name: "g1" }
plugins: [resolve(), commonjs(), htmlparts('src/formhandler.template.html'), htmlparts('src/dropdown.template.html'), uglify()],
output: {
file: "dist/g1.min.js",
format: "umd",
name: "g1"
}
},
{
input: "index-datafilter",
......@@ -80,5 +88,16 @@ export default [
input: "index-scale",
plugins: [uglify()],
output: { file: "dist/scale.min.js", format: "umd", name: "g1" }
},
{
input: "index-dropdown",
plugins: [resolve(),
commonjs(),
htmlparts('src/dropdown.template.html')],
output: {
file: "dist/dropdown.min.js",
format: "umd",
name: "g1"
}
}
]
import * as default_templates from './dropdown.template.html'
import deepmerge from 'deepmerge'
var default_options = {
target: '',
multiple: false
}
export function dropdown(js_options) {
var self = $(this)
var options = deepmerge(default_options, js_options)
self.html(_.template(default_templates['template_dropdown'])(options))
if (options.data) {
render(options.data)
// trigger 'load' event
self.trigger({type: 'load'})
}
else if (options.url) {
render(['Loading...'])
$.ajax(options.url)
.fail(function(xhr, status, message) {
// load error template
self.html(_.template(default_templates['template_error'])({message: message}))
})
.done(function(response) {
render(response)
self.find('.selectpicker').selectpicker('refresh')
self.trigger({type: 'load'})
})
}
function render(data) {
options.data = data
if (options.key) {
// urlfilter
self.urlfilter({
selector: 'select.urlfilter',
target: options.target,
event: 'change',
remove: true
})
}
//re-render dropdown template options with fetched data
self.find('.selectpicker').html(_.template(default_templates['template_dropdown_options'])(options))
self.find('.selectpicker').selectpicker(options.options)
}
return this
}
<!-- var template_dropdown -->
<% var urlfilterClass = key ? 'urlfilter' : '',
multiple = multiple ? 'multiple' : '',
key = key ? key : '' %>
<select class="selectpicker border <%- urlfilterClass %>" id="<%- key %>" <%-multiple%>>
</select>
<!-- end -->
<!-- var template_dropdown_options -->
<% _.each(data, function(item) { %>
<option value="<%- encodeURIComponent(item) %>"><%- item %></option>
<% }) %>
<!-- end -->
<!-- var template_error -->
<div class="alert alert-warning" role="alert">
<p class="text-center">
<%- message %>
</p>
</div>
<!-- end -->
......@@ -13,13 +13,17 @@ const app = express()
var formhandler_json_data = JSON.parse(fs.readFileSync('./test/formhandler_csv.json', { encoding: "utf8" }));
// const router = express.Router()
app.use('/formhandler-data', router.get('/', function (req, res, next) {
app.route('/formhandler-data').get(function(req, res, next) {
var url = req.protocol + '://' + req.get('host') + req.originalUrl
res.send(g1.datafilter(formhandler_json_data, g1.url.parse(url).searchList, 'fhname13'))
}))
})
app.route('/data-list').get(function(req, res, next) {
res.send(['bengaluru', 'hyderabad', 'mumbai', 'delhi'])
})
const server = app.listen(port, function () {
// If run as "node server.js", start the HTTP server for manual testing
......
<!DOCTYPE html>
<html>
<head>
<title>dropdown tests</title>
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../node_modules/bootstrap-select/dist/css/bootstrap-select.min.css">
<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/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../node_modules/bootstrap-select/dist/js/bootstrap-select.min.js"></script>
<script src="../node_modules/lodash/lodash.min.js"></script>
<script src="../dist/dropdown.min.js"></script>
<script src="../dist/g1.min.js"></script>
<script src="tape.js"></script>
</head>
<body>
<script>
tape.onFinish(function () { window.renderComplete = true })
</script>
<div class="m-4">
<div class="container1 w-25 m-3"></div>
<div class="container2 w-25 m-3"></div>
<div class="container3 w-25 m-3"></div>
<div class="container4 w-25 m-3"></div>
<div class="container5 w-25 m-3"></div>
<div class="multiselect w-25 m-3"></div>
<div class="container6 w-25 m-3"></div>
<div class="container7 w-25 m-3"></div>
</div>
<script>
tape('$().dropdown() load event is triggered', function (t) {
$('.container1')
.on('load', function () {
t.end()
})
.dropdown({data: ['One', 'Two']})
})
tape('$().dropdown() assigns given options and key', function(t) {
$('.container2')
.on('load', function(){
t.equals($('.container2 option').length, 3)
t.equals($('.container2 select').attr('id'), 'color')
t.end()
})
.dropdown({ data: ['Red', 'Green', 'Blue'], key: 'color', target: '#'})
})
tape('$().dropdown() applies default selectpicker options', function(t) {
$('.container3')
.on('load', function() {
t.ok($('.container3 button').hasClass('btn-primary'))
t.end()
})
.dropdown({ data: ['Red', 'Green', 'Blue'], key: 'colors',
target: '#',
options: {
style: 'btn-primary',
liveSearch: true
}
})
})
tape('$().dropdown() urlfilter', function (t) {
$('.container4')
.on('load', function() {
$('.container4 select').trigger('change')
var hash = g1.url.parse(location.hash.replace(/^#/, ''))
t.equals(hash.searchKey.loc, 'bengaluru')
t.end()
})
.dropdown({
url: '/data-list',
target: '#',
key: 'loc'
})
})
tape('$().dropdown() multiple select', function(t) {
var data_list = ['Red', 'Green', 'Blue']
$('.multiselect')
.on('load', function() {
$('.multiselect button').click()
$('.multiselect .dropdown-menu.inner a').click()
var hash = g1.url.parse(location.hash.replace(/^#/, ''))
t.deepEquals(hash.searchKey.multicolor, data_list.toString())
t.end()
$('.multiselect button').click()
})
.dropdown({
data: data_list,
multiple: true,
key: 'multicolor',
target: '#'
})
})
tape('$().dropdown() select all button works', function(t) {
var data_list = ['Red', 'Green', 'Blue']
$('.container5')
.on('load', function() {
$('.bs-select-all').click()
var hash = g1.url.parse(location.hash.replace(/^#/, ''))
t.deepEquals(hash.searchKey.selectall, data_list.toString())
t.end()
})
.dropdown({ data: data_list, multiple: true, key: 'selectall',
target: '#',
options: {actionsBox: true}
})
})
tape('$().dropdown() prioritizes data: over url:', function(t) {
var data_list = ['Default 1', 'Default 2', 'Default 3']
$('.container6')
.on('load', function() {
t.deepEquals($('.container6 option').get()
.map(function(item){ return item.text }), data_list)
t.end()
})
.dropdown({
data: data_list,
url: '/data-list',
key: 'data'
})
})
tape('$().dropdown() urlfilter target works', function(t) {
$('.container7').dropdown({
data: ['Europe', 'Asia'],
key: 'continent',
target: '#'
})
$('.container7 select').trigger('change')
var hash = g1.url.parse(location.hash.replace(/^#/, ''))
t.equals(hash.searchKey.continent, 'Europe')
t.end()
})
</script>
</body>
</html>
......@@ -738,9 +738,13 @@ boom@2.x.x:
dependencies:
hoek "2.x.x"
bootstrap@4:
version "4.0.0"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.0.0.tgz#ceb03842c145fcc1b9b4e15da2a05656ba68469a"
bootstrap-select@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/bootstrap-select/-/bootstrap-select-1.13.1.tgz#f59c02926fb5ac6356b9d1cdbc5384c2f013d9ba"
bootstrap@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.1.3.tgz#0eb371af2c8448e8c210411d0cb824a6409a12be"
brace-expansion@^1.1.7:
version "1.1.11"
......
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