Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 06fd6a8

Browse files
Merge pull request #19 from joelwkent/develop
Tab array: sortable tabs, hide add and remove
2 parents 0a40f4b + 2308fe5 commit 06fd6a8

File tree

8 files changed

+265
-11
lines changed

8 files changed

+265
-11
lines changed

‎examples/bootstrap-example.html

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,9 @@ <h3>Schema</h3>
214214
<!-- <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular-sanitize.min.js"></script> -->
215215

216216

217-
<!--
218-
<script type="text/javascript" src="../bower_components/angular-ui-sortable/sortable.js"></script>
219-
-->
217+
<scripttype="text/javascript" src="../bower_components/angular-ui-sortable/sortable.min.js"></script>
218+
<script type="text/javascript" src="../bower_components/jquery-ui/jquery-ui.min.js"></script>
219+
220220
<script type="text/javascript" src="../bower_components/angular-ui-ace/ui-ace.js"></script>
221221
<script type="text/javascript" src="../bower_components/objectpath/lib/ObjectPath.js"></script>
222222
<script type="text/javascript" src="../bower_components/pickadate/lib/picker.js"></script>
@@ -254,6 +254,9 @@ <h3>Schema</h3>
254254
{ name: "TitleMap Examples", data: 'data/titlemaps.json' },
255255
{ name: "Kitchen Sink", data: 'data/sink.json' },
256256
{ name: "Hack: Conditional required", data: 'data/conditional-required.json' },
257+
{ name: "Tab Array: Add Disabled", data: 'data/tabarray-add-disabled.json' },
258+
{ name: "Tab Array: Remove Disabled", data: 'data/tabarray-remove-disabled.json' },
259+
{ name: "Tab Array: Sortable (Drag and Drop)", data: 'data/tabarray-sortable.json' }
257260
];
258261

259262
$scope.navbarMode = 'default';
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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": "<h4>Tab array with add link hidden</h4>"
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+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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": "<h4>Tab array with remove button hidden</h4>"
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+
}

‎examples/data/tabarray-sortable.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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": "<h4>Drag and drop sortable tab array</h4>"
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+
}

‎gulp/tasks/protractor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ gulp.task('protractor', ['webdriver-update'], function(cb) {
2727
}).on('end', cb);
2828
});
2929

30-
['validation-messages', 'custom-validation'].forEach(function(name) {
30+
['validation-messages', 'custom-validation','tabarray'].forEach(function(name) {
3131
gulp.task('protractor:' + name, ['webdriver-update'], function(cb) {
3232
gulp.src(['test/protractor/specs/' + name + '.js']).pipe(protractor.protractor({
3333
configFile: 'test/protractor/conf.js',

‎src/bootstrap-decorator.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ function(decoratorsProvider, sfBuilderProvider, sfPathProvider) {
2727
});
2828
}
2929
};
30+
31+
// Set tabArray sortOptions.items default.
32+
var tabArray = function(args) {
33+
if(args.form.hasOwnProperty('sortOptions')) {
34+
if(!args.form.sortOptions.hasOwnProperty('items')) {
35+
args.form.sortOptions['items'] = 'li:not(:last-child)';
36+
}
37+
} else {
38+
args.form['sortOptions'] = {items: 'li:not(:last-child)'};
39+
}
40+
}
3041

3142
var selectPlaceholder = function(args) {
3243
if (args.form.placeholder) {
@@ -60,7 +71,7 @@ function(decoratorsProvider, sfBuilderProvider, sfPathProvider) {
6071
textarea: {template: base + 'textarea.html', builder: defaults},
6172
fieldset: {template: base + 'fieldset.html', builder: [sfField, simpleTransclusion, condition]},
6273
array: {template: base + 'array.html', builder: [sfField, ngModelOptions, ngModel, array, condition]},
63-
tabarray: {template: base + 'tabarray.html', builder: [sfField, ngModelOptions, ngModel, array, condition]},
74+
tabarray: {template: base + 'tabarray.html', builder: [sfField, ngModelOptions, ngModel, array, condition,tabArray]},
6475
tabs: {template: base + 'tabs.html', builder: [sfField, ngModelOptions, tabs, condition]},
6576
section: {template: base + 'section.html', builder: [sfField, simpleTransclusion, condition]},
6677
conditional: {template: base + 'section.html', builder: [sfField, simpleTransclusion, condition]},

‎src/tabarray.html

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,24 @@
66
class="clearfix schema-form-tabarray schema-form-tabarray-{{form.tabType || 'left'}} {{form.htmlClass}}">
77
<div ng-if="!form.tabType || form.tabType !== 'right'"
88
ng-class="{'col-xs-3': !form.tabType || form.tabType === 'left'}">
9-
<ul class="nav nav-tabs"
10-
ng-class="{ 'tabs-left': !form.tabType || form.tabType === 'left'}">
9+
<ol class="nav nav-tabs"
10+
ng-class="{ 'tabs-left': !form.tabType || form.tabType === 'left'}"
11+
sf-field-model ui-sortable="form.sortOptions">
1112
<li sf-field-model="ng-repeat"
1213
ng-repeat="item in $$value$$ track by $index"
1314
ng-click="$event.preventDefault() || (selected.tab = $index)"
1415
ng-class="{active: selected.tab === $index}">
1516
<a href="#">{{interp(form.title,{'$index':$index, value: item}) || $index}}</a>
1617
</li>
17-
<li ng-hide="form.readonly"
18+
<li ng-hide="form.readonly || form.add === null"
1819
ng-disabled="form.schema.maxItems <= modelArray.length"
1920
ng-click="$event.preventDefault() || (selected.tab = appendToArray().length - 1)">
2021
<a href="#">
2122
<i class="glyphicon glyphicon-plus"></i>
2223
{{ form.add || 'Add'}}
2324
</a>
2425
</li>
25-
</ul>
26+
</ol>
2627
</div>
2728

2829
<div ng-class="{'col-xs-9': !form.tabType || form.tabType === 'left' || form.tabType === 'right'}">
@@ -35,7 +36,7 @@
3536

3637
<div schema-form-array-items></div>
3738

38-
<button ng-hide="form.readonly"
39+
<button ng-hide="form.readonly || form.remove === null"
3940
ng-click="selected.tab = deleteFromArray($index).length - 1"
4041
ng-disabled="form.schema.minItems >= modelArray.length"
4142
type="button"
@@ -59,7 +60,7 @@
5960
ng-class="{active: selected.tab === $index}">
6061
<a href="#">{{interp(form.title,{'$index':$index, value: item}) || $index}}</a>
6162
</li>
62-
<li ng-hide="form.readonly"
63+
<li ng-hide="form.readonly || form.add === null"
6364
ng-disabled="form.schema.maxItems <= modelArray.length"
6465
ng-click="$event.preventDefault() || (selected.tab = appendToArray().length - 1)">
6566
<a href="#">

‎test/protractor/specs/tabarray.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /