├── .babelrc
├── .gitignore
├── src
├── module.js
├── bootstrap
│ ├── actions-trcl.html
│ ├── help.html
│ ├── section.html
│ ├── fieldset.html
│ ├── tabs.html
│ ├── submit.html
│ ├── actions.html
│ ├── checkbox.html
│ ├── radios.html
│ ├── select.html
│ ├── radios-inline.html
│ ├── checkboxes.html
│ ├── radio-buttons.html
│ ├── array.html
│ ├── textarea.html
│ ├── default.html
│ └── tabarray.html
└── bootstrap-decorator.js
├── gulp
├── tasks
│ ├── default.js
│ ├── jscs.js
│ ├── serve.js
│ └── protractor.js
└── index.js
├── test
└── protractor
│ ├── conf.js
│ └── specs
│ ├── validation-messages.js
│ ├── custom-validation.js
│ └── tabarray.js
├── .jscsrc
├── gulpfile.js
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── ISSUE_TEMPLATE.md
├── examples
├── data
│ ├── types.json
│ ├── simple-oneOf.json
│ ├── simple.json
│ ├── conditional-required.json
│ ├── tabarray-sortable.json
│ ├── tabarray-add-disabled.json
│ ├── tabarray-remove-disabled.json
│ ├── grid.json
│ ├── complex-keys.json
│ ├── tabarray.json
│ ├── titlemaps.json
│ ├── array.json
│ ├── array-deep.json
│ └── sink.json
├── custom-validators.html
└── example.html
├── webpack.config.dist.js
├── bower.json
├── CONTRIBUTING.md
├── package.json
├── webpack.config.js
├── README.md
└── dist
├── angular-schema-form-bootstrap.min.js
└── angular-schema-form-bootstrap.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 |
4 |
--------------------------------------------------------------------------------
/src/module.js:
--------------------------------------------------------------------------------
1 | require('bootstrap-decorator.js');
2 |
--------------------------------------------------------------------------------
/gulp/tasks/default.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task('default', [
4 | 'jscs'
5 | ]);
6 |
--------------------------------------------------------------------------------
/test/protractor/conf.js:
--------------------------------------------------------------------------------
1 | exports.config = {
2 | seleniumAddress: 'http://localhost:4444/wd/hub'
3 | }
4 |
--------------------------------------------------------------------------------
/.jscsrc:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "google",
3 | "maximumLineLength": 1000,
4 | "requireSemicolons": true
5 | }
6 |
--------------------------------------------------------------------------------
/src/bootstrap/actions-trcl.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/bootstrap/help.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 |
2 | //all of the tasks themselves are contained in the gulp/tasks directory,
3 | //which is accessed through gulp/index.js
4 |
5 | require('./gulp');
6 |
--------------------------------------------------------------------------------
/gulp/tasks/jscs.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | jscs = require('gulp-jscs');
3 |
4 | gulp.task('jscs', function() {
5 | gulp.src('./src/**/*.js')
6 | .pipe(jscs());
7 | });
8 |
--------------------------------------------------------------------------------
/src/bootstrap/section.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gulp/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | tasks = fs.readdirSync('./gulp/tasks'),
3 | gulp = require('gulp');
4 |
5 | tasks.forEach(function(task) {
6 | require('./tasks/' + task);
7 | });
8 |
--------------------------------------------------------------------------------
/gulp/tasks/serve.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp'),
2 | webserver = require('gulp-webserver');
3 |
4 | gulp.task('serve', function() {
5 | gulp.src('.')
6 | .pipe(webserver({
7 | livereload: true,
8 | directoryListing: true,
9 | open: true
10 | }));
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/src/bootstrap/fieldset.html:
--------------------------------------------------------------------------------
1 |
2 | {{ form.title }}
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/bootstrap/tabs.html:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | #### Description
2 |
3 | Add your description here
4 |
5 | #### Fixes Related issues
6 | - add related
7 | - issues here
8 |
9 | #### Checklist
10 | - [ ] I have read and understand the CONTRIBUTIONS.md file
11 | - [ ] I have searched for and linked related issues
12 | - [ ] I have created test cases to ensure quick resolution of the PR is easier
13 | - [ ] I am NOT targeting main branch
14 | - [ ] I did NOT include the dist folder in my PR
15 |
16 | @json-schema-form/angular-schema-form-bootstrap-lead
17 |
--------------------------------------------------------------------------------
/examples/data/types.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Types",
5 | "properties": {
6 | "string": {
7 | "type": "string",
8 | "minLength": 3
9 | },
10 | "integer": {
11 | "type": "integer"
12 | },
13 | "number": {
14 | "type": "number"
15 | },
16 | "boolean": {
17 | "type": "boolean"
18 | }
19 | },
20 | "required": ["number"]
21 | },
22 | "form": [
23 | "*",
24 | {"type": "submit", "title": "OK"}
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/webpack.config.dist.js:
--------------------------------------------------------------------------------
1 | const config = require('./webpack.config.js');
2 | const path = require('path');
3 |
4 | config.entry = {
5 | 'angular-schema-form-bootstrap': [ path.join(__dirname, 'src', 'module') ],
6 | 'angular-schema-form-bootstrap-bundled': [ 'angular-schema-form', path.join(__dirname, 'src', 'module') ],
7 | 'angular-schema-form-bootstrap.min': [ path.join(__dirname, 'src', 'module') ],
8 | 'angular-schema-form-bootstrap-bundled.min': [ 'angular-schema-form', path.join(__dirname, 'src', 'module') ],
9 | }
10 |
11 | module.exports = config;
12 |
--------------------------------------------------------------------------------
/examples/data/simple-oneOf.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Comment",
5 | "properties": {
6 | "name": {
7 | "oneOf": [
8 | {
9 | "type": "string",
10 | "enum": ["Bob"]
11 | },
12 | {
13 | "type": "string",
14 | "pattern": "^\\S+ \\S+$"
15 | }
16 | ]
17 | }
18 | },
19 | "required": ["name"]
20 | },
21 | "form": [
22 | {
23 | "key": "name",
24 | "title": "Name"
25 | }
26 |
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
8 | #### Enhancement
9 | As a user/developer, when I ... I should be able to ...
10 |
11 | #### Expected behaviour
12 | I expected ...
13 |
14 | #### Actual behaviour
15 | It actually ...
16 |
17 | #### Gist/Plunker/Demo
18 | [Description](url)
19 |
20 | #### Related issues
21 | This is/maybe related to ...
22 |
23 | @json-schema-form/angular-schema-form-bootstrap-lead
24 |
--------------------------------------------------------------------------------
/src/bootstrap/submit.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
13 | {{form.title}}
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/bootstrap/actions.html:
--------------------------------------------------------------------------------
1 |
2 |
7 | {{item.title}}
13 |
14 |
--------------------------------------------------------------------------------
/src/bootstrap/checkbox.html:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/examples/data/simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Comment",
5 | "properties": {
6 | "name": {
7 | "title": "Name",
8 | "type": "string"
9 | },
10 | "email": {
11 | "title": "Email",
12 | "type": "string",
13 | "pattern": "^\\S+@\\S+$",
14 | "description": "Email will be used for evil."
15 | },
16 | "comment": {
17 | "title": "Comment",
18 | "type": "string",
19 | "maxLength": 20,
20 | "validationMessage": "Don't be greedy!"
21 | }
22 | },
23 | "required": ["name","email","comment"]
24 | },
25 | "form": [
26 | "name",
27 | { "key": "email", "ngModelOptions": {"updateOn": "blur"}},
28 | {
29 | "key": "comment",
30 | "type": "textarea",
31 | "placeholder": "Make a comment"
32 | },
33 | {
34 | "type": "submit",
35 | "style": "btn-info",
36 | "title": "OK"
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/src/bootstrap/radios.html:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/src/bootstrap/select.html:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/src/bootstrap/radios-inline.html:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/examples/data/conditional-required.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "properties": {
5 | "switch": {
6 | "title": "Spam me, please",
7 | "type": "boolean"
8 | },
9 | "email": {
10 | "title": "Email",
11 | "type": "string",
12 | "pattern": "^\\S+@\\S+$",
13 | "description": "Email will be used for evil."
14 | }
15 | },
16 | "required": ["switch"]
17 | },
18 | "form": [
19 | {
20 | "type": "help",
21 | "helpvalue": "Schema Form does not support oneOf (yet), but you can do a workaround and simulate certain scenarios with 'condition' and 'required' (and/or 'readonly') in the form.
"
22 | },
23 | "switch",
24 | {
25 | "key": "email",
26 | "condition": "model.switch",
27 | "required": true
28 | },
29 | {
30 | "key": "email",
31 | "condition": "!model.switch"
32 | },
33 | {
34 | "type": "submit",
35 | "style": "btn-info",
36 | "title": "OK"
37 | }
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-schema-form-bootstrap",
3 | "authors": [
4 | "David Jensen (Textalk) ",
5 | "Marcel Bennett "
6 | ],
7 | "description": "Bootstrap 3 decorator for Angular Schema Form",
8 | "main": "dist/bootstrap-decorator.js",
9 | "keywords": [
10 | "angular-schema-form-decorator",
11 | "json-schema",
12 | "json-schema-form",
13 | "angular-schema-form"
14 | ],
15 | "license": "MIT",
16 | "homepage": "schemaform.io",
17 | "ignore": [
18 | "**/.*",
19 | "node_modules",
20 | "bower_components",
21 | "test",
22 | "tests"
23 | ],
24 | "dependencies": {
25 | "angular-schema-form": "1.0.0-alpha.4"
26 | },
27 | "devDependencies": {
28 | "angular-ui-ace": "bower",
29 | "angular-schema-form-datepicker": ">= 0.1.0",
30 | "angular-schema-form-colorpicker": ">= 0.1.0",
31 | "jquery": "~2.1.1",
32 | "angular-mocks": ">= 1.2",
33 | "tx-tinymce": ">= 0.0.5",
34 | "angular-ui-sortable": ">=0.12.11",
35 | "bootstrap-vertical-tabs": "~1.2.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/examples/data/tabarray-sortable.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Tab Array: Sortable (Drag and Drop)",
5 | "properties": {
6 | "sortableTabArray": {
7 | "type": "array",
8 | "items": {
9 | "type": "object",
10 | "properties": {
11 | "name": { "type": "string" },
12 | "nick": { "type": "string" }
13 | }
14 | }
15 | }
16 | }
17 | },
18 | "form": [
19 | {
20 | "type": "section",
21 | "htmlCss": "row",
22 | "items": [
23 | {
24 | "type": "help",
25 | "helpvalue": "Drag and drop sortable tab array "
26 | },
27 | {
28 | "key": "sortableTabArray",
29 | "type": "tabarray",
30 | "title": "My name is: {{ value.name }}",
31 | "items" : [
32 | {"key": "sortableTabArray[].name", "htmlClass": "nameField"},
33 | {"key": "sortableTabArray[].nick", "htmlClass": "nickField"}
34 | ]
35 | }
36 | ]
37 | }
38 | ],
39 | "model": {}
40 | }
41 |
--------------------------------------------------------------------------------
/src/bootstrap/checkboxes.html:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ------------
3 | We love contributions!
4 |
5 | **Please base any merge request on the *development* branch instead of *master*.**
6 |
7 | The reason for this is that we're trying to use
8 | [git flow](http://danielkummer.github.io/git-flow-cheatsheet/), and it makes merging your pull
9 | request heck of a lot easier for us.
10 |
11 | Please avoid including anything from the `dist/` directory as that can make merging harder, and we
12 | always generate these files when we make a new release.
13 |
14 | If its a new field type consider making it an add-on instead,
15 | especially if it has external dependencies. See [extending Schema Form documentation.](https://github.com/json-schema-form/angular-schema-form/blob/development/docs/extending.md)
16 |
17 | With new features we love to see updates to the docs as well as tests, that makes it super
18 | easy and fast for us to merge it!
19 |
20 | Also consider running any code through the code style checker [jscs](https://github.com/mdevils/node-jscs)
21 | (or even better use it in your editor) with preset set to `google`. You can also use `gulp jscs` to
22 | check your code.
23 |
--------------------------------------------------------------------------------
/examples/data/tabarray-add-disabled.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Tab Array: Add Disabled",
5 | "properties": {
6 | "addDisabledTabArray": {
7 | "type": "array",
8 | "items": {
9 | "type": "object",
10 | "properties": {
11 | "name": { "type": "string" },
12 | "nick": { "type": "string" }
13 | }
14 | }
15 | }
16 | }
17 | },
18 | "form": [
19 | {
20 | "type": "section",
21 | "htmlCss": "row",
22 | "items": [
23 | {
24 | "type": "help",
25 | "helpvalue": "Tab array with add link hidden "
26 | },
27 | {
28 | "key": "addDisabledTabArray",
29 | "type": "tabarray",
30 | "add": null,
31 | "title": "My name is: {{ value.name }}",
32 | "sortOptions": {
33 | "disabled": true
34 | },
35 | "items" : [
36 | {"key": "addDisabledTabArray[].name", "htmlClass": "nameField"},
37 | {"key": "addDisabledTabArray[].nick", "htmlClass": "nickField"}
38 | ]
39 | }
40 | ]
41 | }
42 | ],
43 | "model": {}
44 | }
45 |
--------------------------------------------------------------------------------
/examples/data/tabarray-remove-disabled.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Tab Array: Remove Disabled",
5 | "properties": {
6 | "removeDisabledTabArray": {
7 | "type": "array",
8 | "items": {
9 | "type": "object",
10 | "properties": {
11 | "name": { "type": "string" },
12 | "nick": { "type": "string" }
13 | }
14 | }
15 | }
16 | }
17 | },
18 | "form": [
19 | {
20 | "type": "section",
21 | "htmlCss": "row",
22 | "items": [
23 | {
24 | "type": "help",
25 | "helpvalue": "Tab array with remove button hidden "
26 | },
27 | {
28 | "key": "removeDisabledTabArray",
29 | "type": "tabarray",
30 | "remove": null,
31 | "title": "My name is: {{ value.name }}",
32 | "sortOptions": {
33 | "disabled": true
34 | },
35 | "items" : [
36 | {"key": "removeDisabledTabArray[].name", "htmlClass": "nameField"},
37 | {"key": "removeDisabledTabArray[].nick", "htmlClass": "nickField"}
38 | ]
39 | }
40 | ]
41 | }
42 | ],
43 | "model": {}
44 | }
45 |
--------------------------------------------------------------------------------
/src/bootstrap/radio-buttons.html:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/gulp/tasks/protractor.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | // The protractor task
4 | var protractor = require('gulp-protractor');
5 |
6 | // Start a standalone server
7 | var webdriver_standalone = protractor.webdriver_standalone;
8 |
9 | // Download and update the selenium driver
10 | var webdriver_update = protractor.webdriver_update;
11 |
12 | // Downloads the selenium webdriver
13 | gulp.task('webdriver-update', webdriver_update);
14 |
15 | // Start the standalone selenium server
16 | // NOTE: This is not needed if you reference the
17 | // seleniumServerJar in your protractor.conf.js
18 | gulp.task('webdriver-standalone', webdriver_standalone);
19 |
20 |
21 | // Setting up the test task
22 | gulp.task('protractor', ['webdriver-update'], function(cb) {
23 | gulp.src(['test/protractor/specs/**/*.js']).pipe(protractor.protractor({
24 | configFile: 'test/protractor/conf.js',
25 | })).on('error', function(e) {
26 | console.log(e);
27 | }).on('end', cb);
28 | });
29 |
30 | ['validation-messages', 'custom-validation', 'tabarray'].forEach(function(name) {
31 | gulp.task('protractor:' + name, ['webdriver-update'], function(cb) {
32 | gulp.src(['test/protractor/specs/' + name + '.js']).pipe(protractor.protractor({
33 | configFile: 'test/protractor/conf.js',
34 | })).on('error', function(e) {
35 | console.log(e);
36 | }).on('end', cb);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/examples/data/grid.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Comment",
5 | "properties": {
6 | "name": {
7 | "title": "Name",
8 | "type": "string"
9 | },
10 | "email": {
11 | "title": "Email",
12 | "type": "string",
13 | "pattern": "^\\S+@\\S+$",
14 | "description": "Email will be used for evil."
15 | },
16 | "comment": {
17 | "title": "Comment",
18 | "type": "string",
19 | "maxLength": 20,
20 | "validationMessage": "Don't be greedy!"
21 | }
22 | },
23 | "required": ["name","email","comment"]
24 | },
25 | "form": [
26 | {
27 | "type": "help",
28 | "helpvalue": "Grid it up with bootstrap
"
29 | },
30 | {
31 | "type": "section",
32 | "htmlClass": "row",
33 | "items": [
34 | {
35 | "type": "section",
36 | "htmlClass": "col-xs-6",
37 | "items": ["name"]
38 | },
39 | {
40 | "type": "section",
41 | "htmlClass": "col-xs-6",
42 | "items": ["email"]
43 | }
44 | ]
45 | },
46 | {
47 | "key": "comment",
48 | "type": "textarea",
49 | "placeholder": "Make a comment"
50 | },
51 | {
52 | "type": "submit",
53 | "style": "btn-info",
54 | "title": "OK"
55 | }
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/examples/data/complex-keys.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Complex Key Support",
5 | "properties": {
6 | "a[\"b\"].c": {
7 | "type": "string"
8 | },
9 | "simple": {
10 | "type": "object",
11 | "properties": {
12 | "prøp": {
13 | "title": "UTF8 in both dot and bracket notation",
14 | "type": "string"
15 | }
16 | }
17 | },
18 | "array-key": {
19 | "type": "array",
20 | "items": {
21 | "type": "object",
22 | "properties": {
23 | "a'rr[\"l": {
24 | "title": "Control Characters",
25 | "type": "string"
26 | },
27 | "˙∆∂∞˚¬": {
28 | "type": "string"
29 | }
30 | },
31 | "required": [
32 | "a'rr[\"l",
33 | "˙∆∂∞˚¬"
34 | ]
35 | }
36 | }
37 | }
38 | },
39 | "form": [
40 | {
41 | "type": "help",
42 | "helpvalue": "Complex keys are only supported with AngularJS version 1.3.x, see known limitations in the docs."
43 | },
44 | "['a[\"b\"].c']",
45 | {
46 | "key": "array-key",
47 | "items": [
48 | "['array-key'][]['a'rr[\"l']",
49 | {
50 | "key": "['array-key'][]['˙∆∂∞˚¬']",
51 | "title": "Unicode Characters"
52 | }
53 | ]
54 | },
55 | {
56 | "key": "simple",
57 | "items": [
58 | "simple.prøp"
59 | ]
60 | }
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/examples/data/tabarray.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Comment",
5 | "properties": {
6 | "comments": {
7 | "type": "array",
8 | "minItems": 2,
9 | "items": {
10 | "type": "object",
11 | "properties": {
12 | "name": {
13 | "title": "Name",
14 | "type": "string"
15 | },
16 | "email": {
17 | "title": "Email",
18 | "type": "string",
19 | "pattern": "^\\S+@\\S+$",
20 | "description": "Email will be used for evil."
21 | },
22 | "comment": {
23 | "title": "Comment",
24 | "type": "string",
25 | "maxLength": 20,
26 | "validationMessage": "Don't be greedy!"
27 | }
28 | },
29 | "required": ["name","email","comment"]
30 | }
31 | }
32 | }
33 | },
34 | "form": [
35 | {
36 | "type": "help",
37 | "helpvalue": "Tabbed Array Example Tab arrays can have tabs to the left, top or right.
"
38 | },
39 | {
40 | "key": "comments",
41 | "type": "tabarray",
42 | "add": "New",
43 | "remove": "Delete",
44 | "style": {
45 | "remove": "btn-danger"
46 | },
47 | "title": "{{ value.name || 'Tab '+$index }}",
48 | "items": [
49 | "comments[].name",
50 | "comments[].email",
51 | {
52 | "key": "comments[].comment",
53 | "type": "textarea"
54 | }
55 | ]
56 | },
57 | {
58 | "type": "submit",
59 | "style": "btn-default",
60 | "title": "OK"
61 | }
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/src/bootstrap/array.html:
--------------------------------------------------------------------------------
1 |
34 |
--------------------------------------------------------------------------------
/src/bootstrap/textarea.html:
--------------------------------------------------------------------------------
1 |
8 |
{{form.title}}
9 |
10 |
19 |
20 |
22 |
25 |
33 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-schema-form-bootstrap",
3 | "version": "1.0.0-alpha.5",
4 | "description": "Bootstrap 3 decorator for Angular Schema Form",
5 | "main": "dist/angular-schema-form-bootstrap.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "dist": "webpack --config webpack.config.dist.js",
9 | "watch": "webpack --watch",
10 | "test": "echo \"Error: test not currently available\" && exit 1",
11 | "test-me": "karma start --log-level debug"
12 | },
13 | "keywords": [
14 | "angular-schema-form-decorator"
15 | ],
16 | "author": "json-schema-form",
17 | "contributors": [
18 | "David Jensen (https://github.com/davidlgj)",
19 | "Marcel J Bennett (https://github.com/Anthropic)"
20 | ],
21 | "license": "MIT",
22 | "dependencies": {
23 | "angular": ">= 1.2",
24 | "angular-messages": "^1.5.0",
25 | "angular-sanitize": ">= 1.2",
26 | "angular-schema-form": "^1.0.0-alpha.4",
27 | "tv4": "~1.0.15"
28 | },
29 | "devDependencies": {
30 | "babel": "^6.5.2",
31 | "babel-core": "^6.17.0",
32 | "babel-loader": "^6.2.5",
33 | "babel-polyfill": "^6.16.0",
34 | "babel-preset-es2015": "^6.16.0",
35 | "chai": "^3.5.0",
36 | "coveralls": "^2.11.0",
37 | "html": "^1.0.0",
38 | "html-loader": "^0.4.4",
39 | "html-webpack-plugin": "^2.25.0",
40 | "karma": "^0.13.22",
41 | "karma-chai-sinon": "^0.1.5",
42 | "karma-coverage": "^1.0.0",
43 | "karma-growler-reporter": "0.0.1",
44 | "karma-mocha": "^1.0.1",
45 | "karma-phantomjs-launcher": "^0.1.4",
46 | "karma-webpack": "^1.7.0",
47 | "mocha": "^2.5.3",
48 | "mocha-lcov-reporter": "0.0.1",
49 | "ngtemplate-loader": "^1.3.1",
50 | "protractor": "^2.5.1",
51 | "sinon": "^1.17.4",
52 | "sinon-chai": "^2.8.0",
53 | "streamqueue": "^0.1.3",
54 | "uglify-js": "github:mishoo/UglifyJS2#harmony",
55 | "webpack": "^2.1.0-beta.27",
56 | "webpack-dev-server": "^2.1.0-beta.12"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | /* global __dirname */
2 | /**
3 | * NOTE in order to build with angular-schema-form you must
4 | * have it cloned as a sibling directory to this one or npm
5 | * installed with the version you wish to build with.
6 | */
7 | const webpack = require('webpack');
8 | const path = require('path');
9 | const package = require('./package.json');
10 | const buildDate = new Date();
11 | console.log('Angular Schema Form Bootstrap v' + package.version);
12 | const plugins = [
13 | new webpack.BannerPlugin(
14 | 'angular-schema-form-bootstrap\n' +
15 | '@version ' + package.version + '\n' +
16 | '@date ' + buildDate.toUTCString() + '\n' +
17 | '@link https://github.com/json-schema-form/angular-schema-form-bootstrap\n' +
18 | '@license MIT\n' +
19 | 'Copyright (c) 2014-' + buildDate.getFullYear() + ' JSON Schema Form'),
20 | /* Minification only occurs if the output is named .min */
21 | new webpack.optimize.UglifyJsPlugin(
22 | {
23 | include: /\.min\.js$/,
24 | minimize: true
25 | })
26 | ];
27 |
28 | module.exports = {
29 | entry: {
30 | 'angular-schema-form-bootstrap': [ path.join(__dirname, 'src', 'module') ],
31 | 'angular-schema-form-bootstrap-bundled': [ 'angular-schema-form', path.join(__dirname, 'src', 'module') ],
32 | },
33 | output: {
34 | path: path.join(__dirname, 'dist'),
35 | filename: '[name].js',
36 | sourceMapFilename: '[name].map'
37 | },
38 | resolve: {
39 | modules: [
40 | path.join(__dirname, "src"),
41 | path.join(__dirname, "src", "bootstrap"),
42 | path.join(__dirname, "..", "angular-schema-form", "dist"),
43 | 'node_modules',
44 | ],
45 | extensions: [ '.js', '.html' ]
46 | },
47 | module: {
48 | rules: [
49 | {
50 | test: /\.js$/,
51 | use: [{
52 | loader: 'babel-loader',
53 | options: {
54 | presets: [
55 | [ "es2015", { "modules": false }]
56 | ]
57 | }
58 | }],
59 | exclude: /(node_modules|angular-schema-form)/
60 | },
61 | {
62 | test: /\.html$/,
63 | use: [{
64 | loader: 'ngtemplate-loader',
65 | options: {
66 | relativeTo: path.join(__dirname, 'src')
67 | }
68 | }, 'html-loader'],
69 | exclude: /(index)/
70 | }
71 | ]
72 | },
73 | externals: {
74 | 'angular': 'var angular',
75 | 'tv4': 'var tv4',
76 | 'bundle!angular-schema-form': 'commonjs angular-schema-form'
77 | },
78 | plugins: plugins
79 | };
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Angular Bootstrap Decorator
2 | ==========================
3 |
4 | For https://github.com/json-schema-form/angular-schema-form
5 |
6 | This is the new Bootstrap Decorator! That means a Bootstrap 3 frontend for the Angular Schema Form
7 | project. The former Bootstrap decorator used to be included in the main repo, but has now moved
8 | here.
9 |
10 | The big difference is that it now uses new builder methods, for more info on the builder see
11 | [our blog](https://medium.com/@SchemaFormIO/the-new-builder-pt-1-61fadde3c678).
12 |
13 | The biggest change for users is that the form no longer contains any `` tags
14 | since they are no longer needed.
15 |
16 | Install
17 | -------
18 | ```sh
19 | npm install angular-schema-form-bootstrap
20 | ```
21 | **note** we do not recommend using bower as even the bower team recommend using yarn and webpack now.
22 |
23 | The package.json 'main' script is this library alone and unminified so that minification can be handled by webpack or another script bundler.
24 |
25 | **Note when using webpack angular-schema-form versions match this repo so ASF 1.0.0-alpha.4 works with Bootstrap 1.0.0-alpha.4**.
26 |
27 | If you are unsure, check the bundled version in this repo and see which versions are used as both repo now include a version header.
28 |
29 | Look for this:
30 | ```js
31 | /*!
32 | * angular-schema-form
33 | * @version 1.0.0-alpha.4
34 | * @date Mon, 17 Apr 2017 08:55:13 GMT
35 | * @link https://github.com/json-schema-form/angular-schema-form
36 | * @license MIT
37 | * Copyright (c) 2014-2017 JSON Schema Form
38 | */
39 | ```
40 |
41 | Old versions pre-alpha work with 0.8.13 or ASF, but the alphas should be more stable than those versions with more bugs fixed.
42 |
43 | If you include `angular-schema-form-bootstrap-bundled.min.js` you **DO NOT** need to include angular-schema-form, it is now **embedded** within the bundled above file. If you wish to include the files separately you can still use `angular-schema-form-bootstrap.js` or `angular-schema-form-bootstrap.min.js`
44 |
45 | Future
46 | ------
47 | Using the new builder opens up for a lot of optimization. Primarily we can get rid of a lot of small
48 | watches by using build helpers. For instance, slapping on a `sf-changed` directive *only* if the
49 | form definition has an `onChange` option.
50 |
51 | Developer Install
52 | -----------------
53 | ```sh
54 | bower install
55 | npm install
56 | ```
57 | Then read package.json for the available scripts.
58 | **Note** templates are compiled so the templates script must be run after changes.
59 |
--------------------------------------------------------------------------------
/test/protractor/specs/validation-messages.js:
--------------------------------------------------------------------------------
1 | /* global browser, it, describe, element, by */
2 |
3 | describe('Schema Form validation messages', function() {
4 |
5 | describe('#string', function() {
6 | var URL = 'http://localhost:8080/examples/bootstrap-example.html#/86fb7505a8ab6a43bc70';
7 |
8 | it('should not complain if it gets a normal string', function() {
9 | browser.get(URL);
10 | var input = element.all(by.css('form[name=ngform] input')).first();
11 | input.sendKeys('string');
12 |
13 | expect(input.getAttribute('value')).toEqual('string');
14 | expect(input.evaluate('ngModel.$valid')).toEqual(true);
15 |
16 | });
17 |
18 |
19 | var validationMessageTestBuider = function(nr, value, validationMessage) {
20 | it('should say "' + validationMessage + '" when input is ' + value, function() {
21 | browser.get(URL);
22 | var input = element.all(by.css('form[name=ngform] input')).get(nr);
23 | input.sendKeys(value);
24 |
25 | var message = element.all(by.css('form[name=ngform] div[sf-message]')).get(nr);
26 | expect(input.evaluate('ngModel.$valid')).toEqual(false);
27 | expect(message.getText()).toEqual(validationMessage);
28 |
29 | });
30 | };
31 |
32 | var stringTests = {
33 | 's': 'String is too short (1 chars), minimum 3',
34 | 'tooo long string': 'String is too long (11 chars), maximum 10',
35 | 'foo 66': 'String does not match pattern: ^[a-zA-Z ]+$'
36 | };
37 |
38 | Object.keys(stringTests).forEach(function(value) {
39 | validationMessageTestBuider(0, value, stringTests[value]);
40 | });
41 |
42 |
43 | var integerTests = {
44 | '3': '3 is less than the allowed minimum of 6',
45 | '66': '66 is greater than the allowed maximum of 50',
46 | '11': 'Value is not a multiple of 3',
47 | // Chrome no longer lets you input anything but numbers in a type="number" input.
48 | 'aaa': 'Required' //'Value is not a valid number'
49 | };
50 |
51 | Object.keys(integerTests).forEach(function(value) {
52 | validationMessageTestBuider(1, value, integerTests[value]);
53 | });
54 |
55 |
56 | it('should say "Required" when fields are required', function() {
57 | browser.get(URL);
58 | element.all(by.css('form[name=ngform]')).submit();
59 | var input = element.all(by.css('form[name=ngform] input')).get(1);
60 |
61 | var message = element.all(by.css('form[name=ngform] div[sf-message]')).get(1);
62 | expect(input.evaluate('ngModel.$valid')).toEqual(false);
63 | expect(message.getText()).toEqual('Required');
64 |
65 | });
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/src/bootstrap/default.html:
--------------------------------------------------------------------------------
1 |
58 |
--------------------------------------------------------------------------------
/examples/data/titlemaps.json:
--------------------------------------------------------------------------------
1 | {
2 | "model": {
3 | "select": "a",
4 | "array": ["b"]
5 | },
6 | "schema": {
7 | "type": "object",
8 | "properties": {
9 | "select": {
10 | "title": "Select without titleMap",
11 | "type": "string",
12 | "enum": ["a","b","c"]
13 | },
14 | "select2": {
15 | "title": "Select with titleMap (old style)",
16 | "type": "string",
17 | "enum": ["a","b","c"]
18 | },
19 | "noenum": { "type": "string", "title": "No enum, but forms says it's a select" },
20 | "array": {
21 | "title": "Array with enum defaults to 'checkboxes'",
22 | "type": "array",
23 | "items": {
24 | "type": "string",
25 | "enum": ["a","b","c"]
26 | }
27 | },
28 | "array2": {
29 | "title": "Array with titleMap",
30 | "type": "array",
31 | "default": ["b","c"],
32 | "items": {
33 | "type": "string",
34 | "enum": ["a","b","c"]
35 | }
36 | },
37 | "radios": {
38 | "title": "Basic radio button example",
39 | "type": "string",
40 | "enum": ["a","b","c"]
41 | },
42 | "radiobuttons": {
43 | "title": "Radio buttons used to switch a boolean",
44 | "type": "boolean",
45 | "default": false
46 | }
47 | }
48 | },
49 | "form": [
50 | "select",
51 | {
52 | "key": "select2",
53 | "type": "select",
54 | "placeholder": "Please choose",
55 | "titleMap": {
56 | "a": "A",
57 | "b": "B",
58 | "c": "C"
59 | }
60 | },
61 | {
62 | "key": "noenum",
63 | "type": "select",
64 | "placeholder": "Please choose",
65 | "titleMap": [
66 | { "value":"a", "name": "A" },
67 | { "value":"b", "name":"B" },
68 | { "value":"c", "name":"C" }
69 | ]
70 | },
71 | "array",
72 | {
73 | "key": "array2",
74 | "type": "checkboxes",
75 | "titleMap": [
76 | { "value":"a", "name": "A" },
77 | { "value":"b", "name":"B" },
78 | { "value":"c", "name":"C" }
79 | ]
80 | },
81 | {
82 | "key": "radios",
83 | "type": "radios",
84 | "titleMap": [
85 | { "value":"c", "name": "C" },
86 | { "value":"b", "name":"B" },
87 | { "value":"a", "name":"A" }
88 | ]
89 | },
90 | {
91 | "key":"radiobuttons",
92 | "type": "radiobuttons",
93 | "titleMap": [
94 | {"value": false, "name": "No way"},
95 | {"value": true, "name": "OK"}
96 | ]
97 | }
98 | ]
99 | }
100 |
--------------------------------------------------------------------------------
/test/protractor/specs/custom-validation.js:
--------------------------------------------------------------------------------
1 | describe('Schema Form custom validators', function() {
2 | it('should have a form with content', function() {
3 | browser.get('http://localhost:8080/examples/custom-validators.html');
4 |
5 | expect(element(by.css('form')).getInnerHtml()).not.toEqual('');
6 | });
7 |
8 | describe('#name', function() {
9 | it('should not complain if it gets a normal name', function() {
10 | browser.get('http://localhost:8080/examples/custom-validators.html');
11 | var input = element.all(by.css('form input')).first();
12 | input.sendKeys('Joe Schmoe');
13 |
14 | expect(input.getAttribute('value')).toEqual('Joe Schmoe');
15 | expect(input.evaluate('ngModel.$valid')).toEqual(true);
16 |
17 | });
18 |
19 | it('should complain if it gets a "Bob" as a name', function() {
20 | browser.get('http://localhost:8080/examples/custom-validators.html');
21 | var input = element.all(by.css('form input')).first();
22 | input.sendKeys('Bob');
23 |
24 | expect(input.getAttribute('value')).toEqual('Bob');
25 | expect(input.evaluate('ngModel.$valid')).toEqual(false);
26 | });
27 | });
28 |
29 | describe('#email', function() {
30 | it('should not complain if it gets a normal email', function() {
31 | browser.get('http://localhost:8080/examples/custom-validators.html');
32 | var input = element.all(by.css('form input')).get(1);
33 | input.sendKeys('foo@mailinator.com');
34 |
35 | expect(input.getAttribute('value')).toEqual('foo@mailinator.com');
36 | expect(input.evaluate('ngModel.$valid')).toEqual(true);
37 |
38 | });
39 |
40 | it('should complain if it gets a my email', function() {
41 | browser.get('http://localhost:8080/examples/custom-validators.html');
42 | var input = element.all(by.css('form input')).get(1);
43 | input.sendKeys('david.lgj@gmail.com');
44 |
45 | expect(input.getAttribute('value')).toEqual('david.lgj@gmail.com');
46 | expect(input.evaluate('ngModel.$valid')).toEqual(false);
47 | });
48 | });
49 |
50 | describe('#comment', function() {
51 | it('should not complain if it gets a normal email', function() {
52 | browser.get('http://localhost:8080/examples/custom-validators.html');
53 | var input = element.all(by.css('form input')).get(1);
54 | input.sendKeys('foo@mailinator.com');
55 |
56 | expect(input.getAttribute('value')).toEqual('foo@mailinator.com');
57 | expect(input.evaluate('ngModel.$valid')).toEqual(true);
58 |
59 | });
60 |
61 | it('should complain if it gets a my email', function() {
62 | browser.get('http://localhost:8080/examples/custom-validators.html');
63 | var input = element.all(by.css('form input')).get(1);
64 | input.sendKeys('david.lgj@gmail.com');
65 |
66 | expect(input.getAttribute('value')).toEqual('david.lgj@gmail.com');
67 | expect(input.evaluate('ngModel.$valid')).toEqual(false);
68 | });
69 | });
70 |
71 |
72 |
73 |
74 | });
75 |
--------------------------------------------------------------------------------
/src/bootstrap/tabarray.html:
--------------------------------------------------------------------------------
1 |
53 |
54 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/examples/data/array.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "title": "Comment",
5 | "required": ["comments"],
6 | "properties": {
7 | "tags": {
8 | "type": "array",
9 | "maxItems": 4,
10 | "minItems": 2,
11 | "uniqueItems": true,
12 | "items": {
13 | "type": "string"
14 | }
15 | },
16 | "comments": {
17 | "type": "array",
18 | "maxItems": 2,
19 | "items": {
20 | "type": "object",
21 | "properties": {
22 | "name": {
23 | "title": "Name",
24 | "type": "string"
25 | },
26 | "email": {
27 | "title": "Email",
28 | "type": "string",
29 | "pattern": "^\\S+@\\S+$",
30 | "description": "Email will be used for evil."
31 | },
32 | "spam": {
33 | "title": "Spam",
34 | "type": "boolean",
35 | "default": true
36 | },
37 | "comment": {
38 | "title": "Comment",
39 | "type": "string",
40 | "maxLength": 20,
41 | "validationMessage": "Don't be greedy!"
42 | }
43 | },
44 | "required": ["name","comment"]
45 | }
46 | },
47 | "matrix": {
48 | "type": "array",
49 | "items": {
50 | "type": "array",
51 | "items": {
52 | "type": "string"
53 | }
54 | }
55 | },
56 | "subs": {
57 | "type": "array",
58 | "items": {
59 | "type": "object",
60 | "properties": {
61 | "sub": {
62 | "type": "array",
63 | "items": {
64 | "type": "string"
65 | }
66 | }
67 | }
68 | }
69 | },
70 | "triplesubs": {
71 | "type": "array",
72 | "items": {
73 | "type": "object",
74 | "properties": {
75 | "sub": {
76 | "type": "array",
77 | "items": {
78 | "type": "array",
79 | "items": {
80 | "type": "string"
81 | }
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 | },
89 | "form": [
90 | {
91 | "type": "help",
92 | "helpvalue": "Array Example Try adding a couple of forms, reorder by drag'n'drop.
"
93 | },
94 | "tags",
95 | {
96 | "key": "comments",
97 | "add": "New",
98 | "style": {
99 | "add": "btn-success"
100 | },
101 | "items": [
102 | "comments[].name",
103 | "comments[].email",
104 | {
105 | "key": "comments[].spam",
106 | "type": "checkbox",
107 | "title": "Yes I want spam.",
108 | "condition": "model.comments[arrayIndex].email"
109 | },
110 | {
111 | "key": "comments[].comment",
112 | "type": "textarea"
113 | }
114 | ]
115 | },
116 | "matrix",
117 | {
118 | "type": "array",
119 | "key": "subs",
120 | "items": [
121 | "subs[].sub"
122 | ]
123 | },
124 | "triplesubs",
125 | {
126 | "type": "submit",
127 | "style": "btn-info",
128 | "title": "OK"
129 | }
130 | ],
131 | "model": {
132 | "tags": ["one", "two"],
133 | "comments": [{}],
134 | "matrix": [["one","two"],["three"]],
135 | "subs": [{ "sub":["yes!"] }]
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/examples/custom-validators.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom validators, async validators etc
5 |
6 |
7 |
8 |
9 |
10 | Demo of custom validators, async validators and parsers
11 | Check the source
12 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/test/protractor/specs/tabarray.js:
--------------------------------------------------------------------------------
1 | describe('tab array', function () {
2 | it('form should exist', function () {
3 | browser.get('http://localhost:8080/examples/bootstrap-example.html');
4 |
5 | element(by.css('#selectTest')).all(by.cssContainingText('option', 'Tab Array')).first().click().then(function() {
6 | expect(element(by.css('form.ng-valid-schema-form')).getInnerHtml()).not.toEqual('');
7 | });
8 | });
9 |
10 | it('add link should be hidden', function () {
11 | browser.get('http://localhost:8080/examples/bootstrap-example.html');
12 |
13 | /* select the add disabled example */
14 | element(by.css('#selectTest')).element(by.cssContainingText('option', 'Tab Array: Add Disabled')).click().then(function() {
15 |
16 | /* Add link should not be displayed */
17 | var tabs = element.all(by.css('.nav-tabs li'));
18 | expect(tabs.get(0).isDisplayed()).toBeTruthy();
19 | expect(tabs.get(1).isDisplayed()).toBeFalsy();
20 |
21 | var addLink = element.all(by.partialLinkText('Add'));
22 | expect(addLink.count()).toBe(0);
23 |
24 | /*** control tests ***/
25 | /* Remove button should be displayed */
26 | var removeButton = element.all(by.partialButtonText('Remove')).get(0);
27 | expect(removeButton.isDisplayed()).toBeTruthy();
28 | });
29 | });
30 |
31 | it('remove button should be hidden', function () {
32 | browser.get('http://localhost:8080/examples/bootstrap-example.html');
33 |
34 | /* select the remove disabled example */
35 | element(by.css('#selectTest')).element(by.cssContainingText('option', 'Tab Array: Remove Disabled')).click().then(function() {
36 |
37 | /* Remove button should not be displayed */
38 | var removeButton = element.all(by.partialButtonText('Remove')).get(0);
39 | expect(removeButton.isDisplayed()).toBeFalsy();
40 |
41 | /*** control tests ***/
42 | /* Add link should not be displayed */
43 | var tabs = element.all(by.css('.nav-tabs li'));
44 | expect(tabs.get(0).isDisplayed()).toBeTruthy();
45 | expect(tabs.get(1).isDisplayed()).toBeTruthy();
46 |
47 | var addLink = element.all(by.partialLinkText('Add'));
48 | expect(addLink.count()).toBe(1);
49 | });
50 | });
51 |
52 | it('should be able order elements in array by dragging the tabs', function () {
53 | browser.get('http://localhost:8080/examples/bootstrap-example.html');
54 |
55 | function checkDragDrop(i) {
56 | browser.driver.wait(protractor.until.elementLocated(by.xpath("//ol/li[1]/a[text()='My name is: Name " + (i + 1) +"']")), 10000);
57 | expect(element.all(by.css('.nav-tabs li a')).get(0).getText()).toBe('My name is: Name ' + (i + 1));
58 | }
59 |
60 | function populateTab(i) {
61 | browser.driver.wait(protractor.until.elementLocated(by.css('.tab-pane.active.index' + i)), 5000);
62 |
63 | browser.driver.wait(protractor.until.elementLocated(by.css('.tab-pane.index' + i + ' div.nickField > input')), 5000);
64 | input = element.all(by.css('.tab-pane.index' + i + ' div.nickField > input')).first();
65 | input.sendKeys('Nickname ' + i);
66 |
67 | browser.driver.wait(protractor.until.elementLocated(by.css('.tab-pane.index' + i + ' div.nameField > input')), 5000);
68 | input = element.all(by.css('.tab-pane.index' + i + ' div.nameField > input')).first();
69 | input.sendKeys('Name ' + i);
70 |
71 | browser.driver.wait(protractor.until.elementLocated(by.linkText('My name is: Name ' + i)), 10000);
72 | }
73 |
74 | /* select the sortable example */
75 | element(by.css('#selectTest')).element(by.cssContainingText('option', 'Tab Array: Sortable')).click().then(function() {
76 |
77 | var i;
78 | var elementsToAdd = 9;
79 |
80 | /* the array starts with 1 element, populate the first element */
81 | populateTab(0);
82 |
83 | /* add elements and populate */
84 | for (i = 1; i <= elementsToAdd; i++) {
85 | var tabLink = element.all(by.css('.glyphicon-plus'));
86 | tabLink.click().then(populateTab(i));
87 | }
88 |
89 | /* continue when all tabs have been populated*/
90 | browser.driver.wait(protractor.until.elementLocated(by.linkText('My name is: Name ' + elementsToAdd)), 10000);
91 |
92 | /* check the number of tabs */
93 | var tabs = element.all(by.css('.nav-tabs li'));
94 | expect(tabs.count()).toBe(elementsToAdd + 2); //Extra 1 for the "+ Add" link
95 |
96 | /* drag the tabs into reverse order (descending) */
97 | for (i = 0; i < elementsToAdd; i++) {
98 | var draggable_element = element.all(by.css('.nav-tabs li')).get(0);
99 | var target_element = element.all(by.css('.nav-tabs li')).get(elementsToAdd - i);
100 | expect(draggable_element.isPresent()).toEqual(true);
101 | expect(target_element.isPresent()).toEqual(true);
102 | browser.actions().dragAndDrop(draggable_element, target_element).perform().then(checkDragDrop(i));
103 | }
104 |
105 | /* final check of the reverse ordered tabs */
106 | for (i = 0; i <= elementsToAdd; i++) {
107 | expect(element.all(by.css('.nav-tabs li a')).get(i).getText()).toBe('My name is: Name ' + (elementsToAdd - i));
108 | }
109 | });
110 | });
111 | });
112 |
--------------------------------------------------------------------------------
/src/bootstrap-decorator.js:
--------------------------------------------------------------------------------
1 | // ngtemplate-loader embeds the html on build
2 | import actionsTemplate from './bootstrap/actions.html';
3 | import arrayTemplate from './bootstrap/array.html';
4 | import checkboxTemplate from './bootstrap/checkbox.html';
5 | import checkboxesTemplate from './bootstrap/checkboxes.html';
6 | import defaultTemplate from './bootstrap/default.html';
7 | import fieldsetTemplate from './bootstrap/fieldset.html';
8 | import helpTemplate from './bootstrap/help.html';
9 | import radiobuttonsTemplate from './bootstrap/radio-buttons.html';
10 | import radiosTemplate from './bootstrap/radios.html';
11 | import radiosInlineTemplate from './bootstrap/radios-inline.html';
12 | import sectionTemplate from './bootstrap/section.html';
13 | import selectTemplate from './bootstrap/select.html';
14 | import submitTemplate from './bootstrap/submit.html';
15 | import tabarrayTemplate from './bootstrap/tabarray.html';
16 | import tabsTemplate from './bootstrap/tabs.html';
17 | import textareaTemplate from './bootstrap/textarea.html';
18 |
19 | angular
20 | .module('schemaForm')
21 | .config(bootstrapDecoratorConfig);
22 |
23 | bootstrapDecoratorConfig.$inject = [
24 | 'schemaFormProvider', 'schemaFormDecoratorsProvider', 'sfBuilderProvider', 'sfPathProvider', '$injector'
25 | ];
26 |
27 | function bootstrapDecoratorConfig(
28 | schemaFormProvider, decoratorsProvider, sfBuilderProvider, sfPathProvider, $injector) {
29 | var base = 'decorators/bootstrap/';
30 |
31 | var simpleTransclusion = sfBuilderProvider.builders.simpleTransclusion;
32 | var ngModelOptions = sfBuilderProvider.builders.ngModelOptions;
33 | var ngModel = sfBuilderProvider.builders.ngModel;
34 | var sfField = sfBuilderProvider.builders.sfField;
35 | var condition = sfBuilderProvider.builders.condition;
36 | var array = sfBuilderProvider.builders.array;
37 | var numeric = sfBuilderProvider.builders.numeric;
38 |
39 | // Tabs is so bootstrap specific that it stays here.
40 | var tabs = function(args) {
41 | if (args.form.tabs && args.form.tabs.length > 0) {
42 | var tabContent = args.fieldFrag.querySelector('.tab-content');
43 |
44 | args.form.tabs.forEach(function(tab, index) {
45 | var evalExpr = '(evalExpr(' + args.path + '.tabs[' + index + ']' +
46 | '.condition, { model: model, "arrayIndex": $index}))';
47 | var div = document.createElement('div');
48 | div.className = 'tab-pane';
49 | div.setAttribute('ng-disabled', 'form.readonly');
50 | div.setAttribute('ng-show', 'selected.tab === ' + index);
51 | div.setAttribute('ng-class', '{active: selected.tab === ' + index + '}');
52 | if(!!tab.condition) {
53 | div.setAttribute('ng-if', evalExpr);
54 | };
55 |
56 | var childFrag = args.build(tab.items, args.path + '.tabs[' + index + '].items', args.state);
57 | div.appendChild(childFrag);
58 | tabContent.appendChild(div);
59 | });
60 | }
61 | };
62 |
63 | var selectPlaceholder = function(args) {
64 | if (args.form.placeholder) {
65 | var selectBox = args.fieldFrag.querySelector('select');
66 | var option = document.createElement('option');
67 | option.setAttribute('value', '');
68 |
69 | /* We only want the placeholder to show when we do not have a value on the model.
70 | * We make ngModel builder replace all so we can use $$value$$.
71 | */
72 | option.setAttribute('sf-field-model', 'replaceAll');
73 |
74 | /* https://github.com/angular/angular.js/issues/12190#issuecomment-115277040
75 | * angular > 1.4 does a emptyOption.attr('selected', true)
76 | * which does not like the ng-if comment.
77 | */
78 | if (angular.version.major === 1 && angular.version.minor < 4) {
79 | option.setAttribute('ng-if', '$$value$$ === undefined');
80 | } else {
81 | option.setAttribute('ng-show', '$$value$$ === undefined');
82 | }
83 |
84 | option.textContent = args.form.placeholder;
85 |
86 | selectBox.appendChild(option);
87 | }
88 | };
89 |
90 | var defaults = [sfField, ngModel, ngModelOptions, condition];
91 | decoratorsProvider.defineDecorator('bootstrapDecorator', {
92 | actions: {template: actionsTemplate, builder: defaults},
93 | array: {template: arrayTemplate, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
94 | button: {template: submitTemplate, builder: defaults},
95 | checkbox: {template: checkboxTemplate, builder: defaults},
96 | checkboxes: {template: checkboxesTemplate, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
97 | conditional: {template: sectionTemplate, builder: [ sfField, simpleTransclusion, condition ]},
98 | 'default': {template: defaultTemplate, builder: defaults},
99 | fieldset: {template: fieldsetTemplate, builder: [ sfField, simpleTransclusion, condition ]},
100 | help: {template: helpTemplate, builder: defaults},
101 | number: {template: defaultTemplate, builder: defaults.concat(numeric)},
102 | password: {template: defaultTemplate, builder: defaults},
103 | radios: {template: radiosTemplate, builder: defaults},
104 | 'radios-inline': {template: radiosInlineTemplate, builder: defaults},
105 | radiobuttons: {template: radiobuttonsTemplate, builder: defaults},
106 | section: {template: sectionTemplate, builder: [ sfField, simpleTransclusion, condition ]},
107 | select: {template: selectTemplate, builder: [ selectPlaceholder ].concat(defaults)},
108 | submit: {template: submitTemplate, builder: defaults},
109 | tabarray: {template: tabarrayTemplate, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
110 | tabs: {template: tabsTemplate, builder: [ sfField, ngModelOptions, tabs, condition ]},
111 | textarea: {template: textareaTemplate, builder: defaults},
112 | }, []);
113 | };
114 |
--------------------------------------------------------------------------------
/examples/data/array-deep.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "properties": {
5 | "transportCategory": {
6 | "type": "array",
7 | "items": {
8 | "type": "object",
9 | "properties": {
10 | "mode": { "type": "string", "enum": ["Car", "Motorbike", "Horse"] },
11 | "transportOption": {
12 | "type": "array",
13 | "items": {
14 | "type": "object",
15 | "properties": {
16 | "name": { "type": "string" },
17 | "numberOfWheels": { "type": "number" },
18 | "forSale": { "type": "string", "enum": ["yes", "no"] },
19 | "price": { "type": "number" },
20 | "history": {
21 | "type": "object",
22 | "properties": {
23 | "historyKnown": { "type": "string", "enum": ["yes", "no"] },
24 | "previousOwners": {
25 | "type": "array",
26 | "items": {
27 | "type": "object",
28 | "properties": {
29 | "ownerName": { "type": "string" },
30 | "purchaseDate": { "type": "string" },
31 | "logBookProvided": { "type": "string", "enum": ["yes", "no"] },
32 | "logBookEntry": {
33 | "type": "array",
34 | "items": {
35 | "type": "object",
36 | "properties": {
37 | "entryId": { "type": "number" },
38 | "entryDate": { "type": "string" },
39 | "entryNote": { "type": "string" }
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 | },
56 | "form": [
57 | {
58 | "key": "transportCategory",
59 | "type": "tabarray",
60 | "add": "New",
61 | "style": {
62 | "add": "btn-success"
63 | },
64 | "title": "{{ 'Tab '+$index + ' ' + value.mode + ' ' || 'Tab' + $index }}",
65 | "items": [
66 | "transportCategory[].mode",
67 | {
68 | "key": "transportCategory[].transportOption",
69 | "items": [
70 | "transportCategory[].transportOption[].name",
71 | {
72 | "key": "transportCategory[].transportOption[].numberOfWheels",
73 | "condition": "model.transportCategory[arrayIndices[0]].mode != 'Horse'"
74 | },
75 | "transportCategory[].transportOption[].forSale",
76 | {
77 | "key": "transportCategory[].transportOption[].price",
78 | "condition": "model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].forSale == 'yes'"
79 | },
80 | "transportCategory[].transportOption[].history.historyKnown",
81 | {
82 | "key": "transportCategory[].transportOption[].history.previousOwners",
83 | "condition": "model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].history.historyKnown == 'yes'",
84 | "items": [
85 | "transportCategory[].transportOption[].history.previousOwners[].ownerName",
86 | {
87 | "key": "transportCategory[].transportOption[].history.previousOwners[].purchaseDate",
88 | "condition": "model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].history.previousOwners[arrayIndices[2]].ownerName.length > 2"
89 | },
90 | {
91 | "key": "transportCategory[].transportOption[].history.previousOwners[].logBookProvided",
92 | "condition": "model.transportCategory[arrayIndices[0]].mode != 'Horse' && model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].history.previousOwners[arrayIndices[2]].ownerName.length > 2"
93 | },
94 | {
95 | "key": "transportCategory[].transportOption[].history.previousOwners[].logBookEntry",
96 | "condition": "model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].history.previousOwners[arrayIndices[2]].logBookProvided == 'yes'",
97 | "items": [
98 | "transportCategory[].transportOption[].history.previousOwners[].logBookEntry[].entryId",
99 | "transportCategory[].transportOption[].history.previousOwners[].logBookEntry[].entryDate",
100 | {
101 | "key": "transportCategory[].transportOption[].history.previousOwners[].logBookEntry[].entryNote",
102 | "condition": "model.transportCategory[arrayIndices[0]].transportOption[arrayIndices[1]].history.previousOwners[arrayIndices[2]].logBookEntry[arrayIndices[3]].entryDate.length > 2"
103 | }
104 | ]
105 | }
106 | ]
107 | }
108 | ]
109 | }
110 | ]
111 | }
112 | ],
113 | "model": {
114 | "transportCategory": [
115 | {
116 | "mode": "Car",
117 | "transportOption": [
118 | {
119 | "name": "Bertie",
120 | "forSale": "yes",
121 | "price": 100,
122 | "history": {
123 | "historyKnown": "no"
124 | }
125 | },
126 | {
127 | "name": "Lightning McQueen",
128 | "forSale": "no",
129 | "history": {
130 | "historyKnown": "yes",
131 | "previousOwners": [
132 | {
133 | "ownerName": ""
134 | },
135 | {
136 | "ownerName": "Arlo",
137 | "logBookProvided": "yes",
138 | "logBookEntry": [
139 | {
140 | "entryId": 2,
141 | "entryDate": "2015-06-23"
142 | },
143 | {
144 | "entryId": 4
145 | }
146 | ]
147 | }
148 | ]
149 | }
150 | }
151 | ]
152 | },
153 | {
154 | "mode": "Horse",
155 | "transportOption": [
156 | {
157 | "name": "Phar Lap",
158 | "forSale": "no"
159 | },
160 | {
161 | "name": "Greyhound",
162 | "forSale": "yes",
163 | "price": 1000,
164 | "history": {
165 | "historyKnown": "yes",
166 | "previousOwners": [
167 | {
168 | "ownerName": "Tom"
169 | }
170 | ]
171 | }
172 | }
173 | ]
174 | }
175 | ]
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/examples/data/sink.json:
--------------------------------------------------------------------------------
1 | {
2 | "schema": {
3 | "type": "object",
4 | "required": [
5 | "name",
6 | "shoesizeLeft"
7 | ],
8 | "properties": {
9 | "name": {
10 | "title": "Name",
11 | "description": "Gimme yea name lad",
12 | "type": "string",
13 | "pattern": "^[^/]*$",
14 | "minLength": 2
15 | },
16 | "invitation": {
17 | "type": "string",
18 | "format": "html",
19 | "title": "Invitation Design",
20 | "description": "Design the invitation in full technicolor HTML"
21 | },
22 | "favorite": {
23 | "title": "Favorite",
24 | "type": "string",
25 | "enum": [
26 | "undefined",
27 | "null",
28 | "NaN"
29 | ]
30 | },
31 | "shoesizeLeft": {
32 | "title": "Shoe size (left)",
33 | "default": 42,
34 | "type": "number"
35 | },
36 | "shoesizeRight": {
37 | "title": "Shoe size (right)",
38 | "default": 42,
39 | "type": "number"
40 | },
41 | "attributes": {
42 | "type": "object",
43 | "title": "Attributes",
44 | "required": [
45 | "eyecolor"
46 | ],
47 | "properties": {
48 | "eyecolor": {
49 | "type": "string",
50 | "format": "color",
51 | "title": "Eye color",
52 | "default": "pink"
53 | },
54 | "haircolor": {
55 | "type": "string",
56 | "title": "Hair color"
57 | },
58 | "shoulders": {
59 | "type": "object",
60 | "title": "Shoulders",
61 | "properties": {
62 | "left": {
63 | "type": "string",
64 | "title": "Left"
65 | },
66 | "right": {
67 | "type": "string",
68 | "title": "Right"
69 | }
70 | }
71 | }
72 | }
73 | },
74 | "things": {
75 | "type": "array",
76 | "title": "I like...",
77 | "items": {
78 | "type": "string",
79 | "enum": [
80 | "clowns",
81 | "compiling",
82 | "sleeping"
83 | ]
84 | }
85 | },
86 | "dislike": {
87 | "type": "array",
88 | "title": "I dislike...",
89 | "items": {
90 | "type": "string",
91 | "title": "I hate"
92 | }
93 | },
94 | "soul": {
95 | "title": "Terms Of Service",
96 | "description": "I agree to sell my undying soul ",
97 | "type": "boolean",
98 | "default": true
99 | },
100 | "soulserial": {
101 | "title": "Soul Serial No",
102 | "type": "string"
103 | },
104 | "date": {
105 | "title": "Date of party",
106 | "type": "string",
107 | "format": "date"
108 | },
109 | "radio": {
110 | "title": "Radio type",
111 | "type": "string",
112 | "enum": [
113 | "Transistor",
114 | "Tube"
115 | ]
116 | },
117 | "radio2": {
118 | "title": "My Second Radio",
119 | "type": "string",
120 | "enum": [
121 | "Transistor",
122 | "Tube"
123 | ]
124 | },
125 | "radiobuttons": {
126 | "type": "string",
127 | "enum": [
128 | "Select me!",
129 | "No me!"
130 | ]
131 | }
132 | }
133 | },
134 | "form": [
135 | {
136 | "type": "fieldset",
137 | "title": "Stuff",
138 | "items": [
139 | {
140 | "type": "tabs",
141 | "tabs": [
142 | {
143 | "title": "Simple stuff",
144 | "items": [
145 | {
146 | "key": "name",
147 | "placeholder": "Check the console",
148 | "onChange": "log(modelValue)",
149 | "feedback": "{'glyphicon': true, 'glyphicon-ok': hasSuccess(), 'glyphicon-star': !hasSuccess() }"
150 | },
151 | {
152 | "key": "favorite",
153 | "feedback": false
154 | }
155 | ]
156 | },
157 | {
158 | "title": "More stuff",
159 | "items": [
160 | "attributes.eyecolor",
161 | "attributes.haircolor",
162 | {
163 | "key": "attributes.shoulders.left",
164 | "title": "Left shoulder",
165 | "description": "This value is copied to attributes.shoulders.right in the model",
166 | "copyValueTo": ["attributes.shoulders.right"]
167 | },
168 | {
169 | "key": "shoesizeLeft",
170 | "feedback": false,
171 | "copyValueTo":["shoesizeRight"]
172 | },
173 | {
174 | "key": "shoesizeRight"
175 | },
176 | {
177 | "key": "invitation",
178 | "tinymceOptions": {
179 | "toolbar": [
180 | "undo redo| styleselect | bold italic | link image",
181 | "alignleft aligncenter alignright"
182 | ]
183 | }
184 | },
185 | "things",
186 | "dislike"
187 | ]
188 | }
189 | ]
190 | }
191 | ]
192 | },
193 | {
194 | "type": "help",
195 | "helpvalue": " "
196 | },
197 | "soul",
198 | {
199 | "type": "conditional",
200 | "condition": "modelData.soul",
201 | "items": [
202 | {
203 | "key": "soulserial",
204 | "placeholder": "ex. 666"
205 | }
206 | ]
207 | },
208 | {
209 | "key": "date",
210 | "minDate": "2014-06-20"
211 | },
212 | {
213 | "key": "radio",
214 | "type": "radios",
215 | "titleMap": [
216 | {
217 | "value": "Transistor",
218 | "name": "Transistor Not the tube kind."
219 | },
220 | {
221 | "value": "Tube",
222 | "name": "Tube The tube kind."
223 | }
224 | ]
225 | },
226 | {
227 | "key": "radio2",
228 | "type": "radios-inline",
229 | "titleMap": [
230 | {
231 | "value": "Transistor",
232 | "name": "Transistor Not the tube kind."
233 | },
234 | {
235 | "value": "Tube",
236 | "name": "Tube The tube kind."
237 | }
238 | ]
239 | },
240 | {
241 | "key": "radiobuttons",
242 | "style": {
243 | "selected": "btn-success",
244 | "unselected": "btn-default"
245 | },
246 | "type": "radiobuttons",
247 | "notitle": true
248 | },
249 | {
250 | "type": "actions",
251 | "items": [
252 | {
253 | "type": "submit",
254 | "style": "btn-info",
255 | "title": "Do It!"
256 | },
257 | {
258 | "type": "button",
259 | "style": "btn-danger",
260 | "title": "Noooooooooooo",
261 | "onClick": "sayNo()"
262 | }
263 | ]
264 | }
265 | ]
266 | }
267 |
--------------------------------------------------------------------------------
/examples/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Bootstrap Schema Form example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
94 |
95 |
96 |
97 |
98 |
99 |
102 |
103 |
104 |
140 |
141 |
142 |
143 |
144 |
Schema Form Example
145 |
146 |
147 |
The Generated Form
148 |
149 |
150 |
158 |
Form is valid
159 |
Form is not valid
160 |
161 |
Model
162 |
{{pretty()}}
163 |
164 |
165 |
Select Example
166 |
176 |
Form
177 |
179 |
Schema
180 |
182 |
183 |
184 |
191 |
192 |
193 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
392 |
393 |
394 |
--------------------------------------------------------------------------------
/dist/angular-schema-form-bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * angular-schema-form-bootstrap
3 | * @version 1.0.0-alpha.5
4 | * @date Sat, 29 Apr 2017 14:49:38 GMT
5 | * @link https://github.com/json-schema-form/angular-schema-form-bootstrap
6 | * @license MIT
7 | * Copyright (c) 2014-2017 JSON Schema Form
8 | */
9 | !function(r){function e(a){if(n[a])return n[a].exports;var l=n[a]={i:a,l:!1,exports:{}};return r[a].call(l.exports,l,l.exports,e),l.l=!0,l.exports}var n={};return e.m=r,e.c=n,e.i=function(r){return r},e.d=function(r,e,n){Object.defineProperty(r,e,{configurable:!1,enumerable:!0,get:n})},e.n=function(r){var n=r&&r.__esModule?function(){return r.default}:function(){return r};return e.d(n,"a",n),n},e.o=function(r,e){return Object.prototype.hasOwnProperty.call(r,e)},e.p="",e(e.s=24)}([function(r,e,n){n(18)},,function(r,e){var n="/bootstrap/actions.html",a='\r\n \r\n {{item.title}} \r\n
\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/array.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/checkbox.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/checkboxes.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/default.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/fieldset.html",a='\r\n {{ form.title }} \r\n
\r\n \r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/help.html",a='
\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/radio-buttons.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/radios-inline.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/radios.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/section.html",a='
\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/select.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/submit.html",a='\r\n \r\n \r\n \r\n {{form.title}}\r\n \r\n
\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/tabarray.html",a='\r\n\r\n \r\n\r\n\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/tabs.html",a='\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e){var n="/bootstrap/textarea.html",a='\r\n
{{form.title}} \r\n\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n
\r\n\r\n
\r\n
\r\n';window.angular.module("ng").run(["$templateCache",function(r){r.put(n,a)}]),r.exports=n},function(r,e,n){"use strict";function a(r,e,n,a,l){var s=n.builders.simpleTransclusion,i=n.builders.ngModelOptions,m=n.builders.ngModel,c=n.builders.sfField,p=n.builders.condition,h=n.builders.array,v=n.builders.numeric,$=function(r){if(r.form.tabs&&r.form.tabs.length>0){var e=r.fieldFrag.querySelector(".tab-content");r.form.tabs.forEach(function(n,a){var l="(evalExpr("+r.path+".tabs["+a+'].condition, { model: model, "arrayIndex": $index}))',t=document.createElement("div");t.className="tab-pane",t.setAttribute("ng-disabled","form.readonly"),t.setAttribute("ng-show","selected.tab === "+a),t.setAttribute("ng-class","{active: selected.tab === "+a+"}"),n.condition&&t.setAttribute("ng-if",l);var s=r.build(n.items,r.path+".tabs["+a+"].items",r.state);t.appendChild(s),e.appendChild(t)})}},C=function(r){if(r.form.placeholder){var e=r.fieldFrag.querySelector("select"),n=document.createElement("option");n.setAttribute("value",""),n.setAttribute("sf-field-model","replaceAll"),1===angular.version.major&&angular.version.minor<4?n.setAttribute("ng-if","$$value$$ === undefined"):n.setAttribute("ng-show","$$value$$ === undefined"),n.textContent=r.form.placeholder,e.appendChild(n)}},w=[c,m,i,p];e.defineDecorator("bootstrapDecorator",{actions:{template:t.a,builder:w},array:{template:o.a,builder:[c,i,m,h,p]},button:{template:H.a,builder:w},checkbox:{template:d.a,builder:w},checkboxes:{template:f.a,builder:[c,i,m,h,p]},conditional:{template:A.a,builder:[c,s,p]},default:{template:u.a,builder:w},fieldset:{template:b.a,builder:[c,s,p]},help:{template:g.a,builder:w},number:{template:u.a,builder:w.concat(v)},password:{template:u.a,builder:w},radios:{template:x.a,builder:w},"radios-inline":{template:k.a,builder:w},radiobuttons:{template:y.a,builder:w},section:{template:A.a,builder:[c,s,p]},select:{template:E.a,builder:[C].concat(w)},submit:{template:H.a,builder:w},tabarray:{template:q.a,builder:[c,i,m,h,p]},tabs:{template:R.a,builder:[c,i,$,p]},textarea:{template:j.a,builder:w}},[])}var l=n(2),t=n.n(l),s=n(3),o=n.n(s),i=n(4),d=n.n(i),m=n(5),f=n.n(m),c=n(6),u=n.n(c),p=n(7),b=n.n(p),h=n(8),g=n.n(h),v=n(9),y=n.n(v),$=n(11),x=n.n($),C=n(10),k=n.n(C),w=n(12),A=n.n(w),S=n(13),E=n.n(S),I=n(14),H=n.n(I),T=n(15),q=n.n(T),M=n(16),R=n.n(M),L=n(17),j=n.n(L);angular.module("schemaForm").config(a),a.$inject=["schemaFormProvider","schemaFormDecoratorsProvider","sfBuilderProvider","sfPathProvider","$injector"]},,,,,,function(r,e,n){r.exports=n(0)}]);
--------------------------------------------------------------------------------
/dist/angular-schema-form-bootstrap.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * angular-schema-form-bootstrap
3 | * @version 1.0.0-alpha.5
4 | * @date Sat, 29 Apr 2017 14:49:38 GMT
5 | * @link https://github.com/json-schema-form/angular-schema-form-bootstrap
6 | * @license MIT
7 | * Copyright (c) 2014-2017 JSON Schema Form
8 | */
9 | /******/ (function(modules) { // webpackBootstrap
10 | /******/ // The module cache
11 | /******/ var installedModules = {};
12 |
13 | /******/ // The require function
14 | /******/ function __webpack_require__(moduleId) {
15 |
16 | /******/ // Check if module is in cache
17 | /******/ if(installedModules[moduleId])
18 | /******/ return installedModules[moduleId].exports;
19 |
20 | /******/ // Create a new module (and put it into the cache)
21 | /******/ var module = installedModules[moduleId] = {
22 | /******/ i: moduleId,
23 | /******/ l: false,
24 | /******/ exports: {}
25 | /******/ };
26 |
27 | /******/ // Execute the module function
28 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
29 |
30 | /******/ // Flag the module as loaded
31 | /******/ module.l = true;
32 |
33 | /******/ // Return the exports of the module
34 | /******/ return module.exports;
35 | /******/ }
36 |
37 |
38 | /******/ // expose the modules object (__webpack_modules__)
39 | /******/ __webpack_require__.m = modules;
40 |
41 | /******/ // expose the module cache
42 | /******/ __webpack_require__.c = installedModules;
43 |
44 | /******/ // identity function for calling harmory imports with the correct context
45 | /******/ __webpack_require__.i = function(value) { return value; };
46 |
47 | /******/ // define getter function for harmory exports
48 | /******/ __webpack_require__.d = function(exports, name, getter) {
49 | /******/ Object.defineProperty(exports, name, {
50 | /******/ configurable: false,
51 | /******/ enumerable: true,
52 | /******/ get: getter
53 | /******/ });
54 | /******/ };
55 |
56 | /******/ // getDefaultExport function for compatibility with non-harmony modules
57 | /******/ __webpack_require__.n = function(module) {
58 | /******/ var getter = module && module.__esModule ?
59 | /******/ function getDefault() { return module['default']; } :
60 | /******/ function getModuleExports() { return module; };
61 | /******/ __webpack_require__.d(getter, 'a', getter);
62 | /******/ return getter;
63 | /******/ };
64 |
65 | /******/ // Object.prototype.hasOwnProperty.call
66 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
67 |
68 | /******/ // __webpack_public_path__
69 | /******/ __webpack_require__.p = "";
70 |
71 | /******/ // Load entry module and return exports
72 | /******/ return __webpack_require__(__webpack_require__.s = 21);
73 | /******/ })
74 | /************************************************************************/
75 | /******/ ([
76 | /* 0 */
77 | /***/ function(module, exports, __webpack_require__) {
78 |
79 | __webpack_require__(18);
80 |
81 |
82 | /***/ },
83 | /* 1 */,
84 | /* 2 */
85 | /***/ function(module, exports) {
86 |
87 | var path = '/bootstrap/actions.html';
88 | var html = "\r\n \r\n {{item.title}} \r\n
\r\n";
89 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
90 | module.exports = path;
91 |
92 | /***/ },
93 | /* 3 */
94 | /***/ function(module, exports) {
95 |
96 | var path = '/bootstrap/array.html';
97 | var html = "\r\n";
98 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
99 | module.exports = path;
100 |
101 | /***/ },
102 | /* 4 */
103 | /***/ function(module, exports) {
104 |
105 | var path = '/bootstrap/checkbox.html';
106 | var html = "\r\n
\r\n \r\n \r\n \r\n
\r\n
\r\n";
107 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
108 | module.exports = path;
109 |
110 | /***/ },
111 | /* 5 */
112 | /***/ function(module, exports) {
113 |
114 | var path = '/bootstrap/checkboxes.html';
115 | var html = "\r\n";
116 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
117 | module.exports = path;
118 |
119 | /***/ },
120 | /* 6 */
121 | /***/ function(module, exports) {
122 |
123 | var path = '/bootstrap/default.html';
124 | var html = "\r\n";
125 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
126 | module.exports = path;
127 |
128 | /***/ },
129 | /* 7 */
130 | /***/ function(module, exports) {
131 |
132 | var path = '/bootstrap/fieldset.html';
133 | var html = "\r\n {{ form.title }} \r\n
\r\n \r\n";
134 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
135 | module.exports = path;
136 |
137 | /***/ },
138 | /* 8 */
139 | /***/ function(module, exports) {
140 |
141 | var path = '/bootstrap/help.html';
142 | var html = "
\r\n";
143 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
144 | module.exports = path;
145 |
146 | /***/ },
147 | /* 9 */
148 | /***/ function(module, exports) {
149 |
150 | var path = '/bootstrap/radio-buttons.html';
151 | var html = "\r\n";
152 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
153 | module.exports = path;
154 |
155 | /***/ },
156 | /* 10 */
157 | /***/ function(module, exports) {
158 |
159 | var path = '/bootstrap/radios-inline.html';
160 | var html = "\r\n";
161 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
162 | module.exports = path;
163 |
164 | /***/ },
165 | /* 11 */
166 | /***/ function(module, exports) {
167 |
168 | var path = '/bootstrap/radios.html';
169 | var html = "\r\n";
170 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
171 | module.exports = path;
172 |
173 | /***/ },
174 | /* 12 */
175 | /***/ function(module, exports) {
176 |
177 | var path = '/bootstrap/section.html';
178 | var html = "
\r\n";
179 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
180 | module.exports = path;
181 |
182 | /***/ },
183 | /* 13 */
184 | /***/ function(module, exports) {
185 |
186 | var path = '/bootstrap/select.html';
187 | var html = "\r\n";
188 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
189 | module.exports = path;
190 |
191 | /***/ },
192 | /* 14 */
193 | /***/ function(module, exports) {
194 |
195 | var path = '/bootstrap/submit.html';
196 | var html = "\r\n \r\n \r\n \r\n {{form.title}}\r\n \r\n
\r\n";
197 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
198 | module.exports = path;
199 |
200 | /***/ },
201 | /* 15 */
202 | /***/ function(module, exports) {
203 |
204 | var path = '/bootstrap/tabarray.html';
205 | var html = "\r\n
\r\n\r\n
\r\n
\r\n
\r\n\r\n
\r\n\r\n
= modelArray.length\"\r\n type=\"button\"\r\n class=\"btn {{ form.style.remove || 'btn-default' }} pull-right\">\r\n \r\n {{ form.remove || 'Remove'}}\r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n\r\n \r\n\r\n\r\n";
206 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
207 | module.exports = path;
208 |
209 | /***/ },
210 | /* 16 */
211 | /***/ function(module, exports) {
212 |
213 | var path = '/bootstrap/tabs.html';
214 | var html = "\r\n";
215 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
216 | module.exports = path;
217 |
218 | /***/ },
219 | /* 17 */
220 | /***/ function(module, exports) {
221 |
222 | var path = '/bootstrap/textarea.html';
223 | var html = "\r\n";
224 | window.angular.module('ng').run(['$templateCache', function(c) { c.put(path, html) }]);
225 | module.exports = path;
226 |
227 | /***/ },
228 | /* 18 */
229 | /***/ function(module, exports, __webpack_require__) {
230 |
231 | "use strict";
232 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__bootstrap_actions_html__ = __webpack_require__(2);
233 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__bootstrap_actions_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__bootstrap_actions_html__);
234 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__bootstrap_array_html__ = __webpack_require__(3);
235 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__bootstrap_array_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__bootstrap_array_html__);
236 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__bootstrap_checkbox_html__ = __webpack_require__(4);
237 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__bootstrap_checkbox_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__bootstrap_checkbox_html__);
238 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__bootstrap_checkboxes_html__ = __webpack_require__(5);
239 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__bootstrap_checkboxes_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3__bootstrap_checkboxes_html__);
240 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html__ = __webpack_require__(6);
241 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html__);
242 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__bootstrap_fieldset_html__ = __webpack_require__(7);
243 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__bootstrap_fieldset_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5__bootstrap_fieldset_html__);
244 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__bootstrap_help_html__ = __webpack_require__(8);
245 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__bootstrap_help_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6__bootstrap_help_html__);
246 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__bootstrap_radio_buttons_html__ = __webpack_require__(9);
247 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__bootstrap_radio_buttons_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_7__bootstrap_radio_buttons_html__);
248 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__bootstrap_radios_html__ = __webpack_require__(11);
249 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__bootstrap_radios_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_8__bootstrap_radios_html__);
250 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__bootstrap_radios_inline_html__ = __webpack_require__(10);
251 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__bootstrap_radios_inline_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_9__bootstrap_radios_inline_html__);
252 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__bootstrap_section_html__ = __webpack_require__(12);
253 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__bootstrap_section_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_10__bootstrap_section_html__);
254 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__bootstrap_select_html__ = __webpack_require__(13);
255 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__bootstrap_select_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_11__bootstrap_select_html__);
256 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__bootstrap_submit_html__ = __webpack_require__(14);
257 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__bootstrap_submit_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_12__bootstrap_submit_html__);
258 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__bootstrap_tabarray_html__ = __webpack_require__(15);
259 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__bootstrap_tabarray_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_13__bootstrap_tabarray_html__);
260 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__bootstrap_tabs_html__ = __webpack_require__(16);
261 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__bootstrap_tabs_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_14__bootstrap_tabs_html__);
262 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__bootstrap_textarea_html__ = __webpack_require__(17);
263 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__bootstrap_textarea_html___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_15__bootstrap_textarea_html__);
264 | // ngtemplate-loader embeds the html on build
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 | angular
283 | .module('schemaForm')
284 | .config(bootstrapDecoratorConfig);
285 |
286 | bootstrapDecoratorConfig.$inject = [
287 | 'schemaFormProvider', 'schemaFormDecoratorsProvider', 'sfBuilderProvider', 'sfPathProvider', '$injector'
288 | ];
289 |
290 | function bootstrapDecoratorConfig(
291 | schemaFormProvider, decoratorsProvider, sfBuilderProvider, sfPathProvider, $injector) {
292 | var base = 'decorators/bootstrap/';
293 |
294 | var simpleTransclusion = sfBuilderProvider.builders.simpleTransclusion;
295 | var ngModelOptions = sfBuilderProvider.builders.ngModelOptions;
296 | var ngModel = sfBuilderProvider.builders.ngModel;
297 | var sfField = sfBuilderProvider.builders.sfField;
298 | var condition = sfBuilderProvider.builders.condition;
299 | var array = sfBuilderProvider.builders.array;
300 | var numeric = sfBuilderProvider.builders.numeric;
301 |
302 | // Tabs is so bootstrap specific that it stays here.
303 | var tabs = function(args) {
304 | if (args.form.tabs && args.form.tabs.length > 0) {
305 | var tabContent = args.fieldFrag.querySelector('.tab-content');
306 |
307 | args.form.tabs.forEach(function(tab, index) {
308 | var evalExpr = '(evalExpr(' + args.path + '.tabs[' + index + ']' +
309 | '.condition, { model: model, "arrayIndex": $index}))';
310 | var div = document.createElement('div');
311 | div.className = 'tab-pane';
312 | div.setAttribute('ng-disabled', 'form.readonly');
313 | div.setAttribute('ng-show', 'selected.tab === ' + index);
314 | div.setAttribute('ng-class', '{active: selected.tab === ' + index + '}');
315 | if(!!tab.condition) {
316 | div.setAttribute('ng-if', evalExpr);
317 | };
318 |
319 | var childFrag = args.build(tab.items, args.path + '.tabs[' + index + '].items', args.state);
320 | div.appendChild(childFrag);
321 | tabContent.appendChild(div);
322 | });
323 | }
324 | };
325 |
326 | var selectPlaceholder = function(args) {
327 | if (args.form.placeholder) {
328 | var selectBox = args.fieldFrag.querySelector('select');
329 | var option = document.createElement('option');
330 | option.setAttribute('value', '');
331 |
332 | /* We only want the placeholder to show when we do not have a value on the model.
333 | * We make ngModel builder replace all so we can use $$value$$.
334 | */
335 | option.setAttribute('sf-field-model', 'replaceAll');
336 |
337 | /* https://github.com/angular/angular.js/issues/12190#issuecomment-115277040
338 | * angular > 1.4 does a emptyOption.attr('selected', true)
339 | * which does not like the ng-if comment.
340 | */
341 | if (angular.version.major === 1 && angular.version.minor < 4) {
342 | option.setAttribute('ng-if', '$$value$$ === undefined');
343 | } else {
344 | option.setAttribute('ng-show', '$$value$$ === undefined');
345 | }
346 |
347 | option.textContent = args.form.placeholder;
348 |
349 | selectBox.appendChild(option);
350 | }
351 | };
352 |
353 | var defaults = [sfField, ngModel, ngModelOptions, condition];
354 | decoratorsProvider.defineDecorator('bootstrapDecorator', {
355 | actions: {template: __WEBPACK_IMPORTED_MODULE_0__bootstrap_actions_html___default.a, builder: defaults},
356 | array: {template: __WEBPACK_IMPORTED_MODULE_1__bootstrap_array_html___default.a, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
357 | button: {template: __WEBPACK_IMPORTED_MODULE_12__bootstrap_submit_html___default.a, builder: defaults},
358 | checkbox: {template: __WEBPACK_IMPORTED_MODULE_2__bootstrap_checkbox_html___default.a, builder: defaults},
359 | checkboxes: {template: __WEBPACK_IMPORTED_MODULE_3__bootstrap_checkboxes_html___default.a, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
360 | conditional: {template: __WEBPACK_IMPORTED_MODULE_10__bootstrap_section_html___default.a, builder: [ sfField, simpleTransclusion, condition ]},
361 | 'default': {template: __WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html___default.a, builder: defaults},
362 | fieldset: {template: __WEBPACK_IMPORTED_MODULE_5__bootstrap_fieldset_html___default.a, builder: [ sfField, simpleTransclusion, condition ]},
363 | help: {template: __WEBPACK_IMPORTED_MODULE_6__bootstrap_help_html___default.a, builder: defaults},
364 | number: {template: __WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html___default.a, builder: defaults.concat(numeric)},
365 | password: {template: __WEBPACK_IMPORTED_MODULE_4__bootstrap_default_html___default.a, builder: defaults},
366 | radios: {template: __WEBPACK_IMPORTED_MODULE_8__bootstrap_radios_html___default.a, builder: defaults},
367 | 'radios-inline': {template: __WEBPACK_IMPORTED_MODULE_9__bootstrap_radios_inline_html___default.a, builder: defaults},
368 | radiobuttons: {template: __WEBPACK_IMPORTED_MODULE_7__bootstrap_radio_buttons_html___default.a, builder: defaults},
369 | section: {template: __WEBPACK_IMPORTED_MODULE_10__bootstrap_section_html___default.a, builder: [ sfField, simpleTransclusion, condition ]},
370 | select: {template: __WEBPACK_IMPORTED_MODULE_11__bootstrap_select_html___default.a, builder: [ selectPlaceholder ].concat(defaults)},
371 | submit: {template: __WEBPACK_IMPORTED_MODULE_12__bootstrap_submit_html___default.a, builder: defaults},
372 | tabarray: {template: __WEBPACK_IMPORTED_MODULE_13__bootstrap_tabarray_html___default.a, builder: [ sfField, ngModelOptions, ngModel, array, condition ]},
373 | tabs: {template: __WEBPACK_IMPORTED_MODULE_14__bootstrap_tabs_html___default.a, builder: [ sfField, ngModelOptions, tabs, condition ]},
374 | textarea: {template: __WEBPACK_IMPORTED_MODULE_15__bootstrap_textarea_html___default.a, builder: defaults},
375 | }, []);
376 | };
377 |
378 |
379 | /***/ },
380 | /* 19 */,
381 | /* 20 */,
382 | /* 21 */
383 | /***/ function(module, exports, __webpack_require__) {
384 |
385 | module.exports = __webpack_require__(0);
386 |
387 |
388 | /***/ }
389 | /******/ ]);
--------------------------------------------------------------------------------