Skip to content

Commit

Permalink
Feature/stepper (jdorn#841)
Browse files Browse the repository at this point in the history
* stepper editor

* stepper enable disable logic

* added stepper test

* fixed code format

* use right dist script in tests

* fix display error message stepper

* added button "type" attribute

Co-authored-by: German Bisurgi <[email protected]>
Co-authored-by: Marc Mautz <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2020
1 parent 9109d1f commit 84fe806
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/editors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { SelectizeEditor as selectize } from './selectize.js'
import { SignatureEditor as signature } from './signature.js'
import { SimplemdeEditor as simplemde } from './simplemde.js'
import { StarratingEditor as starrating } from './starrating.js'
import { StepperEditor as stepper } from './stepper.js'
import { StringEditor as string } from './string.js'
import { TableEditor as table } from './table.js'
import { UploadEditor as upload } from './upload.js'
Expand Down Expand Up @@ -71,6 +72,7 @@ export const editors = {
signature,
simplemde,
starrating,
stepper,
string,
table,
upload,
Expand Down
24 changes: 24 additions & 0 deletions src/editors/stepper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IntegerEditor } from './integer.js'

export class StepperEditor extends IntegerEditor {
build () {
super.build()
this.input.setAttribute('type', 'number')
const stepperButtons = this.theme.getStepperButtons(this.input)
this.control.appendChild(stepperButtons)
this.stepperDown = this.control.querySelector('.stepper-down')
this.stepperUp = this.control.querySelector('.stepper-up')
}

enable () {
super.enable()
this.stepperDown.removeAttribute('disabled')
this.stepperUp.removeAttribute('disabled')
}

disable () {
super.disable()
this.stepperDown.setAttribute('disabled', true)
this.stepperUp.setAttribute('disabled', true)
}
}
9 changes: 8 additions & 1 deletion src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ const describeBy = schema => {
}
}

/* Use the stepper editor for schemas with type `number` or `integer` and format `stepper` */
const stepper = schema => {
if ((schema.type === 'integer' || schema.type === 'number') && schema.format === 'stepper') {
return 'stepper'
}
}

/* Enable custom editor type */
const button = schema => schema.format === 'button' && 'button'

Expand All @@ -115,4 +122,4 @@ const ip = schema => schema.type === 'string' && ['ip', 'ipv4', 'ipv6', 'hostnam
const colorPicker = schema => schema.type === 'string' && schema.format === 'color' && 'colorpicker'

/* Export resolvers in order of discovery, first to last */
export const resolvers = [colorPicker, ip, ace, xhtml, markdown, jodit, autoComplete, uuid, info, button, describeBy, starratings, date, oneOf, arraysOfStrings, enumeratedProperties, enumSource, table, upload, base64, any, boolean, signature, primitive, object, defaultResolver]
export const resolvers = [colorPicker, ip, ace, xhtml, markdown, jodit, autoComplete, uuid, info, button, stepper, describeBy, starratings, date, oneOf, arraysOfStrings, enumeratedProperties, enumSource, table, upload, base64, any, boolean, signature, primitive, object, defaultResolver]
38 changes: 38 additions & 0 deletions src/theme.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { trigger } from './utilities'

const matchKey = [
'matches',
'webkitMatchesSelector',
Expand Down Expand Up @@ -231,6 +233,42 @@ export class AbstractTheme {
return el
}

getStepperButtons (input) {
const div = document.createElement('div')

const minusBtn = document.createElement('button')
minusBtn.setAttribute('type', 'button')
minusBtn.classList.add('stepper-down')

const plusBtn = document.createElement('button')
plusBtn.setAttribute('type', 'button')
plusBtn.classList.add('stepper-up')

const readonly = input.getAttribute('readonly')

if (readonly) {
minusBtn.setAttribute('disabled', true)
plusBtn.setAttribute('disabled', true)
}

minusBtn.textContent = '-'
plusBtn.textContent = '+'

minusBtn.addEventListener('click', () => {
input.stepDown()
trigger(input, 'change')
})

plusBtn.addEventListener('click', () => {
input.stepUp()
trigger(input, 'change')
})

div.appendChild(minusBtn)
div.appendChild(plusBtn)
return div
}

getRangeOutput (input, startvalue) {
const output = document.createElement('output')
output.value = startvalue || 0
Expand Down
55 changes: 53 additions & 2 deletions src/themes/bootstrap4.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AbstractTheme } from '../theme.js'
import rules from './bootstrap4.css.js'
import { trigger } from '../utilities'

/* Theme config options that allows changing various aspects of the output */
const options = {
Expand Down Expand Up @@ -85,6 +86,56 @@ export class bootstrap4Theme extends AbstractTheme {
return el
}

getStepperButtons (input) {
const inputGroup = document.createElement('div')
const prepend = document.createElement('div')
const append = document.createElement('div')

const minusBtn = document.createElement('button')
minusBtn.setAttribute('type', 'button')

const plusBtn = document.createElement('button')
plusBtn.setAttribute('type', 'button')

inputGroup.appendChild(prepend)
inputGroup.appendChild(input)
inputGroup.appendChild(append)
prepend.appendChild(minusBtn)
append.appendChild(plusBtn)

inputGroup.classList.add('input-group')
prepend.classList.add('input-group-prepend')
append.classList.add('input-group-append')
minusBtn.classList.add('btn')
minusBtn.classList.add('btn-secondary')
minusBtn.classList.add('stepper-down')
plusBtn.classList.add('btn')
plusBtn.classList.add('btn-secondary')
plusBtn.classList.add('stepper-up')

const readonly = input.getAttribute('readonly')

if (readonly) {
minusBtn.setAttribute('disabled', true)
plusBtn.setAttribute('disabled', true)
}

minusBtn.textContent = '-'
plusBtn.textContent = '+'

minusBtn.addEventListener('click', () => {
input.stepDown()
trigger(input, 'change')
})

plusBtn.addEventListener('click', () => {
input.stepUp()
trigger(input, 'change')
})

return inputGroup
}

getFormInputField (type) {
const el = super.getFormInputField(type)
if (type !== 'checkbox' && type !== 'radio' && type !== 'file') {
Expand Down Expand Up @@ -402,10 +453,10 @@ export class bootstrap4Theme extends AbstractTheme {
input.errmsg = document.createElement('p')
input.errmsg.classList.add('invalid-feedback')
input.controlgroup.appendChild(input.errmsg)
} else {
input.errmsg.style.display = ''
input.errmsg.style.display = 'block'
}

input.errmsg.style.display = 'block'
input.errmsg.textContent = text
}

Expand Down
27 changes: 27 additions & 0 deletions tests/codeceptjs/editors/stepper_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* global Feature Scenario Event */

var assert = require('assert')

Feature('stepper')

Scenario('should validate value @stepper', async (I) => {
I.amOnPage('stepper.html')
I.click('.get-value')
I.see('Property must be set.', '[data-schemapath="root.stepper"] div')
assert.equal(await I.grabValueFrom('.value'), '{}')
})

Scenario('should be constrained to maximun and minimun values when stepped @stepper', async (I) => {
I.amOnPage('stepper.html')
I.click('.stepper-up')
I.click('.stepper-up')
I.click('.stepper-up')
I.click('.get-value')
I.click('.get-value')
assert.equal(await I.grabValueFrom('.value'), '{"stepper":6}')
I.click('.stepper-down')
I.click('.stepper-down')
I.click('.stepper-down')
I.click('.get-value')
assert.equal(await I.grabValueFrom('.value'), '{"stepper":5}')
})
30 changes: 26 additions & 4 deletions tests/pages/number.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
<head>
<meta charset="utf-8"/>
<title>Number</title>
<link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/math.min.js" class="external_mathjs"></script>
<script src="../../dist/jsoneditor.js"></script>
</head>
<body>

<textarea class="value" cols="30" rows="10"></textarea>
<button class='get-value'>Get Value</button>
<button class='set-value'>Set Value</button>
<div class='container'></div>
<div class='json-editor-container'></div>

<script>
var container = document.querySelector('.container');
var jsonEditorContainer = document.querySelector('.json-editor-container');
var value = document.querySelector('.value');

var schema = {
Expand Down Expand Up @@ -44,12 +47,31 @@
"minimum": 1,
"maximum": 10,
"step": 0.25
},
"stepper_number": {
"title": "stepper number",
"format": "stepper",
"type": "number",
"minimum": 1,
"maximum": 10,
"step": 0.25
},
"stepper_integer": {
"title": "stepper integer",
"format": "stepper",
"type": "integer",
"minimum": 1,
"maximum": 10,
"step": 0.25
}
}
};

var editor = new JSONEditor(container, {
schema: schema
var editor = new JSONEditor(jsonEditorContainer, {
schema: schema,
theme: 'bootstrap4',
use_default_values: false,
show_errors: 'always'
});

document.querySelector('.get-value').addEventListener('click', function () {
Expand Down
59 changes: 59 additions & 0 deletions tests/pages/stepper.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Stepper</title>
<link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/math.min.js" class="external_mathjs"></script>
<script src="../../dist/jsoneditor.js"></script>
</head>
<body>

<div class="container">
<textarea class="value form-control" rows="10"></textarea>
<button class='get-value'>Get Value</button>
<button class='set-value'>Set Value</button>
<div class='json-editor-container'></div>
</div>


<script>
var jsonEditorContainer = document.querySelector('.json-editor-container');
var value = document.querySelector('.value');

var schema = {
"type": "object",
"title": "range",
"properties": {
"stepper": {
'type': 'integer',
'format': 'stepper',
"default": "",
"minimum": 5,
"maximum": 6
}
}
};

var editor = new JSONEditor(jsonEditorContainer, {
schema: schema,
theme: 'bootstrap4',
use_default_values: false,
required_by_default: true,
show_errors: 'always'
});

document.querySelector('.get-value').addEventListener('click', function () {
value.value = JSON.stringify(editor.getValue());
console.log(editor.getValue());
});

document.querySelector('.set-value').addEventListener('click', function () {
editor.setValue({number_range: 2})
});

</script>

</body>
</html>

0 comments on commit 84fe806

Please sign in to comment.