@kaspernj/api-maker 1.0.215 → 1.0.218
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -4
- package/src/base-model.mjs +1 -1
- package/src/bootstrap/attribute-row/basic-style.scss +9 -0
- package/src/bootstrap/attribute-row/index.jsx +84 -0
- package/src/bootstrap/attribute-rows.jsx +27 -0
- package/src/bootstrap/card.jsx +135 -0
- package/src/bootstrap/checkbox.jsx +79 -0
- package/src/bootstrap/checkboxes.jsx +122 -0
- package/src/bootstrap/index.js +0 -0
- package/src/bootstrap/input.jsx +160 -0
- package/src/bootstrap/invalid-feedback.jsx +31 -0
- package/src/bootstrap/live-table/model-row.jsx +150 -0
- package/src/bootstrap/live-table.jsx +399 -0
- package/src/bootstrap/paginate.jsx +153 -0
- package/src/bootstrap/radio-buttons.jsx +87 -0
- package/src/bootstrap/select.jsx +110 -0
- package/src/bootstrap/sort-link.jsx +102 -0
- package/src/collection-loader.jsx +7 -8
- package/src/inputs/auto-submit.mjs +37 -0
- package/src/inputs/checkbox.jsx +97 -0
- package/src/inputs/checkboxes.jsx +113 -0
- package/src/inputs/id-for-component.mjs +15 -0
- package/src/inputs/input-wrapper.jsx +170 -0
- package/src/inputs/input.jsx +235 -0
- package/src/inputs/money.jsx +177 -0
- package/src/inputs/name-for-component.mjs +15 -0
- package/src/inputs/select.jsx +87 -0
- package/src/model-class-require.mjs +1 -1
- package/src/model-name.mjs +6 -2
- package/src/params.mjs +7 -0
- package/src/super-admin/index-page/index.jsx +44 -0
- package/src/super-admin/index.jsx +46 -0
- package/src/super-admin/layout/header/index.jsx +60 -0
- package/src/super-admin/layout/header/style.scss +124 -0
- package/src/super-admin/layout/index.jsx +156 -0
- package/src/super-admin/layout/menu/index.jsx +116 -0
- package/src/super-admin/layout/menu/menu-content.jsx +55 -0
- package/src/super-admin/layout/menu/menu-item/index.jsx +27 -0
- package/src/super-admin/layout/menu/menu-item/style.scss +30 -0
- package/src/super-admin/layout/menu/style.scss +103 -0
- package/src/super-admin/layout/no-access.jsx +16 -0
- package/src/super-admin/layout/style.scss +25 -0
- package/src/super-admin/show-page.jsx +9 -0
- package/src/table/column-identifier.mjs +23 -0
- package/src/table/column-visible.mjs +7 -0
- package/src/table/model-row.jsx +182 -0
- package/src/table/select-calculator.mjs +48 -0
- package/src/table/style.scss +72 -0
- package/src/table/table-settings.js +175 -0
- package/src/table/table.jsx +498 -0
- package/src/table/variables.scss +11 -0
- package/src/table/with-breakpoint.jsx +48 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import inputWrapper from "../inputs/input-wrapper"
|
|
3
|
+
import InvalidFeedback from "./invalid-feedback"
|
|
4
|
+
import PropTypes from "prop-types"
|
|
5
|
+
import propTypesExact from "prop-types-exact"
|
|
6
|
+
import React from "react"
|
|
7
|
+
|
|
8
|
+
class ApiMakerBootstrapRadioButtons extends React.PureComponent {
|
|
9
|
+
static propTypes = propTypesExact({
|
|
10
|
+
attribute: PropTypes.string,
|
|
11
|
+
collection: PropTypes.array.isRequired,
|
|
12
|
+
defaultValue: PropTypes.oneOfType([
|
|
13
|
+
PropTypes.number,
|
|
14
|
+
PropTypes.string
|
|
15
|
+
]),
|
|
16
|
+
id: PropTypes.string,
|
|
17
|
+
inputProps: PropTypes.object.isRequired,
|
|
18
|
+
name: PropTypes.string,
|
|
19
|
+
model: PropTypes.object,
|
|
20
|
+
onChange: PropTypes.func,
|
|
21
|
+
onMatchValidationError: PropTypes.func,
|
|
22
|
+
wrapperClassName: PropTypes.string,
|
|
23
|
+
wrapperOpts: PropTypes.object.isRequired
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
render () {
|
|
27
|
+
return (
|
|
28
|
+
<div className={this.wrapperClassName()}>
|
|
29
|
+
<input {...this.props.inputProps} type="hidden" value="" />
|
|
30
|
+
{this.props.collection.map((option, index) => this.optionElement(option, index))}
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
inputRadioClassName () {
|
|
36
|
+
const classNames = ["form-check-input"]
|
|
37
|
+
|
|
38
|
+
if (this.props.wrapperOpts.errors.length > 0)
|
|
39
|
+
classNames.push("is-invalid")
|
|
40
|
+
|
|
41
|
+
return classNames.join(" ")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
generatedId () {
|
|
45
|
+
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
optionElement (option, index) {
|
|
49
|
+
const {collection} = digs(this.props, "collection")
|
|
50
|
+
const {onChange} = this.props
|
|
51
|
+
const id = this.generatedId()
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div className="form-check" key={`option-${option[1]}`}>
|
|
55
|
+
<input
|
|
56
|
+
className={this.inputRadioClassName()}
|
|
57
|
+
data-option-value={option[1]}
|
|
58
|
+
defaultChecked={option[1] == this.props.inputProps.defaultValue}
|
|
59
|
+
id={id}
|
|
60
|
+
name={this.props.inputProps.name}
|
|
61
|
+
onChange={onChange}
|
|
62
|
+
type="radio"
|
|
63
|
+
value={option[1]}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<label className="form-check-label" htmlFor={id}>
|
|
67
|
+
{option[0]}
|
|
68
|
+
</label>
|
|
69
|
+
|
|
70
|
+
{(index + 1) == collection.length && this.props.wrapperOpts.errors.length > 0 &&
|
|
71
|
+
<InvalidFeedback errors={this.props.wrapperOpts.errors} />
|
|
72
|
+
}
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
wrapperClassName () {
|
|
78
|
+
const classNames = ["component-bootstrap-radio-buttons"]
|
|
79
|
+
|
|
80
|
+
if (this.props.wrapperClassName)
|
|
81
|
+
classNames.push(this.props.wrapperClassName)
|
|
82
|
+
|
|
83
|
+
return classNames.join(" ")
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default inputWrapper(ApiMakerBootstrapRadioButtons)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import {digs} from "diggerize"
|
|
2
|
+
import inputWrapper from "../inputs/input-wrapper"
|
|
3
|
+
import {Select} from "../inputs/select"
|
|
4
|
+
import InvalidFeedback from "./invalid-feedback"
|
|
5
|
+
import PropTypes from "prop-types"
|
|
6
|
+
import React from "react"
|
|
7
|
+
|
|
8
|
+
class ApiMakerBootstrapSelect extends React.PureComponent {
|
|
9
|
+
static propTypes = {
|
|
10
|
+
attribute: PropTypes.string,
|
|
11
|
+
className: PropTypes.string,
|
|
12
|
+
description: PropTypes.node,
|
|
13
|
+
id: PropTypes.string,
|
|
14
|
+
hint: PropTypes.node,
|
|
15
|
+
hintBottom: PropTypes.node,
|
|
16
|
+
inputProps: PropTypes.object.isRequired,
|
|
17
|
+
label: PropTypes.node,
|
|
18
|
+
labelContainerClassName: PropTypes.string,
|
|
19
|
+
model: PropTypes.object,
|
|
20
|
+
wrapperClassName: PropTypes.string,
|
|
21
|
+
wrapperOpts: PropTypes.object.isRequired
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
render () {
|
|
25
|
+
const {
|
|
26
|
+
children,
|
|
27
|
+
className,
|
|
28
|
+
description,
|
|
29
|
+
id,
|
|
30
|
+
inputProps,
|
|
31
|
+
hint,
|
|
32
|
+
hintBottom,
|
|
33
|
+
label,
|
|
34
|
+
labelContainerClassName,
|
|
35
|
+
name,
|
|
36
|
+
wrapperClassName,
|
|
37
|
+
wrapperOpts,
|
|
38
|
+
...restProps
|
|
39
|
+
} = this.props
|
|
40
|
+
const {ref, ...forwardedInputProps} = inputProps
|
|
41
|
+
const {errors} = digs(wrapperOpts, "errors")
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className={this.wrapperClassName()}>
|
|
45
|
+
{wrapperOpts.label &&
|
|
46
|
+
<div className={labelContainerClassName ? labelContainerClassName : null}>
|
|
47
|
+
<label className={this.labelClassName()} htmlFor={inputProps.id}>
|
|
48
|
+
{wrapperOpts.label}
|
|
49
|
+
</label>
|
|
50
|
+
</div>
|
|
51
|
+
}
|
|
52
|
+
{description &&
|
|
53
|
+
<div className="mb-4">
|
|
54
|
+
{description}
|
|
55
|
+
</div>
|
|
56
|
+
}
|
|
57
|
+
{hint &&
|
|
58
|
+
<span className="font-smoothing font-xs form-text text-muted">
|
|
59
|
+
{hint}
|
|
60
|
+
</span>
|
|
61
|
+
}
|
|
62
|
+
{children}
|
|
63
|
+
{!children &&
|
|
64
|
+
<Select
|
|
65
|
+
{...forwardedInputProps}
|
|
66
|
+
className={this.selectClassName()}
|
|
67
|
+
inputProps={inputProps}
|
|
68
|
+
inputRef={ref}
|
|
69
|
+
wrapperOpts={wrapperOpts}
|
|
70
|
+
{...restProps}
|
|
71
|
+
/>
|
|
72
|
+
}
|
|
73
|
+
{hintBottom &&
|
|
74
|
+
<span className="form-text text-muted font-smoothing font-xs">
|
|
75
|
+
{hintBottom}
|
|
76
|
+
</span>
|
|
77
|
+
}
|
|
78
|
+
{errors.length > 0 && <InvalidFeedback errors={errors} />}
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
labelClassName () {
|
|
84
|
+
const classNames = ["form-group-label"]
|
|
85
|
+
|
|
86
|
+
if (this.props.labelClassName)
|
|
87
|
+
classNames.push(this.props.labelClassName)
|
|
88
|
+
|
|
89
|
+
return classNames.join(" ")
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
selectClassName () {
|
|
93
|
+
const classNames = ["form-control"]
|
|
94
|
+
|
|
95
|
+
if (this.props.className) classNames.push(this.props.className)
|
|
96
|
+
if (this.props.wrapperOpts.errors.length > 0) classNames.push("is-invalid")
|
|
97
|
+
|
|
98
|
+
return classNames.join(" ")
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
wrapperClassName () {
|
|
102
|
+
const classNames = ["form-group", "component-bootstrap-select"]
|
|
103
|
+
|
|
104
|
+
if (this.props.wrapperClassName) classNames.push(this.props.wrapperClassName)
|
|
105
|
+
|
|
106
|
+
return classNames.join(" ")
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default inputWrapper(ApiMakerBootstrapSelect, {type: "select"})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {digg, digs} from "diggerize"
|
|
2
|
+
import inflection from "inflection"
|
|
3
|
+
import PropTypes from "prop-types"
|
|
4
|
+
import qs from "qs"
|
|
5
|
+
import React from "react"
|
|
6
|
+
|
|
7
|
+
import Link from "../link"
|
|
8
|
+
import PureComponent from "set-state-compare/src/pure-component"
|
|
9
|
+
import withQueryParams from "on-location-changed/src/with-query-params"
|
|
10
|
+
|
|
11
|
+
class ApiMakerBootstrapSortLink extends PureComponent {
|
|
12
|
+
static propTypes = {
|
|
13
|
+
attribute: PropTypes.string.isRequired,
|
|
14
|
+
className: PropTypes.string,
|
|
15
|
+
linkComponent: PropTypes.object,
|
|
16
|
+
onChanged: PropTypes.func,
|
|
17
|
+
query: PropTypes.object.isRequired,
|
|
18
|
+
queryParams: PropTypes.object.isRequired,
|
|
19
|
+
title: PropTypes.node
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
searchKey = digg(this, "props", "query", "queryArgs").searchKey || "q"
|
|
23
|
+
|
|
24
|
+
attribute () {
|
|
25
|
+
return inflection.underscore(this.props.attribute)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
href () {
|
|
29
|
+
const {queryParams} = digs(this.props, "queryParams")
|
|
30
|
+
const {searchKey} = digs(this, "searchKey")
|
|
31
|
+
|
|
32
|
+
if (!queryParams[searchKey]) queryParams[searchKey] = {}
|
|
33
|
+
|
|
34
|
+
queryParams[searchKey].s = `${this.attribute()} ${this.sortMode()}` // eslint-disable-line id-length
|
|
35
|
+
|
|
36
|
+
const newParams = qs.stringify(queryParams)
|
|
37
|
+
const newPath = `${location.pathname}?${newParams}`
|
|
38
|
+
|
|
39
|
+
return newPath
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
isSortedByAttribute () {
|
|
43
|
+
const {queryParams} = digs(this.props, "queryParams")
|
|
44
|
+
const {searchKey} = digs(this, "searchKey")
|
|
45
|
+
const params = queryParams[searchKey] || {}
|
|
46
|
+
|
|
47
|
+
if (params.s == this.attribute()) return true
|
|
48
|
+
if (params.s == `${this.attribute()} asc`) return true
|
|
49
|
+
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
render () {
|
|
54
|
+
const LinkComponent = this.linkComponent()
|
|
55
|
+
const {attribute, className, linkComponent, onChanged, query, queryParams, title, ...restProps} = this.props
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<LinkComponent
|
|
60
|
+
className={this.className()}
|
|
61
|
+
data-attribute={attribute}
|
|
62
|
+
data-sort-mode={this.sortMode()}
|
|
63
|
+
to={this.href()}
|
|
64
|
+
{...restProps}
|
|
65
|
+
>
|
|
66
|
+
{this.title()}
|
|
67
|
+
</LinkComponent>
|
|
68
|
+
</>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
className () {
|
|
73
|
+
const classNames = ["component-api-maker-bootstrap-sort-link"]
|
|
74
|
+
|
|
75
|
+
if (this.props.className) classNames.push(this.props.className)
|
|
76
|
+
|
|
77
|
+
return classNames.join(" ")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
linkComponent () {
|
|
81
|
+
if (this.props.linkComponent) return this.props.linkComponent
|
|
82
|
+
|
|
83
|
+
return Link
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
sortMode () {
|
|
87
|
+
if (this.isSortedByAttribute()) return "desc"
|
|
88
|
+
|
|
89
|
+
return "asc"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
title () {
|
|
93
|
+
const {attribute, query} = digs(this.props, "attribute", "query")
|
|
94
|
+
const {title} = this.props
|
|
95
|
+
|
|
96
|
+
if (title) return title
|
|
97
|
+
|
|
98
|
+
return query.modelClass().humanAttributeName(attribute)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default withQueryParams(ApiMakerBootstrapSortLink)
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import Collection from "
|
|
1
|
+
import Collection from "./collection"
|
|
2
2
|
import {debounce} from "debounce"
|
|
3
3
|
import {digg, digs} from "diggerize"
|
|
4
|
-
import EventCreated from "
|
|
5
|
-
import EventDestroyed from "
|
|
6
|
-
import EventUpdated from "
|
|
7
|
-
import instanceOfClassName from "
|
|
8
|
-
import
|
|
4
|
+
import EventCreated from "./event-created"
|
|
5
|
+
import EventDestroyed from "./event-destroyed"
|
|
6
|
+
import EventUpdated from "./event-updated"
|
|
7
|
+
import instanceOfClassName from "./instance-of-class-name"
|
|
8
|
+
import {LocationChanged} from "on-location-changed/src/location-changed-component"
|
|
9
|
+
import Params from "./params"
|
|
9
10
|
import PropTypes from "prop-types"
|
|
10
11
|
import React from "react"
|
|
11
12
|
|
|
12
|
-
import {LocationChanged} from "on-location-changed/src/location-changed-component"
|
|
13
|
-
|
|
14
13
|
export default class CollectionLoader extends React.PureComponent {
|
|
15
14
|
static defaultProps = {
|
|
16
15
|
destroyEnabled: true,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {digg} from "diggerize"
|
|
2
|
+
import inflection from "inflection"
|
|
3
|
+
|
|
4
|
+
export default class ApiMakerInputsAutoSubmit {
|
|
5
|
+
constructor ({component}) {
|
|
6
|
+
this.component = component
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
autoSubmit () {
|
|
10
|
+
const {attribute, model} = this.component.props
|
|
11
|
+
const updateAttributeName = inflection.underscore(attribute)
|
|
12
|
+
const updateParams = {}
|
|
13
|
+
|
|
14
|
+
updateParams[updateAttributeName] = this.value()
|
|
15
|
+
|
|
16
|
+
model.update(updateParams)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
value () {
|
|
20
|
+
const inputRef = this.component.props.inputRef || this.component.props.inputProps.ref || this.component.inputRef
|
|
21
|
+
const input = digg(inputRef, "current")
|
|
22
|
+
|
|
23
|
+
if (input.type == "checkbox") {
|
|
24
|
+
if (input.checked) {
|
|
25
|
+
if (input.value !== undefined) {
|
|
26
|
+
return input.value
|
|
27
|
+
} else {
|
|
28
|
+
return 1
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return digg(input, "value")
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import AutoSubmit from "./auto-submit.mjs"
|
|
2
|
+
import {digg, digs} from "diggerize"
|
|
3
|
+
import EventUpdated from "../event-updated"
|
|
4
|
+
import inputWrapper from "./input-wrapper"
|
|
5
|
+
import PropTypes from "prop-types"
|
|
6
|
+
import React from "react"
|
|
7
|
+
|
|
8
|
+
class ApiMakerInputsCheckbox extends React.PureComponent {
|
|
9
|
+
static defaultProps = {
|
|
10
|
+
autoRefresh: false,
|
|
11
|
+
autoSubmit: false,
|
|
12
|
+
defaultValue: 1,
|
|
13
|
+
zeroInput: true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static propTypes = {
|
|
17
|
+
attribute: PropTypes.string,
|
|
18
|
+
autoRefresh: PropTypes.bool.isRequired,
|
|
19
|
+
autoSubmit: PropTypes.bool.isRequired,
|
|
20
|
+
defaultChecked: PropTypes.bool,
|
|
21
|
+
defaultValue: PropTypes.node,
|
|
22
|
+
id: PropTypes.string,
|
|
23
|
+
inputRef: PropTypes.object,
|
|
24
|
+
model: PropTypes.object,
|
|
25
|
+
name: PropTypes.string,
|
|
26
|
+
onErrors: PropTypes.func,
|
|
27
|
+
onMatchValidationError: PropTypes.func,
|
|
28
|
+
zeroInput: PropTypes.bool
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
render () {
|
|
32
|
+
const {
|
|
33
|
+
attribute,
|
|
34
|
+
autoRefresh,
|
|
35
|
+
autoSubmit,
|
|
36
|
+
defaultChecked,
|
|
37
|
+
defaultValue,
|
|
38
|
+
id,
|
|
39
|
+
inputProps,
|
|
40
|
+
inputRef,
|
|
41
|
+
model,
|
|
42
|
+
name,
|
|
43
|
+
onChange,
|
|
44
|
+
zeroInput,
|
|
45
|
+
wrapperOpts,
|
|
46
|
+
...restProps
|
|
47
|
+
} = this.props
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
{autoRefresh && model &&
|
|
52
|
+
<EventUpdated model={model} onUpdated={digg(this, "onModelUpdated")} />
|
|
53
|
+
}
|
|
54
|
+
{zeroInput && inputProps.name &&
|
|
55
|
+
<input defaultValue="0" name={inputProps.name} type="hidden" />
|
|
56
|
+
}
|
|
57
|
+
<input
|
|
58
|
+
{...inputProps}
|
|
59
|
+
data-auto-refresh={autoRefresh}
|
|
60
|
+
data-auto-submit={autoSubmit}
|
|
61
|
+
defaultValue={defaultValue}
|
|
62
|
+
onChange={digg(this, "onChanged")}
|
|
63
|
+
type="checkbox"
|
|
64
|
+
{...restProps}
|
|
65
|
+
/>
|
|
66
|
+
</>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
onChanged = (...args) => {
|
|
71
|
+
const {attribute, autoSubmit, model, onChange} = this.props
|
|
72
|
+
|
|
73
|
+
if (attribute && autoSubmit && model) new AutoSubmit({component: this}).autoSubmit()
|
|
74
|
+
if (onChange) onChange(...args)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onModelUpdated = (args) => {
|
|
78
|
+
const inputRef = digg(this, "props", "inputProps", "ref")
|
|
79
|
+
|
|
80
|
+
if (!inputRef.current) {
|
|
81
|
+
// This can happen if the component is being unmounted
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const {attribute} = digs(this.props, "attribute")
|
|
86
|
+
const newModel = digg(args, "model")
|
|
87
|
+
const currentChecked = digg(inputRef, "current", "checked")
|
|
88
|
+
const newValue = newModel.readAttribute(attribute)
|
|
89
|
+
|
|
90
|
+
if (currentChecked != newValue) {
|
|
91
|
+
inputRef.current.checked = newValue
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export {ApiMakerInputsCheckbox as Checkbox}
|
|
97
|
+
export default inputWrapper(ApiMakerInputsCheckbox, {type: "checkbox"})
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import classNames from "classnames"
|
|
2
|
+
import {digs} from "diggerize"
|
|
3
|
+
import inputWrapper from "./input-wrapper"
|
|
4
|
+
import inflection from "inflection"
|
|
5
|
+
import InvalidFeedback from "../bootstrap/invalid-feedback"
|
|
6
|
+
import PropTypes from "prop-types"
|
|
7
|
+
import propTypesExact from "prop-types-exact"
|
|
8
|
+
import React from "react"
|
|
9
|
+
|
|
10
|
+
class ApiMakerInputsCheckboxes extends React.PureComponent {
|
|
11
|
+
static propTypes = propTypesExact({
|
|
12
|
+
attribute: PropTypes.string,
|
|
13
|
+
defaultValue: PropTypes.array,
|
|
14
|
+
id: PropTypes.string,
|
|
15
|
+
inputProps: PropTypes.object.isRequired,
|
|
16
|
+
label: PropTypes.node,
|
|
17
|
+
model: PropTypes.object,
|
|
18
|
+
name: PropTypes.string,
|
|
19
|
+
onChange: PropTypes.func,
|
|
20
|
+
options: PropTypes.array.isRequired,
|
|
21
|
+
wrapperOpts: PropTypes.object
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
render () {
|
|
25
|
+
const {className, inputProps, label, wrapperOpts, ...restProps} = this.props
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={classNames("component-bootstrap-check-boxes", className)} {...restProps}>
|
|
29
|
+
<input name={this.inputName()} ref={this.props.inputProps.ref} type="hidden" value="" />
|
|
30
|
+
{this.props.options.map((option, index) => this.optionElement(option, index))}
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
inputDefaultValue () {
|
|
36
|
+
const {attribute, defaultValue, model} = this.props
|
|
37
|
+
|
|
38
|
+
if (defaultValue) {
|
|
39
|
+
return defaultValue
|
|
40
|
+
} else if (attribute && model) {
|
|
41
|
+
if (!model[attribute])
|
|
42
|
+
throw `No such attribute: ${attribute}`
|
|
43
|
+
|
|
44
|
+
return this.props.model[attribute]()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
inputCheckboxClassName () {
|
|
49
|
+
const classNames = []
|
|
50
|
+
|
|
51
|
+
if (this.props.wrapperOpts.errors.length > 0) classNames.push("is-invalid")
|
|
52
|
+
|
|
53
|
+
return classNames.join(" ")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
inputName () {
|
|
57
|
+
if (this.props.name) {
|
|
58
|
+
return `${this.props.name}[]`
|
|
59
|
+
} else if (this.props.model) {
|
|
60
|
+
return `${this.props.model.modelClassData().paramKey}[${inflection.underscore(this.props.attribute)}]`
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
isDefaultSelected (option) {
|
|
65
|
+
let defaultValue = this.inputDefaultValue()
|
|
66
|
+
|
|
67
|
+
if (!defaultValue) return false
|
|
68
|
+
|
|
69
|
+
if (defaultValue.constructor === Array) {
|
|
70
|
+
return defaultValue.includes(option)
|
|
71
|
+
} else {
|
|
72
|
+
return defaultValue == option
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
generatedId () {
|
|
77
|
+
if (!this.generatedIdValue)
|
|
78
|
+
this.generatedIdValue = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
|
79
|
+
|
|
80
|
+
return this.generatedIdValue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
optionElement (option, index) {
|
|
84
|
+
const {onChange, options, wrapperOpts} = this.props
|
|
85
|
+
const {errors} = digs(wrapperOpts, "errors")
|
|
86
|
+
const id = `${this.generatedId()}-${index}`
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className="checkboxes-option" key={`option-${option[1]}`}>
|
|
90
|
+
<input
|
|
91
|
+
className={this.inputCheckboxClassName()}
|
|
92
|
+
data-option-value={option[1]}
|
|
93
|
+
defaultChecked={this.isDefaultSelected(option[1])}
|
|
94
|
+
id={id}
|
|
95
|
+
name={this.inputName()}
|
|
96
|
+
onChange={onChange}
|
|
97
|
+
type="checkbox"
|
|
98
|
+
value={option[1]}
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<label className="ml-1" htmlFor={id}>
|
|
102
|
+
{option[0]}
|
|
103
|
+
</label>
|
|
104
|
+
|
|
105
|
+
{(index + 1) == options.length && errors.length > 0 &&
|
|
106
|
+
<InvalidFeedback errors={errors} />
|
|
107
|
+
}
|
|
108
|
+
</div>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default inputWrapper(ApiMakerInputsCheckboxes)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import inflection from "inflection"
|
|
2
|
+
|
|
3
|
+
export default function apiMakerIdForComponent (component) {
|
|
4
|
+
if ("id" in component.props) {
|
|
5
|
+
return component.props.id
|
|
6
|
+
} else if (component.props.attribute && component.props.model) {
|
|
7
|
+
return `${component.props.model.modelClassData().paramKey}_${inflection.underscore(component.props.attribute)}`
|
|
8
|
+
} else if (component.generatedInputId) {
|
|
9
|
+
return component.generatedInputId
|
|
10
|
+
} else {
|
|
11
|
+
const generatedInputId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
|
|
12
|
+
component.generatedInputId = generatedInputId
|
|
13
|
+
return generatedInputId
|
|
14
|
+
}
|
|
15
|
+
}
|