diff --git a/docs/demos/dev-uiselect/controller.js b/docs/demos/dev-uiselect/controller.js index 6411b8c9..b4287581 100644 --- a/docs/demos/dev-uiselect/controller.js +++ b/docs/demos/dev-uiselect/controller.js @@ -1,8 +1,11 @@ app.controller('DevUiSelectCtrl', function($scope) { $scope.user = { state: 'Arizona', - state2: 'Kansas' + state2: 'Kansas', + tag: [] }; $scope.states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming']; + + $scope.tags = ['JavaScript', 'Angular', 'TypeScript']; }); \ No newline at end of file diff --git a/docs/demos/dev-uiselect/test.js b/docs/demos/dev-uiselect/test.js index 2e732045..1cf25786 100644 --- a/docs/demos/dev-uiselect/test.js +++ b/docs/demos/dev-uiselect/test.js @@ -9,19 +9,19 @@ describe('uiselect', function() { //edit button initially shown, form initially hidden expect(element(s+'div#state:visible').count()).toBe(1); - expect(element(s+'.buttons > button:visible').count()).toBe(1); + expect(element(s+'.buttons > button:visible').count()).toBe(2); expect(element(s+'.buttons > span:visible').count()).toBe(0); //show form - element(s+'form > div > button').click(); + element(s+'form[name=uiSelectForm] > div > button').click(); //second click to test that controls not duplicated! - element(s+'form > div > button').click(); + element(s+'form[name=uiSelectForm] > div > button').click(); //also click outside to check blur = ignore element('body').click(); //form shown in disabled state (loading) - expect(element(s+'div#name:visible').count()).toBe(0); - expect(element(s+'.buttons > button:visible').count()).toBe(0); + expect(element(s+'div#state:visible').count()).toBe(0); + expect(element(s+'.buttons > button:visible').count()).toBe(1); sleep(delay); @@ -30,15 +30,15 @@ describe('uiselect', function() { //form enabled when data loaded expect(element(s+'div#state:visible').count()).toBe(0); - expect(element(s+'.buttons > button:visible').count()).toBe(0); - expect(element(s+'.buttons > span button:enabled').count()).toBe(2); + expect(element(s+'.buttons > button:visible').count()).toBe(1); + expect(element(s+'.buttons > span button:enabled').count()).toBe(4); //click cancel - element(s+'form > div > span button[type="button"]').click(); + element(s+'form[name=uiSelectForm] > div > span button[type="button"]').click(); //form closed expect(element(s+'div#state:visible').count()).toBe(1); - expect(element(s+'.buttons > button:visible').count()).toBe(1); + expect(element(s+'.buttons > button:visible').count()).toBe(2); expect(element(s+'.buttons > span:visible').count()).toBe(0); }); @@ -46,7 +46,7 @@ describe('uiselect', function() { var s = '[ng-controller="DevUiSelectCtrl"] '; //show form - element(s+'form > div > button').click(); + element(s+'form[name=uiSelectForm] > div > button').click(); sleep(delay); @@ -61,12 +61,12 @@ describe('uiselect', function() { element(s+'#ui-select-choices-row-1-').click(); //click submit - element(s+'span button[type="submit"]').click(); + element(s+'span button[name="submitState"]').click(); //second click to check that it works correctly - element(s+'span button[type="submit"]').click(); + element(s+'span button[name="submitState"]').click(); //saving - expect(element(s+'form > div:eq(0) .editable-error:visible').count()).toBe(0); + expect(element(s+'form[name=uiSelectForm] > div:eq(0) .editable-error:visible').count()).toBe(0); sleep(delay); @@ -75,8 +75,98 @@ describe('uiselect', function() { expect(element(s+'div#state:visible').text()).toMatch('Illinois'); expect(element(s+'div#state2:visible').count()).toBe(1); expect(element(s+'div#state2:visible').text()).toMatch('Arizona'); + expect(element(s+'.buttons > button:visible').count()).toBe(2); + expect(element(s+'.buttons > span:visible').count()).toBe(0); + }); + + + it('should show form by `edit` button click and close by `cancel` for tag select', function() { + var s = '[ng-controller="DevUiSelectCtrl"] '; + + //edit button initially shown, form initially hidden + expect(element(s+'div#tag:visible').count()).toBe(1); + expect(element(s+'.buttons > button:visible').count()).toBe(2); + expect(element(s+'.buttons > span:visible').count()).toBe(0); + + //show form + element(s+'form[name=uiTagsform] > div > button').click(); + //second click to test that controls not duplicated! + element(s+'form[name=uiTagsform] > div > button').click(); + //also click outside to check blur = ignore + element('body').click(); + + //form shown in disabled state (loading) + expect(element(s+'div#tag:visible').count()).toBe(0); + expect(element(s+'.buttons > button:visible').count()).toBe(1); + + sleep(delay); + + //also click outside to check blur = ignore + element('body').click(); + + //form enabled when data loaded + expect(element(s+'div#tag:visible').count()).toBe(0); expect(element(s+'.buttons > button:visible').count()).toBe(1); + expect(element(s+'.buttons > span button:enabled').count()).toBe(4); + + //click cancel + element(s+'form[name=uiTagsform] > div > span button[type="button"]').click(); + + //form closed + expect(element(s+'div#tag:visible').count()).toBe(1); + expect(element(s+'.buttons > button:visible').count()).toBe(2); expect(element(s+'.buttons > span:visible').count()).toBe(0); }); + it('should show form and save new values for tag select', function() { + var s = '[ng-controller="DevUiSelectCtrl"] '; + + //show form + element(s+'form[name=uiSelectForm] > div > button').click(); + element(s+'form[name=uiTagsform] > div > button').click(); + + sleep(delay); + + //select a value for the first dropdown + element(s+'div[name=state] > div > span').click(); + input('$select.search').enter('Illinois'); + element(s+'#ui-select-choices-row-0-').click(); + + //select a value for the second dropdown + element(s+'div[name=state2] > div > span').click(); + input('$select.search').enter('Arizona'); + element(s+'#ui-select-choices-row-1-').click(); + + //select a value for the tag dropdown + element(s+'div[name=tag] > div > span').click(); + input('$select.search').enter('Angular'); + element(s+'#ui-select-choices-row-2-').click(); + + //click submit for state form + element(s+'span button[name="submitState"]').click(); + //second click to check that it works correctly + element(s+'span button[name="submitState"]').click(); + + + //click submit for tag form + element(s+'span button[name="submitTag"]').click(); + //second click to check that it works correctly + element(s+'span button[name="submitTag"]').click(); + + //saving + expect(element(s+'form[name=uiTagsform] > div:eq(0) .editable-error:visible').count()).toBe(0); + expect(element(s+'form[name=uiSelectForm] > div:eq(0) .editable-error:visible').count()).toBe(0); + + sleep(delay); + + //form closed, new values shown + expect(element(s+'div#state:visible').count()).toBe(1); + expect(element(s+'div#state:visible').text()).toMatch('Illinois'); + expect(element(s+'div#state2:visible').count()).toBe(1); + expect(element(s+'div#state2:visible').text()).toMatch('Arizona'); + expect(element(s+'div#tag:visible').count()).toBe(1); + expect(element(s+'div#tag:visible').text()).toMatch('Angular'); + expect(element(s+'.buttons > button:visible').count()).toBe(2); + expect(element(s+'.buttons > span:visible').count()).toBe(0); + }); }); \ No newline at end of file diff --git a/docs/demos/dev-uiselect/view.html b/docs/demos/dev-uiselect/view.html index 070ba15d..c4d6e845 100644 --- a/docs/demos/dev-uiselect/view.html +++ b/docs/demos/dev-uiselect/view.html @@ -27,7 +27,7 @@
- + + +
+ + +
+ + \ No newline at end of file diff --git a/docs/demos/editable-form/desc.md b/docs/demos/editable-form/desc.md index 7e7e1d4c..27dd31c9 100644 --- a/docs/demos/editable-form/desc.md +++ b/docs/demos/editable-form/desc.md @@ -49,4 +49,6 @@ The result of form's `onaftersave` is also important for next step: Commonly you should define `onbeforesave` for child elements to perform validation and `onaftersave` for whole form to send data on server. +Note: `e-required` will not work since HTML5 validation only works if submitting a form with a submit button and `editable-form` submits via a script. + Please have a look at examples. \ No newline at end of file diff --git a/docs/demos/editable-popover/controller.js b/docs/demos/editable-popover/controller.js new file mode 100644 index 00000000..d8606bf1 --- /dev/null +++ b/docs/demos/editable-popover/controller.js @@ -0,0 +1,5 @@ +app.controller('EditPopoverCtrl', function($scope) { + $scope.user = { + name: 'awesome user' + }; +}); \ No newline at end of file diff --git a/docs/demos/editable-popover/desc.md b/docs/demos/editable-popover/desc.md new file mode 100644 index 00000000..64c399e2 --- /dev/null +++ b/docs/demos/editable-popover/desc.md @@ -0,0 +1 @@ +To made an editable field display in a popover, wrap the editable in `
`. \ No newline at end of file diff --git a/docs/demos/editable-popover/test.js b/docs/demos/editable-popover/test.js new file mode 100644 index 00000000..43277cbc --- /dev/null +++ b/docs/demos/editable-popover/test.js @@ -0,0 +1,86 @@ +describe('editable-popover', function() { + + beforeEach(function() { + browser().navigateTo(mainUrl); + }); + + + it('should show editor and submit new value', function() { + var s = '[ng-controller="EditPopoverCtrl"] '; + + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toMatch('awesome user'); + element(s+'a').click(); + + expect(element(s+'a').css('display')).toBe('inline'); + expect(element(s+'form[editable-form="$form"]').count()).toBe(1); + expect(element(s+'form input[type="text"]:visible').count()).toBe(1); + expect(element(s+'form input[type="text"]').val()).toBe('awesome user'); + expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); + expect(element(s+'form button[type="button"]:visible').count()).toBe(1); + + using(s).input('$data').enter('username2'); + element(s+'form button[type="submit"]').click(); + + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toBe('username2'); + expect(element(s+'form').count()).toBe(0); + }); + + it('should not save by cancel button', function() { + var s = '[ng-controller="EditPopoverCtrl"] '; + element(s+'a').click(); + + using(s).input('$data').enter('username2'); + element(s+'form button[type="button"]').click(); + + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toMatch('awesome user'); + expect(element(s+'form').count()).toBe(0); + }); + + it('should attach `editable-empty` class', function() { + var s = '[ng-controller="EditPopoverCtrl"] '; + + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toMatch('awesome user'); + expect(element(s+'a').attr('class')).not().toMatch('editable-empty'); + element(s+'a').click(); + + expect(element(s+'a').css('display')).toBe('inline'); + expect(element(s+'form[editable-form="$form"]').count()).toBe(1); + expect(element(s+'form input[type="text"]:visible').count()).toBe(1); + expect(element(s+'form input[type="text"]').val()).toBe('awesome user'); + expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); + expect(element(s+'form button[type="button"]:visible').count()).toBe(1); + + using(s).input('$data').enter(''); + element(s+'form button[type="submit"]').click(); + + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toBe('empty'); + expect(element(s+'a').attr('class')).toMatch('editable-empty'); + expect(element(s+'form').count()).toBe(0); + }); + + it('should cancel by click on body', function() { + var s = '[ng-controller="EditPopoverCtrl"] '; + element(s+'a').click(); + + expect(element(s+'a').css('display')).toBe('inline'); + expect(element(s+'form[editable-form="$form"]').count()).toBe(1); + expect(element(s+'form input[type="text"]:visible').count()).toBe(1); + + // click on input - still visible + element(s+'form input[type="text"]').click(); + expect(element(s+'a').css('display')).toBe('inline'); + expect(element(s+'form[editable-form="$form"]').count()).toBe(1); + expect(element(s+'form input[type="text"]:visible').count()).toBe(1); + + // click on body - close + element('body').click(); + expect(element(s+'a').css('display')).not().toBe('none'); + expect(element(s+'a').text()).toMatch('awesome user'); + expect(element(s+'form').count()).toBe(0); + }); +}); \ No newline at end of file diff --git a/docs/demos/editable-popover/view.html b/docs/demos/editable-popover/view.html new file mode 100644 index 00000000..48b0d1b1 --- /dev/null +++ b/docs/demos/editable-popover/view.html @@ -0,0 +1,5 @@ +
+ +
\ No newline at end of file diff --git a/docs/demos/editable-row/view.html b/docs/demos/editable-row/view.html index d8d1e541..74016434 100644 --- a/docs/demos/editable-row/view.html +++ b/docs/demos/editable-row/view.html @@ -9,7 +9,7 @@ - + {{ user.name || 'empty' }} diff --git a/docs/demos/radiolist/view.html b/docs/demos/radiolist/view.html index 9b04a548..04eef87e 100644 --- a/docs/demos/radiolist/view.html +++ b/docs/demos/radiolist/view.html @@ -1,5 +1,5 @@
- + {{ showStatus() }}
\ No newline at end of file diff --git a/docs/demos/text-simple/test.js b/docs/demos/text-simple/test.js index 61e3f59b..7e8381b6 100644 --- a/docs/demos/text-simple/test.js +++ b/docs/demos/text-simple/test.js @@ -70,7 +70,7 @@ describe('text-simple', function() { expect(element(s+'form[editable-form="$form"]').count()).toBe(1); expect(element(s+'form input[type="text"]:visible').count()).toBe(1); - // click on input - stil visible + // click on input - still visible element(s+'form input[type="text"]').click(); expect(element(s+'a').css('display')).toBe('none'); expect(element(s+'form[editable-form="$form"]').count()).toBe(1); diff --git a/docs/js/structure.js b/docs/js/structure.js index 8c9c74ff..078c69ae 100644 --- a/docs/js/structure.js +++ b/docs/js/structure.js @@ -24,7 +24,8 @@ module.exports = [ {id: 'select-multiple', text: 'Select multiple', fiddle: 'http://jsfiddle.net/NfPcH/30/'}, {id: 'validate-local', text: 'Validate local', fiddle: 'http://jsfiddle.net/NfPcH/35/'}, {id: 'validate-remote', text: 'Validate remote', fiddle: 'http://jsfiddle.net/NfPcH/36/'}, - {id: 'edit-disabled', text: 'Disable editing'} + {id: 'edit-disabled', text: 'Disable editing'}, + {id: 'editable-popover', text: 'Editable Popover'} ]}, {id: 'onbeforesave', text: 'Submit', type: 'demos', items: [ diff --git a/src/css/xeditable.css b/src/css/xeditable.css index 8919a903..ae9d4642 100644 --- a/src/css/xeditable.css +++ b/src/css/xeditable.css @@ -113,4 +113,53 @@ a.editable-empty:focus { text-decoration: none; } +/* editable popover */ +.popover-wrapper a { + /* make the link always show up */ + display: inline !important; +} + +.popover-wrapper { + /* make absolutely positioned children constrained to this box*/ + display: inline; + position: relative; +} + +.popover-wrapper form { + position: absolute; + top: -53px; + background: #FFF; + border: 1px solid #AAA; + border-radius: 5px; + padding: 7px; + width: auto; + display: inline-block; + left: 50%; + margin-left: -110px; + z-index: 101; +} + +.popover-wrapper form:before { + content:""; + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 10px solid #AAA; + position:absolute; + bottom:-10px; + left:100px; +} + +.popover-wrapper form:after { + content:""; + width:0; + height:0; + border-left: 9px solid transparent; + border-right: 9px solid transparent; + border-top: 9px solid #FFF; + position:absolute; + bottom:-9px; + left:101px; +} diff --git a/src/js/directives/radiolist.js b/src/js/directives/radiolist.js index dfa4f20b..764a6946 100644 --- a/src/js/directives/radiolist.js +++ b/src/js/directives/radiolist.js @@ -9,9 +9,10 @@ angular.module('xeditable').directive('editableRadiolist', [ render: function() { this.parent.render.call(this); var parsed = editableNgOptionsParser(this.attrs.eNgOptions); - var html = ''; + + var html = ''; this.inputEl.removeAttr('ng-model'); this.inputEl.removeAttr('ng-options'); diff --git a/test/e2e/dev-test.html b/test/e2e/dev-test.html index 51b04d0c..91d72edc 100644 --- a/test/e2e/dev-test.html +++ b/test/e2e/dev-test.html @@ -33,6 +33,7 @@ + diff --git a/test/e2e/docs-test.html b/test/e2e/docs-test.html index f6edb919..fb4f773b 100644 --- a/test/e2e/docs-test.html +++ b/test/e2e/docs-test.html @@ -34,6 +34,7 @@ +