├── .gitattributes ├── .gitignore ├── CHANGELOG.txt ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── bower.json ├── dist ├── css │ ├── xeditable.css │ └── xeditable.min.css └── js │ ├── xeditable.js │ └── xeditable.min.js ├── docs ├── css │ └── docs.css ├── demos │ ├── bsdate │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── bstime │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── checkbox │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── checklist │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── combodate │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-bsdate │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-checkbox │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-checklist │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-combodate │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-editable-row │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-eform │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-form │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-ngtags │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-radiolist │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-select-multiple │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-select │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-text │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-textarea │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-theme │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── dev-uiselect │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── e-single │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── edit-disabled │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── editable-column │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── editable-form │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── editable-popover │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── editable-row │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── editable-table │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── html5-inputs │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── ngtags │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── onaftersave │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── onbeforesave │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── radiolist │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── select-local │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── select-multiple │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── select-nobuttons │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── select-remote │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── text-btn │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── text-customize │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── text-simple │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── textarea │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── typeahead │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── uidate │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── uipopover │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── uiselect │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ ├── validate-local │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html │ └── validate-remote │ │ ├── controller.js │ │ ├── desc.md │ │ ├── test.js │ │ └── view.html ├── img │ └── angular32.jpeg ├── jade │ ├── getstarted.jade │ ├── main.jade │ ├── metrika.html │ ├── navbar.jade │ ├── overview.jade │ ├── reference.jade │ ├── scripts-dev.jade │ ├── scripts-prod.jade │ ├── social.html │ └── themes.jade └── js │ ├── app.js │ └── structure.js ├── index.html ├── index.js ├── jsdoc.conf.json ├── package-lock.json ├── package.json ├── readme.md ├── src ├── css │ └── xeditable.css └── js │ ├── directives │ ├── bsdate.js │ ├── bstime.js │ ├── checkbox.js │ ├── checklist.js │ ├── combodate.js │ ├── input.js │ ├── ngtags.js │ ├── radiolist.js │ ├── select.js │ ├── textarea.js │ ├── uidate.js │ └── uiselect.js │ ├── editable-element │ ├── controller.js │ └── directive.js │ ├── editable-form │ ├── controller.js │ └── directive.js │ ├── helpers.js │ ├── icons.js │ ├── module.js │ └── themes.js ├── starter ├── angular-xeditable │ ├── css │ │ ├── xeditable.css │ │ └── xeditable.min.css │ └── js │ │ ├── xeditable.js │ │ └── xeditable.min.js ├── app.js └── index.html ├── test └── e2e │ ├── dev-test.html │ ├── docs-test.html │ └── scenarios.js └── zip ├── angular-xeditable-0.1.0.zip ├── angular-xeditable-0.1.1.zip ├── angular-xeditable-0.1.10.zip ├── angular-xeditable-0.1.11.zip ├── angular-xeditable-0.1.12.zip ├── angular-xeditable-0.1.2.zip ├── angular-xeditable-0.1.3.zip ├── angular-xeditable-0.1.4.zip ├── angular-xeditable-0.1.5.zip ├── angular-xeditable-0.1.6.zip ├── angular-xeditable-0.1.7.zip ├── angular-xeditable-0.1.8.1.zip ├── angular-xeditable-0.1.8.zip ├── angular-xeditable-0.1.9.zip ├── angular-xeditable-0.10.0.zip ├── angular-xeditable-0.10.1.zip ├── angular-xeditable-0.10.2.zip ├── angular-xeditable-0.2.0.zip ├── angular-xeditable-0.3.0.zip ├── angular-xeditable-0.4.0.zip ├── angular-xeditable-0.5.0.zip ├── angular-xeditable-0.6.0.zip ├── angular-xeditable-0.7.0.zip ├── angular-xeditable-0.7.1.zip ├── angular-xeditable-0.8.0.zip ├── angular-xeditable-0.8.1.zip ├── angular-xeditable-0.9.0.zip └── angular-xeditable-starter.zip /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /playground 3 | dev.html 4 | jsdoc.json 5 | /.idea 6 | node_modules 7 | .tmp 8 | .sass-cache 9 | bower_components 10 | npm-debug.log -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## jsFiddle / Plunker 2 | Please use these live templates when creating issues: 3 | http://jsfiddle.net/ckosloski/NfPcH/20243/ 4 | http://plnkr.co/edit/OqOveMtnSs1G68SC36wt?p=preview 5 | 6 | ## Contribute 7 | * Don't include files from the `dist`, `starter` and `zip` folders in your pull request. 8 | * Add new tests in `docs/demos` if possible. 9 | * Make sure all existing tests run. 10 | * Squash your commits before creating the pull request. 11 | 12 | ## How to run the tests 13 | * `npm install` in the project 14 | * `npm run build` - to build the project files 15 | * `npm start` - to start the server 16 | * Run the "doc" tests `http://localhost:8000/test/e2e/docs-test.html` 17 | * Run the "dev" tests `http://localhost:8000/test/e2e/dev-test.html` 18 | * Verify the documentation still works correctly by navigating to `http://localhost:8000` 19 | * To view the "dev" documentation, navigate to `http://localhost:8000/dev.html` 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vitaliy Potapov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-xeditable", 3 | "version": "0.10.2", 4 | "description": "Edit in place for AngularJS", 5 | "author": "https://github.com/vitalets", 6 | "license": "MIT", 7 | "homepage": "http://vitalets.github.io/angular-xeditable", 8 | "main": [ 9 | "dist/css/xeditable.css", 10 | "dist/js/xeditable.js" 11 | ], 12 | "ignore": [ 13 | "**/.*", 14 | "node_modules", 15 | "bower_components", 16 | "playground", 17 | "test", 18 | "libs", 19 | "docs", 20 | "zip", 21 | "src", 22 | "starter", 23 | "Gruntfile.js", 24 | "index.html", 25 | "jsdoc.conf.json", 26 | "package.json" 27 | ], 28 | "dependencies": { 29 | "angular": "~1.x" 30 | }, 31 | "devDependencies": { 32 | "angular": "~1.5.0", 33 | "angular-mocks": "~1.5.0", 34 | "angular-scenario": "~1.5.0", 35 | "angular-sanitize": "~1.5.0", 36 | "jquery": "^2.2.4", 37 | "bootstrap": "^3.3.7", 38 | "moment": "^2.17.1", 39 | "checklist-model": "^0.10.0", 40 | "ng-tags-input": "^3.1.1", 41 | "angular-bootstrap": "^2.5.0", 42 | "angular-ui-select": "^0.16.1", 43 | "jquery-ui": "^1.12.1", 44 | "angular-ui-date": "^1.0.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dist/css/xeditable.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | angular-xeditable - 0.10.2 3 | Edit-in-place for angular.js 4 | Build date: 2019-11-01 5 | */ 6 | 7 | .editable-wrap{display:inline-block;white-space:pre;margin:0}.editable-wrap .editable-controls,.editable-wrap .editable-error{margin-bottom:0}.editable-wrap .editable-controls>input,.editable-wrap .editable-controls>select,.editable-wrap .editable-controls>textarea{margin-bottom:0}.editable-wrap .editable-input{display:inline-block}.editable-buttons{display:inline-block;vertical-align:top}.editable-buttons button{margin-left:5px}.editable-input.editable-has-buttons{width:auto}.editable-text{white-space:nowrap}.editable-bsdate{white-space:nowrap}.editable-bstime{white-space:nowrap}.editable-bstime .editable-input input[type=text]{width:46px}.editable-bstime .well-small{margin-bottom:0;padding:10px}.editable-range output{display:inline-block;min-width:30px;vertical-align:top;text-align:center}.editable-color input[type=color]{width:50px}.editable-checkbox label span,.editable-checklist label span,.editable-radiolist label span{margin-left:7px;margin-right:10px}.editable-hide{display:none!important}.editable-click,a.editable-click{text-decoration:none;color:#428bca;border-bottom:dashed 1px #428bca}.editable-click:hover,a.editable-click:hover{text-decoration:none;color:#2a6496;border-bottom-color:#2a6496}.editable-empty,.editable-empty:hover,.editable-empty:focus,a.editable-empty,a.editable-empty:hover,a.editable-empty:focus{font-style:italic;color:#D14;text-decoration:none}.ui-popover-wrapper a{display:inline!important}.ui-popover-wrapper form{display:none!important}.popover-wrapper>a{display:inline!important}.popover-wrapper{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%;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}.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}@media screen and (max-width:750px){.popover-wrapper form{margin-left:-60px}.popover-wrapper form:before{left:50px}.popover-wrapper form:after{left:51px}}@media screen and (min-width:750px){.popover-wrapper form{margin-left:-110px}.popover-wrapper form:before{left:100px}.popover-wrapper form:after{left:101px}} -------------------------------------------------------------------------------- /docs/demos/bsdate/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('BsdateCtrl', function($scope) { 2 | $scope.user = { 3 | dob: new Date(1984, 4, 15) 4 | }; 5 | 6 | $scope.opened = {}; 7 | 8 | $scope.open = function($event, elementOpened) { 9 | $event.preventDefault(); 10 | $event.stopPropagation(); 11 | 12 | $scope.opened[elementOpened] = !$scope.opened[elementOpened]; 13 | }; 14 | }); -------------------------------------------------------------------------------- /docs/demos/bsdate/desc.md: -------------------------------------------------------------------------------- 1 | Date control is implemented via [Angular-ui bootstrap datepicker](http://angular-ui.github.io/bootstrap/#/datepicker). 2 | You should include additional `ui-bootstrap-tpls.min.js` for Bootstrap 3: 3 | 4 | 5 | 6 | For Bootstrap 4, include: 7 | 8 | 9 | 10 | Add `ui.bootstrap` as module dependency: 11 | 12 | var app = angular.module("app", ["xeditable", "ui.bootstrap"]); 13 | 14 | And set `editable-bsdate` attribute in editable element. 15 | To make the input field read-only and force the date to be selected from the popup, add the `e-readonly="true"` attribute. 16 | Add `e-ng-change` attribute to call a function when the value of the datepicker is changed. 17 | To hide the calendar button and display the calendar popup on click of the input field, set the `e-show-calendar-button` attribute to false. 18 | Other parameters can be defined via `e-*` syntax, e.g. `e-datepicker-popup="dd-MMMM-yyyy"`. -------------------------------------------------------------------------------- /docs/demos/bsdate/test.js: -------------------------------------------------------------------------------- 1 | describe('bsdate', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor and submit new value', function() { 8 | var s = '[ng-controller="BsdateCtrl"] '; 9 | 10 | expect(element(s+'a[editable-bsdate]').css('display')).not().toBe('none'); 11 | expect(element(s+'a[editable-bsdate]').text()).toMatch('15/05/1984'); 12 | element(s+'a[editable-bsdate]').click(); 13 | element(s+'form .input-group-btn button[type="button"]').click(); 14 | 15 | expect(element(s+'a[editable-bsdate]').css('display')).toBe('none'); 16 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 17 | expect(element(s+'form input[type="text"]:visible').count()).toBe(1); 18 | expect(element(s+'form input[type="text"]').val()).toBe('15-May-1984'); 19 | expect(element(s+'form .editable-buttons button[type="submit"]:visible').count()).toBe(1); 20 | expect(element(s+'form .editable-buttons button[type="button"]:visible').count()).toBe(1); 21 | expect(element(s+'ul.dropdown-menu:visible').count()).toBe(1); 22 | expect(element(s+'form table button.btn-info span').text()).toMatch('15'); 23 | 24 | //set 29 april 25 | element(s+'form table > tbody > tr:eq(0) > td:eq(1) > button').click(); 26 | expect(element(s+'ul.dropdown-menu:visible').count()).toBe(0); 27 | expect(element(s+'form input[type="text"]').val()).toBe('29-April-1984'); 28 | 29 | //submit 30 | element(s+'form button[type="submit"]').click(); 31 | 32 | expect(element(s+'a[editable-bsdate]').css('display')).not().toBe('none'); 33 | expect(element(s+'a[editable-bsdate]').text()).toMatch('29/04/1984'); 34 | expect(element(s+'form').count()).toBe(0); 35 | }); 36 | }); -------------------------------------------------------------------------------- /docs/demos/bsdate/view.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 7 | 8 |
-------------------------------------------------------------------------------- /docs/demos/bstime/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('BstimeCtrl', function($scope) { 2 | $scope.user = { 3 | time: new Date(1984, 4, 15, 19, 20) 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/bstime/desc.md: -------------------------------------------------------------------------------- 1 | Time control is implemented via [Angular-ui bootstrap timepicker](http://angular-ui.github.io/bootstrap/#/timepicker). 2 | You should include additional `ui-bootstrap-tpls.min.js`for Bootstrap 3: 3 | 4 | 5 | 6 | For Bootstrap 4, include: 7 | 8 | 9 | 10 | Add `ui.bootstrap` as module dependency: 11 | 12 | var app = angular.module("app", ["xeditable", "ui.bootstrap"]); 13 | 14 | And set `editable-bstime` attribute in editable element. 15 | Other parameters can be defined via `e-*` syntax, e.g. `e-minute-step="10"`. -------------------------------------------------------------------------------- /docs/demos/bstime/test.js: -------------------------------------------------------------------------------- 1 | describe('bstime', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor and submit new value', function() { 8 | var s = '[ng-controller="BstimeCtrl"] '; 9 | var a = s+'a[editable-bstime] '; 10 | 11 | expect(element(a).css('display')).not().toBe('none'); 12 | expect(element(a).text()).toMatch('19:20'); 13 | element(a).click(); 14 | 15 | expect(element(a).css('display')).toBe('none'); 16 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 17 | expect(element(s+'form input[type="text"]:visible').count()).toBe(2); 18 | expect(element(s+'form input[type="text"]:eq(0)').val()).toBe('19'); 19 | expect(element(s+'form input[type="text"]:eq(1)').val()).toBe('20'); 20 | expect(element(s+'form .editable-buttons button[type="submit"]:visible').count()).toBe(1); 21 | expect(element(s+'form .editable-buttons button[type="button"]:visible').count()).toBe(1); 22 | 23 | //set 20:30 24 | element(s+'form table > tbody > tr:eq(0) > td:eq(0) a').click(); 25 | element(s+'form table > tbody > tr:eq(0) > td:eq(2) a').click(); 26 | expect(element(s+'form input[type="text"]:eq(0)').val()).toBe('20'); 27 | expect(element(s+'form input[type="text"]:eq(1)').val()).toBe('30'); 28 | 29 | //submit 30 | element(s+'form button[type="submit"]').click(); 31 | 32 | expect(element(a).css('display')).not().toBe('none'); 33 | expect(element(a).text()).toMatch('20:30'); 34 | expect(element(s+'form').count()).toBe(0); 35 | }); 36 | }); -------------------------------------------------------------------------------- /docs/demos/bstime/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ (user.time | date:"HH:mm") || 'empty' }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/checkbox/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('CheckboxCtrl', function($scope) { 2 | $scope.user = { 3 | remember: true 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/checkbox/desc.md: -------------------------------------------------------------------------------- 1 | To make element editable via checkbox just add `editable-checkbox` attribute 2 | pointing to model in scope. Set `e-title` attribute to define text shown with checkbox. -------------------------------------------------------------------------------- /docs/demos/checkbox/test.js: -------------------------------------------------------------------------------- 1 | describe('checkbox', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor and submit new value', function() { 8 | var s = '[ng-controller="CheckboxCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('Remember me'); 11 | element(s+'a').click(); 12 | 13 | expect(element(s+'a:visible').count()).toBe(0); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="checkbox"]:visible').count()).toBe(1); 16 | expect(element(s+'form input[type="checkbox"]').val()).toBe('on'); 17 | expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); 18 | expect(element(s+'form button[type="button"]:visible').count()).toBe(1); 19 | 20 | using(s).input('$parent.$data').check(); 21 | element(s+'form button[type="submit"]').click(); 22 | 23 | expect(element(s+'a:visible').count()).toBe(1); 24 | expect(element(s+'a').text()).toMatch("Don't remember"); 25 | expect(element(s+'form').count()).toBe(0); 26 | }); 27 | 28 | }); -------------------------------------------------------------------------------- /docs/demos/checkbox/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ user.remember && "Remember me!" || "Don't remember" }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/checklist/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('ChecklistCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | status: [2, 3] 4 | }; 5 | 6 | $scope.statuses = [ 7 | {value: 1, text: 'status1'}, 8 | {value: 2, text: 'status2'}, 9 | {value: 3, text: 'status3'} 10 | ]; 11 | 12 | $scope.showStatus = function() { 13 | var selected = []; 14 | angular.forEach($scope.statuses, function(s) { 15 | if ($scope.user.status.indexOf(s.value) >= 0) { 16 | selected.push(s.text); 17 | } 18 | }); 19 | return selected.length ? selected.join(', ') : 'Not set'; 20 | }; 21 | 22 | $scope.disableCheckbox = function (v) { 23 | if ($scope.user.status.indexOf(v) === -1) { 24 | return true 25 | } 26 | return false; 27 | } 28 | 29 | }); -------------------------------------------------------------------------------- /docs/demos/checklist/desc.md: -------------------------------------------------------------------------------- 1 | To create list of checkboxes use `editable-checklist` attribute pointing to model. 2 | Also you should define `e-ng-options` attribute to set value and display items. 3 | Optionally define `e-checklist-comparator` to use a function to determine which checkboxes are actually checked. 4 | 5 | **Please note**, you should include [checklist-model directive](http://vitalets.github.io/checklist-model) into your app: `var app = angular.module("app", [..., "checklist-model"]);`. 6 | 7 | To disable a checkbox include the attribute `e-ng-disabled` and pass a condition. 8 | 9 | By default, checkboxes aligned *horizontally*. To align *vertically* just add following **CSS**: 10 | 11 | .editable-checklist label { 12 | display: block; 13 | } 14 | -------------------------------------------------------------------------------- /docs/demos/checklist/test.js: -------------------------------------------------------------------------------- 1 | describe('checklist', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show checkboxes and submit new value', function() { 8 | var s = '[ng-controller="ChecklistCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('status2, status3'); 11 | element(s+'a').click(); 12 | 13 | expect(element(s+'a').css('display')).toBe('none'); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="checkbox"]:visible:enabled').count()).toBe(2); 16 | expect(element(s+'form input[type="checkbox"]:checked').count()).toBe(2); 17 | 18 | // uncheck status3 19 | using(s+'label:eq(2)').input('checked').check(); 20 | element(s+'form button[type="submit"]').click(); 21 | 22 | expect(element(s+'a').css('display')).not().toBe('none'); 23 | expect(element(s+'a').text()).toMatch('status2'); 24 | expect(element(s+'form').count()).toBe(0); 25 | }); 26 | 27 | }); -------------------------------------------------------------------------------- /docs/demos/checklist/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ showStatus() }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/combodate/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('CombodateCtrl', function($scope) { 2 | $scope.user = { 3 | dob: new Date(1984, 4, 15) 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/combodate/desc.md: -------------------------------------------------------------------------------- 1 | You should include additional `moment.js`: 2 | 3 | And set `editable-combodate` attribute in editable element. 4 | Custom options supported by [Combodate](https://vitalets.github.io/combodate/) can be provided via `e-*` syntax, e.g. `e-min-year="2015"`, `e-max-year="2025"`. 5 | -------------------------------------------------------------------------------- /docs/demos/combodate/test.js: -------------------------------------------------------------------------------- 1 | describe('combodate', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor and submit new value', function() { 8 | var s = '[ng-controller="CombodateCtrl"] '; 9 | 10 | expect(element(s+'a[editable-combodate]').css('display')).not().toBe('none'); 11 | expect(element(s+'a[editable-combodate]').text()).toMatch('May 15, 1984 12:00:00 AM'); 12 | element(s+'a[editable-combodate]').click(); 13 | 14 | expect(element(s+'a[editable-combodate]').css('display')).toBe('none'); 15 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 16 | expect(element(s+'form select:visible').count()).toBe(5); 17 | expect(element(s+'form select.day').val()).toBe('15'); 18 | expect(element(s+'form select.month').val()).toBe('4'); 19 | expect(element(s+'form select.year').val()).toBe('1984'); 20 | expect(element(s+'form select.hour').val()).toBe('0'); 21 | expect(element(s+'form select.minute').val()).toBe('0'); 22 | expect(element(s+'form .editable-buttons button[type="submit"]:visible').count()).toBe(1); 23 | expect(element(s+'form .editable-buttons button[type="button"]:visible').count()).toBe(1); 24 | 25 | //set 29 april 26 | element(s+'form select.day option[value=29]').click(); 27 | element(s+'form select.month option[value=3]').click(); // month option numbers appear to be offset by 1 28 | 29 | //submit 30 | element(s+'form button[type="submit"]').click(); 31 | 32 | expect(element(s+'a[editable-combodate]').css('display')).not().toBe('none'); 33 | expect(element(s+'a[editable-combodate]').text()).toMatch('Apr 29, 1984 12:00:00 AM'); 34 | expect(element(s+'form').count()).toBe(0); 35 | }); 36 | 37 | it('should show editor and submit empty value when empty value is selected in one of the drop downs', function() { 38 | var s = '[ng-controller="CombodateCtrl"] '; 39 | 40 | expect(element(s+'a[editable-combodate]').css('display')).not().toBe('none'); 41 | expect(element(s+'a[editable-combodate]').text()).toMatch('May 15, 1984 12:00:00 AM'); 42 | element(s+'a[editable-combodate]').click(); 43 | 44 | expect(element(s+'a[editable-combodate]').css('display')).toBe('none'); 45 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 46 | expect(element(s+'form select:visible').count()).toBe(5); 47 | expect(element(s+'form select.day').val()).toBe('15'); 48 | expect(element(s+'form select.month').val()).toBe('4'); 49 | expect(element(s+'form select.year').val()).toBe('1984'); 50 | expect(element(s+'form select.hour').val()).toBe('0'); 51 | expect(element(s+'form select.minute').val()).toBe('0'); 52 | expect(element(s+'form .editable-buttons button[type="submit"]:visible').count()).toBe(1); 53 | expect(element(s+'form .editable-buttons button[type="button"]:visible').count()).toBe(1); 54 | 55 | //set 29 april 56 | element(s+'form select.day option[value=""]').click(); 57 | 58 | //submit 59 | element(s+'form button[type="submit"]').click(); 60 | 61 | expect(element(s+'a[editable-combodate]').css('display')).not().toBe('none'); 62 | expect(element(s+'a[editable-combodate]').text()).toMatch('empty'); 63 | expect(element(s+'form').count()).toBe(0); 64 | }); 65 | }); -------------------------------------------------------------------------------- /docs/demos/combodate/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ (user.dob | date:"medium") || 'empty' }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/dev-bsdate/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevBsdateCtrl', function($scope) { 2 | $scope.user = { 3 | dob: new Date(1984, 4, 15), 4 | startDate: '', 5 | hireDate: new Date(2006, 4, 15) 6 | }; 7 | 8 | $scope.getMinDate = function() { 9 | return new Date(1984, 4, 01); 10 | }; 11 | 12 | $scope.getMaxDate = function($event, elementOpened) { 13 | return new Date(2016, 4, 01); 14 | }; 15 | 16 | $scope.getInitDate = function($event, elementOpened) { 17 | return new Date(); 18 | }; 19 | 20 | $scope.altInputFormats = ['d/M/yy']; 21 | 22 | $scope.opened = {}; 23 | 24 | $scope.open = function($event, elementOpened) { 25 | $event.preventDefault(); 26 | $event.stopPropagation(); 27 | 28 | $scope.opened[elementOpened] = !$scope.opened[elementOpened]; 29 | }; 30 | 31 | $scope.changed = function(data) { 32 | $scope.user.changed = true; 33 | window.console.log("data = "+ data); 34 | window.console.log("value changed"); 35 | }; 36 | }); -------------------------------------------------------------------------------- /docs/demos/dev-bsdate/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-bsdate/view.html: -------------------------------------------------------------------------------- 1 |
2 | 12 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 13 | 14 |   15 | 22 | {{ (user.startDate | date:"dd/MM/yyyy") || 'empty' }} 23 | 24 |   25 | 34 | {{ (user.hireDate | date:"dd/MM/yyyy") || 'empty' }} 35 | 36 |   37 | 44 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 45 | 46 |   47 | 54 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 55 | 56 |   57 | 65 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 66 | 67 |   68 | 76 | {{ (user.dob | date:"dd/MM/yyyy") || 'empty' }} 77 | 78 |
-------------------------------------------------------------------------------- /docs/demos/dev-checkbox/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevCheckboxCtrl', function($scope) { 2 | $scope.user = { 3 | remember: true 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/dev-checkbox/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-checkbox/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-checkbox', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor and submit new value', function() { 8 | var s = '[ng-controller="DevCheckboxCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('Remember me'); 11 | element(s+'a').click(); 12 | 13 | expect(element(s+'a:visible').count()).toBe(0); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="checkbox"]:visible').count()).toBe(1); 16 | expect(element(s+'form input[type="checkbox"]').val()).toBe('on'); 17 | expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); 18 | expect(element(s+'form button[type="button"]:visible').count()).toBe(1); 19 | 20 | using(s).input('$parent.$data').check(); 21 | element(s+'form button[type="submit"]').click(); 22 | 23 | expect(element(s+'a:visible').count()).toBe(1); 24 | expect(element(s+'a').text()).toMatch("Don't remember"); 25 | expect(element(s+'form').count()).toBe(0); 26 | }); 27 | 28 | }); -------------------------------------------------------------------------------- /docs/demos/dev-checkbox/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ user.remember && "Remember me!" || "Don't remember" }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/dev-checklist/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevChecklistCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | devstatus: [2, 3], 4 | devobjectstatus: [ 5 | {value: 2, text: 'status2'}, 6 | {value: 3, text: 'status3'} 7 | ] 8 | }; 9 | 10 | $scope.statuses = [ 11 | {value: 1, text: 'status1'}, 12 | {value: 2, text: 'status2'}, 13 | {value: 3, text: 'status3'} 14 | ]; 15 | 16 | $scope.showStatus = function() { 17 | var selected = []; 18 | angular.forEach($scope.statuses, function(s) { 19 | if ($scope.user.devstatus.indexOf(s.value) >= 0) { 20 | selected.push(s.text); 21 | } 22 | }); 23 | return selected.length ? selected.join(', ') : 'Not set'; 24 | }; 25 | 26 | $scope.showObjectStatus = function() { 27 | var selected = []; 28 | angular.forEach($scope.user.devobjectstatus, function(s) { 29 | selected.push(s.text); 30 | }); 31 | return selected.length ? selected.join(', ') : 'Not set'; 32 | }; 33 | 34 | $scope.compareFn = function(obj1, obj2) { 35 | return obj1.value === obj2.value; 36 | }; 37 | 38 | $scope.doSomething = function($data) { 39 | window.console.log($data); 40 | }; 41 | }); -------------------------------------------------------------------------------- /docs/demos/dev-checklist/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-checklist/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-checklist', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show checkboxes and submit new value with no buttons and blur = submit', function() { 8 | var s = '[ng-controller="DevChecklistCtrl"] '; 9 | 10 | expect(element(s+'a.nobuttons ').text()).toMatch('status2, status3'); 11 | element(s+'a.nobuttons ').click(); 12 | 13 | expect(element(s+'a.nobuttons ').css('display')).toBe('none'); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="checkbox"]:visible:enabled').count()).toBe(3); 16 | expect(element(s+'form input[type="checkbox"]:checked').count()).toBe(2); 17 | 18 | // check status1 19 | using(s+'label:eq(0)').input('checked').check(); 20 | // uncheck status3 21 | using(s+'label:eq(2)').input('checked').check(); 22 | element(s).click(); 23 | 24 | expect(element(s+'a.nobuttons ').css('display')).not().toBe('none'); 25 | expect(element(s+'a.nobuttons ').text()).toMatch('status1, status2'); 26 | expect(element(s+'form').count()).toBe(0); 27 | }); 28 | 29 | it('should show checkboxes and submit new value with no buttons and blur = submit and call on-change event', function() { 30 | var s = '[ng-controller="DevChecklistCtrl"] '; 31 | 32 | expect(element(s+'a.onchange ').text()).toMatch('status2, status3'); 33 | element(s+'a.onchange ').click(); 34 | 35 | expect(element(s+'a.onchange ').css('display')).toBe('none'); 36 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 37 | expect(element(s+'form input[type="checkbox"]:visible:enabled').count()).toBe(3); 38 | expect(element(s+'form input[type="checkbox"]:checked').count()).toBe(2); 39 | expect(element(s+'form input[type="checkbox"]').attr('ng-change')).toBeDefined(); 40 | expect(element(s+'form input[type="checkbox"]').attr('checklist-comparator')).toBeDefined(); 41 | 42 | // check status1 43 | using(s+'label:eq(0)').input('checked').check(); 44 | // uncheck status3 45 | using(s+'label:eq(2)').input('checked').check(); 46 | element(s).click(); 47 | 48 | expect(element(s+'a.onchange ').css('display')).not().toBe('none'); 49 | expect(element(s+'a.onchange ').text()).toMatch('status2, status1'); 50 | expect(element(s+'form').count()).toBe(0); 51 | }); 52 | 53 | }); -------------------------------------------------------------------------------- /docs/demos/dev-checklist/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ showStatus() }} 4 |    5 | 6 | 7 | {{ showObjectStatus() }} 8 | 9 |
-------------------------------------------------------------------------------- /docs/demos/dev-combodate/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevCombodateCtrl', function($scope) { 2 | $scope.user = { 3 | dob: new Date(1984, 4, 15), 4 | dob2: new Date(1984, 4, 15, 10, 11, 0) 5 | }; 6 | $scope.myDate = { 7 | date: new Date(1984, 4, 15), 8 | format: "yyyy", 9 | template: "YYYY" 10 | }; 11 | $scope.myDate2 = { 12 | date: new Date(1984, 4, 15), 13 | format: "yyyy, MMMM", 14 | template: "YYYY, MMMM" 15 | }; 16 | $scope.myDate3 = { 17 | date: new Date(1984, 4, 15), 18 | format: "MMMM", 19 | template: "MMMM" 20 | } 21 | $scope.myDate4 = { 22 | date: new Date(1984, 4, 15), 23 | format: "dd/MM/yyyy", 24 | template: "DD/MM/YYYY" 25 | }; 26 | }); -------------------------------------------------------------------------------- /docs/demos/dev-combodate/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-combodate/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ (user.dob | date:"medium") || 'empty' }} 4 |   5 | 6 | {{ (user.dob2 | date:"medium") || 'empty' }} 7 | 8 |
9 | {{myDate.date | date: myDate.format}} 10 |
11 | {{myDate.date}} 12 |
13 |
14 | {{myDate2.date | date: myDate2.format}} 15 |
16 | {{myDate2.date}} 17 |
18 |
19 | {{myDate3.date | date: myDate3.format}} 20 |
21 | {{myDate3.date}} 22 |
23 |
24 | {{myDate4.date | date: myDate4.format}} 25 |
26 | {{myDate4.date}} 27 |
-------------------------------------------------------------------------------- /docs/demos/dev-editable-row/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevEditableRowCtrl', function($scope, $filter, $http) { 2 | $scope.users = [ 3 | {id: 1, name: 'awesome user1', status: [2], group: 4, groupName: 'admin'}, 4 | {id: 2, name: 'awesome user2', status: [], group: 3, groupName: 'vip'}, 5 | {id: 3, name: 'awesome user3', status: [2], group: null} 6 | ]; 7 | 8 | $scope.statuses = [ 9 | {value: 1, text: 'status1'}, 10 | {value: 2, text: 'status2'}, 11 | {value: 3, text: 'status3'}, 12 | {value: 4, text: 'status4'} 13 | ]; 14 | 15 | $scope.groups = []; 16 | $scope.loadGroups = function() { 17 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 18 | $scope.groups = data; 19 | }); 20 | }; 21 | 22 | $scope.showGroup = function(user) { 23 | if(user.group && $scope.groups.length) { 24 | var selected = $filter('filter')($scope.groups, {id: user.group}); 25 | return selected.length ? selected[0].text : 'Not set'; 26 | } else { 27 | return user.groupName || 'Not set'; 28 | } 29 | }; 30 | 31 | $scope.showStatus = function(user) { 32 | var selected = []; 33 | angular.forEach($scope.statuses, function(s) { 34 | if (user.status && user.status.indexOf(s.value) >= 0) { 35 | selected.push(s.text); 36 | } 37 | }); 38 | return selected.length ? selected.join(', ') : 'Not set'; 39 | }; 40 | 41 | $scope.checkName = function(data, id) { 42 | if (id === 2 && data !== 'awesome') { 43 | return "Username 2 should be awesome"; 44 | } 45 | }; 46 | 47 | $scope.saveUser = function(data, id) { 48 | //$scope.user not updated yet 49 | angular.extend(data, {id: id}); 50 | return $http.post('/saveUser', data); 51 | }; 52 | 53 | // remove user 54 | $scope.removeUser = function(index) { 55 | $scope.users.splice(index, 1); 56 | }; 57 | 58 | // add user 59 | $scope.addUser = function() { 60 | $scope.inserted = { 61 | id: $scope.users.length+1, 62 | name: '', 63 | status: null, 64 | group: null 65 | }; 66 | $scope.users.push($scope.inserted); 67 | }; 68 | }); -------------------------------------------------------------------------------- /docs/demos/dev-editable-row/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-editable-row/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 22 | 28 | 43 | 44 |
NameStatusGroupEdit
11 | 12 | 13 | {{ user.name || 'empty' }} 14 | 15 | 17 | 18 | 19 | {{ showStatus(user) }} 20 | 21 | 23 | 24 | 25 | {{ showGroup(user) }} 26 | 27 | 29 | 30 |
31 | 34 | 37 |
38 |
39 | 40 | 41 |
42 |
45 | 46 | 47 |
-------------------------------------------------------------------------------- /docs/demos/dev-eform/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevEformCtrl', function($scope, $filter, $http) { 2 | $scope.users = [ 3 | {id: 1, name: 'awesome user1', status: 2, group: 4, groupName: 'admin'}, 4 | {id: 2, name: 'awesome user2', status: undefined, group: 3, groupName: 'vip'}, 5 | {id: 3, name: 'awesome user3', status: 2, group: null} 6 | ]; 7 | 8 | $scope.statuses = [ 9 | {value: 1, text: 'status1'}, 10 | {value: 2, text: 'status2'}, 11 | {value: 3, text: 'status3'}, 12 | {value: 4, text: 'status4'} 13 | ]; 14 | 15 | $scope.groups = []; 16 | $scope.loadGroups = function() { 17 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 18 | $scope.groups = data; 19 | }); 20 | }; 21 | 22 | $scope.showGroup = function(user) { 23 | if(user.group && $scope.groups.length) { 24 | var selected = $filter('filter')($scope.groups, {id: user.group}); 25 | return selected.length ? selected[0].text : 'Not set'; 26 | } else { 27 | return user.groupName || 'Not set'; 28 | } 29 | }; 30 | 31 | $scope.showStatus = function(user) { 32 | var selected = []; 33 | if(user.status) { 34 | selected = $filter('filter')($scope.statuses, {value: user.status}); 35 | } 36 | return selected.length ? selected[0].text : 'Not set'; 37 | }; 38 | 39 | $scope.checkName = function(data, id) { 40 | if (id === 2 && data !== 'awesome') { 41 | return "Username 2 should be `awesome`"; 42 | } 43 | }; 44 | 45 | $scope.saveUser = function(data, id) { 46 | //$scope.user not updated yet 47 | angular.extend(data, {id: id}); 48 | return $http.post('/saveUser', data); 49 | }; 50 | 51 | // remove user 52 | $scope.removeUser = function(index) { 53 | $scope.users.splice(index, 1); 54 | }; 55 | 56 | // add user 57 | $scope.addUser = function() { 58 | $scope.inserted = { 59 | id: $scope.users.length+1, 60 | name: '', 61 | status: null, 62 | group: null 63 | }; 64 | $scope.users.push($scope.inserted); 65 | }; 66 | }); -------------------------------------------------------------------------------- /docs/demos/dev-eform/desc.md: -------------------------------------------------------------------------------- 1 | dev 2 | -------------------------------------------------------------------------------- /docs/demos/dev-eform/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-eform', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show editor by click', function() { 8 | var s = '[ng-controller="DevEformCtrl"] '; 9 | 10 | expect(element(s+'a:eq(0)').text()).toMatch('awesome user1'); 11 | 12 | //not open by click 13 | element(s+'a:eq(0)').click(); 14 | expect(element(s+'a:eq(0)').css('display')).toBe('none'); 15 | expect(element(s+'form').count()).toBe(1); 16 | 17 | //e-form should not transfer 18 | expect(element(s+'form input[type="text"]').attr('form')).toBeFalsy(); 19 | expect(element(s+'form').attr('name')).toBeFalsy(); 20 | expect(element(s+'form').attr('editable-form')).toBeTruthy(); 21 | 22 | //submit 23 | using(s).input('$parent.$data').enter('username2'); 24 | element(s+'form button[type="submit"]').click(); 25 | 26 | expect(element(s+'a:eq(0)').css('display')).not().toBe('none'); 27 | expect(element(s+'a:eq(0)').text()).toMatch('username2'); 28 | expect(element(s+'form').count()).toBe(0); 29 | }); 30 | 31 | }); -------------------------------------------------------------------------------- /docs/demos/dev-eform/view.html: -------------------------------------------------------------------------------- 1 |
2 | 9 |
-------------------------------------------------------------------------------- /docs/demos/dev-form/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevFormCtrl', function($scope, $filter, $http) { 2 | $scope.user = { 3 | id: 1, 4 | name: 'awesome user', 5 | status: 2, 6 | group: 4, 7 | groupName: 'admin' 8 | }; 9 | 10 | $scope.statuses = [ 11 | {value: 1, text: 'status1'}, 12 | {value: 2, text: 'status2'}, 13 | {value: 3, text: 'status3'}, 14 | {value: 4, text: 'status4'} 15 | ]; 16 | 17 | $scope.groups = []; 18 | $scope.loadGroups = function() { 19 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 20 | $scope.groups = data; 21 | }); 22 | }; 23 | 24 | $scope.showGroup = function() { 25 | if($scope.groups.length) { 26 | var selected = $filter('filter')($scope.groups, {id: $scope.user.group}); 27 | return selected.length ? selected[0].text : 'Not set'; 28 | } else { 29 | return $scope.user.groupName; 30 | } 31 | }; 32 | 33 | $scope.checkName = function(data) { 34 | if (data !== 'awesome' && data !== 'error') { 35 | return "Username should be `awesome` or `error`"; 36 | } 37 | }; 38 | 39 | $scope.saveUser = function() { 40 | // $scope.user already updated! 41 | return $http.post('/saveUser', $scope.user).error(function(err) { 42 | if(err.field && err.msg) { 43 | // err like {field: "name", msg: "Server-side error for this username!"} 44 | $scope.editableForm.$setError(err.field, err.msg); 45 | } else { 46 | // unknown error 47 | $scope.editableForm.$setError('name', 'Unknown error!'); 48 | } 49 | }); 50 | }; 51 | }); -------------------------------------------------------------------------------- /docs/demos/dev-form/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-ngtags/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevNgTagsCtrl', function($scope, $http) { 2 | $scope.user = { 3 | tags: [ 4 | { text: 'Tag1' }, 5 | { text: 'Tag2' }, 6 | { text: 'Tag3' } 7 | ] 8 | }; 9 | }); -------------------------------------------------------------------------------- /docs/demos/dev-ngtags/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-ngtags/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-ngtags', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show form by `edit` button click and close by `cancel` with no autocomplete tag', function() { 8 | var s = '[ng-controller="DevNgTagsCtrl"] '; 9 | 10 | //edit button initially shown, form initially hidden 11 | expect(element(s+'form[name=ngTagsForm] > div[editable-tags-input]:visible').count()).toBe(1); 12 | expect(element(s+'form[name=ngTagsForm] .buttons > button:visible').count()).toBe(1); 13 | expect(element(s+'form[name=ngTagsForm] .buttons > span:visible').count()).toBe(0); 14 | 15 | //show form 16 | element(s+'form[name=ngTagsForm] > div > button').click(); 17 | //second click to test that controls not duplicated! 18 | element(s+'form[name=ngTagsForm] > div > button').click(); 19 | //also click outside to check blur = ignore 20 | element('body').click(); 21 | 22 | //form shown in disabled state (loading) 23 | expect(element(s+'form[name=ngTagsForm] > div[editable-tags-input]:visible').count()).toBe(0); 24 | expect(element(s+'form[name=ngTagsForm] .buttons > button:visible').count()).toBe(0); 25 | 26 | sleep(delay); 27 | 28 | //also click outside to check blur = ignore 29 | element('body').click(); 30 | 31 | //form enabled when data loaded 32 | expect(element(s+'form[name=ngTagsForm] > div[editable-ui-select]:visible').count()).toBe(0); 33 | expect(element(s+'form[name=ngTagsForm] .buttons > button:visible').count()).toBe(0); 34 | expect(element(s+'form[name=ngTagsForm] .buttons > span button:enabled').count()).toBe(2); 35 | 36 | //click cancel 37 | element(s+'form[name=ngTagsForm] > div > span button[type="button"]').click(); 38 | 39 | //form closed 40 | expect(element(s+'form[name=ngTagsForm] > div[editable-tags-input]:visible').count()).toBe(1); 41 | expect(element(s+'form[name=ngTagsForm] .buttons > button:visible').count()).toBe(1); 42 | expect(element(s+'form[name=ngTagsForm] .buttons > span:visible').count()).toBe(0); 43 | }); 44 | 45 | it('should show form and save new values with no autocomplete tag', function() { 46 | var s = '[ng-controller="DevNgTagsCtrl"] '; 47 | 48 | //show form 49 | element(s+'form[name=ngTagsForm] > div > button').click(); 50 | 51 | sleep(delay); 52 | 53 | //select a value 54 | element(s+' input[type="text"]').click(); 55 | input('newTag.text').enter('Tag4'); 56 | 57 | //click submit 58 | element(s+'form[name=ngTagsForm] span button[type="submit"]').click(); 59 | //second click to check that it works correctly 60 | element(s+'form[name=ngTagsForm] span button[type="submit"]').click(); 61 | 62 | //saving 63 | expect(element(s+'form[name=ngTagsForm] > div:eq(0) .editable-error:visible').count()).toBe(0); 64 | 65 | sleep(delay); 66 | 67 | //form closed, new values shown 68 | expect(element(s+'form[name=ngTagsForm] > div[editable-tags-input]:visible').count()).toBe(1); 69 | expect(element(s+'form[name=ngTagsForm] > div[editable-tags-input]:visible').text()).toMatch('[{"text":"Tag1"},{"text":"Tag2"},{"text":"Tag3"},{"text":"Tag4"}]'); 70 | expect(element(s+'form[name=ngTagsForm] .buttons > button:visible').count()).toBe(1); 71 | expect(element(s+'form[name=ngTagsForm] .buttons > span:visible').count()).toBe(0); 72 | }); 73 | }); -------------------------------------------------------------------------------- /docs/demos/dev-ngtags/view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{user.tags}} 5 |
6 |
7 |
8 | 9 | 12 | 13 | 14 |
15 | 18 | 21 |
22 |
23 |
24 |
-------------------------------------------------------------------------------- /docs/demos/dev-radiolist/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevRadiolistCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | booleanstatus: true, 4 | stringStatus: "s1" 5 | }; 6 | 7 | $scope.bolleanstatuses = [ 8 | {value: true, text: 'status1'}, 9 | {value: false, text: 'status2'} 10 | ]; 11 | 12 | $scope.stringStatuses = [ 13 | {value: 's1', text: 'status1'}, 14 | {value: 's2', text: 'status2'} 15 | ]; 16 | 17 | $scope.showBooleanStatus = function() { 18 | var selected = $filter('filter')($scope.bolleanstatuses, {value: $scope.user.booleanstatus}); 19 | return ($scope.user.booleanstatus != null && selected.length) ? selected[0].text : 'Not set'; 20 | }; 21 | 22 | $scope.showStringStatus = function() { 23 | var selected = $filter('filter')($scope.stringStatuses, {value: $scope.user.stringStatus}); 24 | return ($scope.user.stringStatus != null && selected.length) ? selected[0].text : 'Not set'; 25 | }; 26 | 27 | $scope.doSomething = function($data) { 28 | window.console.log($data); 29 | }; 30 | }); -------------------------------------------------------------------------------- /docs/demos/dev-radiolist/desc.md: -------------------------------------------------------------------------------- 1 | dev 2 | -------------------------------------------------------------------------------- /docs/demos/dev-radiolist/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-radiolist', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show radio options with name and submit new value', function() { 8 | var s = '[ng-controller="DevRadiolistCtrl"] '; 9 | 10 | expect(element(s+'a.normal ').text()).toMatch('status1'); 11 | element(s+'a.normal ').click(); 12 | 13 | expect(element(s+'a.normal ').css('display')).toBe('none'); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="radio"]:visible:enabled').count()).toBe(2); 16 | expect(element(s+'form input[type="radio"]').attr('name')).toBeDefined(); 17 | 18 | expect(using(s+'label:eq(0)').input('$parent.$parent.$data').val()).toBe('true'); 19 | expect(using(s+'label:eq(1)').input('$parent.$parent.$data').val()).toBe('false'); 20 | 21 | // select status2 22 | using(s+'label:eq(1)').input('$parent.$parent.$data').select('false'); 23 | element(s+'form button[type="submit"]').click(); 24 | 25 | expect(element(s+'a.normal ').css('display')).not().toBe('none'); 26 | expect(element(s+'a.normal ').text()).toMatch('status2'); 27 | expect(element(s+'form').count()).toBe(0); 28 | }); 29 | 30 | it('should show radio options and call on-change event', function() { 31 | var s = '[ng-controller="DevRadiolistCtrl"] '; 32 | 33 | expect(element(s+'a.nobuttons ').text()).toMatch('status1'); 34 | element(s+'a.nobuttons ').click(); 35 | 36 | expect(element(s+'a.nobuttons ').css('display')).toBe('none'); 37 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 38 | expect(element(s+'form input[type="radio"]:visible:enabled').count()).toBe(2); 39 | expect(element(s+'form input[type="radio"]').attr('ng-change')).toBeDefined(); 40 | 41 | expect(using(s+'label:eq(0)').input('$parent.$parent.$data').val()).toBe('true'); 42 | expect(using(s+'label:eq(1)').input('$parent.$parent.$data').val()).toBe('false'); 43 | 44 | // select status2 45 | using(s+'label:eq(1)').input('$parent.$parent.$data').select('false'); 46 | element(s).click(); 47 | 48 | expect(element(s+'a.nobuttons ').css('display')).not().toBe('none'); 49 | expect(element(s+'a.nobuttons ').text()).toMatch('status1'); 50 | expect(element(s+'form').count()).toBe(0); 51 | }); 52 | 53 | it('should show radio options with string values and submit new value', function() { 54 | var s = '[ng-controller="DevRadiolistCtrl"] '; 55 | 56 | expect(element(s+'a.string ').text()).toMatch('status1'); 57 | element(s+'a.string ').click(); 58 | 59 | expect(element(s+'a.string ').css('display')).toBe('none'); 60 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 61 | expect(element(s+'form input[type="radio"]:visible:enabled').count()).toBe(2); 62 | expect(element(s+'form input[type="radio"]').attr('name')).toBeDefined(); 63 | 64 | expect(using(s+'label:eq(0)').input('$parent.$parent.$data').val()).toBe('s1'); 65 | expect(using(s+'label:eq(1)').input('$parent.$parent.$data').val()).toBe('s2'); 66 | 67 | // select status2 68 | using(s+'label:eq(1)').input('$parent.$parent.$data').select('s2'); 69 | element(s+'form button[type="submit"]').click(); 70 | 71 | expect(element(s+'a.string ').css('display')).not().toBe('none'); 72 | expect(element(s+'a.string ').text()).toMatch('status2'); 73 | expect(element(s+'form').count()).toBe(0); 74 | }); 75 | }); -------------------------------------------------------------------------------- /docs/demos/dev-radiolist/view.html: -------------------------------------------------------------------------------- 1 |
2 | 6 | {{ showBooleanStatus() }} 7 |    8 | 9 | 14 | {{ showBooleanStatus() }} 15 |    16 | 17 | 21 | {{ showStringStatus() }} 22 | 23 |
-------------------------------------------------------------------------------- /docs/demos/dev-select-multiple/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevSelectMultipleCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | status: [2, 4] 4 | }; 5 | 6 | $scope.statuses = [ 7 | {value: 1, text: 'status1'}, 8 | {value: 2, text: 'status2'}, 9 | {value: 3, text: 'status3'}, 10 | {value: 4, text: 'status4'} 11 | ]; 12 | 13 | $scope.showStatus = function() { 14 | var selected = []; 15 | angular.forEach($scope.statuses, function(s) { 16 | if ($scope.user.status.indexOf(s.value) >= 0) { 17 | selected.push(s.text); 18 | } 19 | }); 20 | return selected.length ? selected.join(', ') : 'Not set'; 21 | }; 22 | }); -------------------------------------------------------------------------------- /docs/demos/dev-select-multiple/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-select-multiple/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-select-multiple', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show options and submit new value on blur', function() { 8 | var s = '[ng-controller="DevSelectMultipleCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('status2'); 11 | expect(element(s+'a').text()).toMatch('status4'); 12 | element(s+'a').click(); 13 | 14 | expect(element(s+'a').css('display')).toBe('none'); 15 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 16 | expect(element(s+'form select:visible:enabled').count()).toBe(1); 17 | expect(element(s+'form select option').count()).toBe(4); 18 | expect(element(s+'form select option:selected').count()).toBe(2); 19 | expect(element(s+'form select').val()).toMatch('["1","3"]'); 20 | 21 | using(s).select('$parent.$data').options('number:2', 'number:3'); 22 | element('body').click(); 23 | 24 | expect(element(s+'a').css('display')).not().toBe('none'); 25 | expect(element(s+'a').text()).toMatch('status2'); 26 | expect(element(s+'a').text()).toMatch('status3'); 27 | expect(element(s+'a').text()).not().toMatch('status4'); 28 | expect(element(s+'form').count()).toBe(0); 29 | }); 30 | 31 | }); -------------------------------------------------------------------------------- /docs/demos/dev-select-multiple/view.html: -------------------------------------------------------------------------------- 1 |
2 | 7 | {{ showStatus() }} 8 | 9 |
-------------------------------------------------------------------------------- /docs/demos/dev-select/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevSelectCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | status: [2, 4], 4 | status2: null 5 | }; 6 | 7 | $scope.statuses = [ 8 | {value: 1, text: 'status1'}, 9 | {value: 2, text: 'status2'}, 10 | {value: 3, text: 'status3'}, 11 | {value: 4, text: 'status4'} 12 | ]; 13 | 14 | $scope.showStatus = function() { 15 | var selected = []; 16 | angular.forEach($scope.statuses, function(s) { 17 | if ($scope.user.status.indexOf(s.value) >= 0) { 18 | selected.push(s.text); 19 | } 20 | }); 21 | return selected.length ? selected.join(', ') : 'Not set'; 22 | }; 23 | 24 | $scope.showStatus2 = function() { 25 | var selected = $filter('filter')($scope.statuses, {value: $scope.user.status2}); 26 | return ($scope.user.status2 && selected.length) ? selected[0].text : 'Not set'; 27 | }; 28 | }); -------------------------------------------------------------------------------- /docs/demos/dev-select/desc.md: -------------------------------------------------------------------------------- 1 | dev 2 | -------------------------------------------------------------------------------- /docs/demos/dev-select/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-select-multiple', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show options defined without value', function() { 8 | var s = '[ng-controller="DevSelectCtrl"] '; 9 | 10 | expect(element(s+'a#multiSelect').text()).toMatch('status2'); 11 | expect(element(s+'a#multiSelect').text()).toMatch('status4'); 12 | element(s+'a#multiSelect').click(); 13 | 14 | expect(element(s+'a#multiSelect').css('display')).toBe('none'); 15 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 16 | expect(element(s+'form select:visible:enabled').count()).toBe(1); 17 | expect(element(s+'form select option').count()).toBe(4); 18 | expect(element(s+'form select option:selected').count()).toBe(2); 19 | expect(element(s+'form select').val()).toMatch('["1","3"]'); 20 | 21 | using(s).select('$parent.$data').option('status2'); 22 | element(s+'form button[type="submit"]').click(); 23 | 24 | expect(element(s+'a#multiSelect').css('display')).not().toBe('none'); 25 | expect(element(s+'a#multiSelect').text()).toMatch('status2'); 26 | expect(element(s+'a#multiSelect').text()).not().toMatch('status4'); 27 | expect(element(s+'form').count()).toBe(0); 28 | }); 29 | 30 | it('should show options with default value selected', function() { 31 | var s = '[ng-controller="DevSelectCtrl"] '; 32 | 33 | expect(element(s+'a#defaultValue').text()).toMatch('Not set'); 34 | element(s+'a#defaultValue').click(); 35 | 36 | expect(element(s+'a#defaultValue').css('display')).toBe('none'); 37 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 38 | expect(element(s+'form select:visible:enabled').count()).toBe(1); 39 | expect(element(s+'form select option').count()).toBe(5); 40 | expect(element(s+'form select option:selected').count()).toBe(1); 41 | expect(element(s+'form select').val()).toMatch(''); 42 | 43 | using(s).select('$parent.$data').option('status2'); 44 | element(s+'form button[type="submit"]').click(); 45 | 46 | expect(element(s+'a#defaultValue').css('display')).not().toBe('none'); 47 | expect(element(s+'a#defaultValue').text()).toMatch('status2'); 48 | expect(element(s+'form').count()).toBe(0); 49 | }); 50 | }); -------------------------------------------------------------------------------- /docs/demos/dev-select/view.html: -------------------------------------------------------------------------------- 1 |
2 | 7 | {{ showStatus() }} 8 | 9 |   10 | {{showStatus2()}} 15 |
-------------------------------------------------------------------------------- /docs/demos/dev-text/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevText', function($scope) { 2 | $scope.user = { 3 | name: 'awesome user', 4 | number: 12 5 | }; 6 | 7 | $scope.val = 10; 8 | $scope.newValue = $scope.val; 9 | $scope.calcSomething = function(val) { 10 | $scope.newValue = val; 11 | } 12 | }); -------------------------------------------------------------------------------- /docs/demos/dev-text/desc.md: -------------------------------------------------------------------------------- 1 | dev-test -------------------------------------------------------------------------------- /docs/demos/dev-text/view.html: -------------------------------------------------------------------------------- 1 |
2 | 17 | {{ (user.name || 'empty') | uppercase }} 18 | 19 |   20 | 21 | {{ user.name }} 22 | 23 |   24 | 25 | {{ user.name }} 26 | 27 |   28 | 29 | {{ user.name }} 30 | 31 |   32 | 33 | {{ user.name }} 34 | 35 |   36 | 37 | {{ user.name }} 38 | 39 |   40 |
41 | {{ user.name }} 42 |
43 | 44 | {{ val }} 45 | 46 |   47 |
-------------------------------------------------------------------------------- /docs/demos/dev-textarea/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevTextareaCtrl', function($scope) { 2 | $scope.user = { 3 | html: 'Title

my text...' 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/dev-textarea/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/dev-textarea/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-textarea', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show html in link and show editor and submit new value', function() { 8 | var s = '[ng-controller="DevTextareaCtrl"] '; 9 | var a = s + 'a#displayHtml '; 10 | 11 | expect(element(a).css('display')).not().toBe('none'); 12 | expect(element(a).text()).toMatch('Titlemy text...'); 13 | element(a).click(); 14 | 15 | expect(element(a).css('display')).toBe('none'); 16 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 17 | expect(element(s+'form textarea:visible').count()).toBe(1); 18 | expect(element(s+'form textarea').val()).toMatch('Title

my text...'); 19 | expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); 20 | expect(element(s+'form button[type="button"]:visible').count()).toBe(1); 21 | 22 | using(s).input('$parent.$data').enter('username2'); 23 | element(s+'form button[type="submit"]').click(); 24 | 25 | expect(element(a).css('display')).not().toBe('none'); 26 | expect(element(a).text()).toMatch('username2'); 27 | expect(element(s+'form').count()).toBe(0); 28 | }); 29 | 30 | it('textarea with submit on enter attribute', function() { 31 | var s = '[ng-controller="DevTextareaCtrl"] '; 32 | var a = s + 'a#submitOnEnter '; 33 | 34 | expect(element(a).css('display')).not().toBe('none'); 35 | expect(element(a).text()).toMatch('Titlemy text...'); 36 | element(a).click(); 37 | 38 | expect(element(a).css('display')).toBe('none'); 39 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 40 | expect(element(s+'form textarea:visible').count()).toBe(1); 41 | expect(element(s+'form textarea').val()).toMatch('Title

my text...'); 42 | expect(element(s+'form button[type="submit"]:visible').count()).toBe(0); 43 | expect(element(s+'form button[type="button"]:visible').count()).toBe(0); 44 | 45 | using(s).input('$parent.$data').enter('username3'); 46 | 47 | //click body --> submit 48 | element('body').click(); 49 | 50 | expect(element(a).css('display')).not().toBe('none'); 51 | expect(element(a).text()).toMatch('Titlemy text...'); 52 | expect(element(s+'form').count()).toBe(0); 53 | }); 54 | 55 | it('should show textarea with formclasses set', function() { 56 | var s = '[ng-controller="DevTextareaCtrl"] '; 57 | var a = s + 'a#formclass '; 58 | 59 | expect(element(a).css('display')).not().toBe('none'); 60 | expect(element(a).text()).toMatch('Title

my text...'); 61 | element(a).click(); 62 | 63 | expect(element(a).css('display')).toBe('none'); 64 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 65 | expect(element(s+'form textarea:visible').count()).toBe(1); 66 | expect(element(s+'form textarea').val()).toMatch('Title

my text...'); 67 | expect(element(s+'form button[type="submit"]:visible').count()).toBe(1); 68 | expect(element(s+'form button[type="button"]:visible').count()).toBe(1); 69 | expect(element(s+'form textarea').attr('formclass')).not().toBeDefined(); 70 | expect(element(s+'form').attr('class')).toBe("form-inline editable-wrap editable-textarea testclass ng-pristine ng-valid ng-scope"); 71 | 72 | using(s).input('$parent.$data').enter('username2'); 73 | element(s+'form button[type="submit"]').click(); 74 | 75 | expect(element(a).css('display')).not().toBe('none'); 76 | expect(element(a).text()).toMatch('username2'); 77 | expect(element(s+'form').count()).toBe(0); 78 | }); 79 | }); -------------------------------------------------------------------------------- /docs/demos/dev-textarea/view.html: -------------------------------------------------------------------------------- 1 |

2 | 3 |
{{ user.html || 'no description' }}
4 |
   5 | 6 |
{{ user.html || 'no description' }}
7 |
   8 | 9 |
{{ user.html || 'no description' }}
10 |
   11 |
-------------------------------------------------------------------------------- /docs/demos/dev-theme/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevTheme', function($scope) { 2 | $scope.user = { 3 | name: 'awesome user' 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/dev-theme/desc.md: -------------------------------------------------------------------------------- 1 | dev-test -------------------------------------------------------------------------------- /docs/demos/dev-theme/test.js: -------------------------------------------------------------------------------- 1 | describe('dev-theme', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should have bs3 theme classes', function() { 8 | var s = '[ng-controller="DevTheme"] '; 9 | var a = s + 'a#e-attrs '; 10 | 11 | // click on body 12 | element(a).click(); 13 | expect(element(a).css('display')).toBe('none'); 14 | 15 | expect(element(s+'form .editable-buttons button[type="submit"]').attr('class')).toBe("btn btn-primary"); 16 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 17 | using(s).input('$parent.$data').enter('username2'); 18 | 19 | element('body').click(); 20 | expect(element(a).css('display')).not().toBe('none'); 21 | expect(element(a).text()).toMatch('awesome user'); 22 | expect(element(s+'form').count()).toBe(0); 23 | }); 24 | 25 | it('should have default theme classes', function() { 26 | var s = '[ng-controller="DevTheme"] '; 27 | var a = s + 'a.cancel '; 28 | 29 | expect(element(a).text()).toMatch('awesome user'); 30 | element(a).click(); 31 | 32 | expect(element(s+'form .editable-buttons button[type="submit"]').attr('class')).toBe(undefined); 33 | }); 34 | 35 | it('should have bs2 icons', function() { 36 | var s = '[ng-controller="DevTheme"] '; 37 | var a = s + 'a.bs2-test '; 38 | 39 | expect(element(a).text()).toMatch('awesome user'); 40 | element(a).click(); 41 | 42 | expect(element(s+'form .editable-buttons button[type="submit"] span').attr('class')).toBe('icon-ok icon-white') 43 | }); 44 | 45 | it('should have font-awesome icons', function() { 46 | var s = '[ng-controller="DevTheme"] '; 47 | var a = s + 'a.fa-test '; 48 | 49 | expect(element(a).text()).toMatch('awesome user'); 50 | element(a).click(); 51 | 52 | expect(element(s+'form .editable-buttons button[type="submit"] span').attr('class')).toBe('fa fa-check') 53 | }); 54 | 55 | it('should have bs4 icons', function() { 56 | var s = '[ng-controller="DevTheme"] '; 57 | var a = s + 'a.bs4-test '; 58 | 59 | expect(element(a).text()).toMatch('awesome user'); 60 | element(a).click(); 61 | 62 | expect(element(s+'form .editable-buttons button[type="submit"] span').attr('class')).toBe('fa fa-check') 63 | }); 64 | 65 | }); -------------------------------------------------------------------------------- /docs/demos/dev-theme/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ user.name }} 4 | 5 |   6 | 7 | {{ user.name }} 8 | 9 |   10 | 11 | {{ user.name }} 12 | 13 |   14 | 15 | {{ user.name }} 16 | 17 |   18 | 19 | {{ user.name }} 20 | 21 |
22 | -------------------------------------------------------------------------------- /docs/demos/dev-uiselect/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('DevUiSelectCtrl', function($scope) { 2 | $scope.user = { 3 | state: 'Arizona', 4 | state2: 'Kansas', 5 | tag: [] 6 | }; 7 | 8 | $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']; 9 | 10 | $scope.tags = ['JavaScript', 'Angular', 'TypeScript']; 11 | }); -------------------------------------------------------------------------------- /docs/demos/dev-uiselect/desc.md: -------------------------------------------------------------------------------- 1 | dev -------------------------------------------------------------------------------- /docs/demos/e-single/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('ESingleCtrl', function($scope) { 2 | $scope.user = { 3 | name: 'awesome user' 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/e-single/desc.md: -------------------------------------------------------------------------------- 1 | Add `e-single` attribute when you want a single item to be clickable inside of a form. 2 | It ignores the outer form. -------------------------------------------------------------------------------- /docs/demos/e-single/view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ user.name || 'empty' }} 4 |
5 |
6 | -------------------------------------------------------------------------------- /docs/demos/edit-disabled/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditDisabledCtrl', function($scope) { 2 | $scope.user = { 3 | name: 'awesome user' 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/edit-disabled/desc.md: -------------------------------------------------------------------------------- 1 | To disable an element from being editable, just add the `edit-disabled="true"` attribute. Additionally, you can disable all elements at a global level by setting `editableOptions.isDisabled=true`. -------------------------------------------------------------------------------- /docs/demos/edit-disabled/test.js: -------------------------------------------------------------------------------- 1 | describe('edit-disabled', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should not show editor', function() { 8 | var s = '[ng-controller="EditDisabledCtrl"] '; 9 | 10 | expect(element(s+'a').css('display')).not().toBe('none'); 11 | expect(element(s+'a').text()).toMatch('awesome user'); 12 | element(s+'a').click(); 13 | 14 | expect(element(s+'a').css('display')).not().toBe('none'); 15 | expect(element(s+'a').text()).toBe('username2'); 16 | expect(element(s+'form').count()).toBe(0); 17 | }); 18 | }); -------------------------------------------------------------------------------- /docs/demos/edit-disabled/view.html: -------------------------------------------------------------------------------- 1 |
2 | {{user.name || 'empty' }} 3 |
-------------------------------------------------------------------------------- /docs/demos/editable-column/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditableColumnCtrl', function($scope, $filter, $http, $q) { 2 | $scope.users = [ 3 | {id: 1, name: 'awesome user1', status: 2, group: 4, groupName: 'admin'}, 4 | {id: 2, name: 'awesome user2', status: undefined, group: 3, groupName: 'vip'}, 5 | {id: 3, name: 'awesome user3', status: 2, group: null} 6 | ]; 7 | 8 | $scope.statuses = [ 9 | {value: 1, text: 'status1'}, 10 | {value: 2, text: 'status2'}, 11 | {value: 3, text: 'status3'}, 12 | {value: 4, text: 'status4'} 13 | ]; 14 | 15 | $scope.groups = []; 16 | $scope.loadGroups = function() { 17 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 18 | $scope.groups = data; 19 | }); 20 | }; 21 | 22 | $scope.showGroup = function(user) { 23 | if(user.group && $scope.groups.length) { 24 | var selected = $filter('filter')($scope.groups, {id: user.group}); 25 | return selected.length ? selected[0].text : 'Not set'; 26 | } else { 27 | return user.groupName || 'Not set'; 28 | } 29 | }; 30 | 31 | $scope.showStatus = function(user) { 32 | var selected = []; 33 | if(user.status) { 34 | selected = $filter('filter')($scope.statuses, {value: user.status}); 35 | } 36 | return selected.length ? selected[0].text : 'Not set'; 37 | }; 38 | 39 | $scope.checkName = function(data) { 40 | if (data !== 'awesome') { 41 | return "Username should be `awesome`"; 42 | } 43 | }; 44 | 45 | $scope.saveColumn = function(column) { 46 | var results = []; 47 | angular.forEach($scope.users, function(user) { 48 | results.push($http.post('/saveColumn', {column: column, value: user[column], id: user.id})); 49 | }) 50 | return $q.all(results); 51 | }; 52 | 53 | }); -------------------------------------------------------------------------------- /docs/demos/editable-column/desc.md: -------------------------------------------------------------------------------- 1 | To create editable column in table you should place editable elements in cells with `e-form` attribute pointing to form's name. The form itself can appear in column header or footer. The form behavior is absolutely the same as described in 2 | [Editable form section](#editable-form) 3 | -------------------------------------------------------------------------------- /docs/demos/editable-column/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 20 | 21 | 22 | 36 | 37 | 38 | 52 | 53 | 54 | 55 | 61 | 62 | 68 | 69 | 75 | 76 |
7 | Name 8 |
9 | 12 | 15 |
16 | 19 |
23 | Status 24 |
25 | 28 | 31 |
32 | 35 |
39 | Group 40 |
41 | 44 | 47 |
48 | 51 |
56 | 57 | 58 | {{ user.name || 'empty' }} 59 | 60 | 63 | 64 | 65 | {{ showStatus(user) }} 66 | 67 | 70 | 71 | 72 | {{ showGroup(user) }} 73 | 74 |
77 |
-------------------------------------------------------------------------------- /docs/demos/editable-form/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditableFormCtrl', function($scope, $filter, $http) { 2 | $scope.user = { 3 | id: 1, 4 | name: 'awesome user', 5 | status: 2, 6 | group: 4, 7 | groupName: 'admin' 8 | }; 9 | 10 | $scope.statuses = [ 11 | {value: 1, text: 'status1'}, 12 | {value: 2, text: 'status2'}, 13 | {value: 3, text: 'status3'}, 14 | {value: 4, text: 'status4'} 15 | ]; 16 | 17 | $scope.groups = []; 18 | $scope.loadGroups = function() { 19 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 20 | $scope.groups = data; 21 | }); 22 | }; 23 | 24 | $scope.showGroup = function() { 25 | if($scope.groups.length) { 26 | var selected = $filter('filter')($scope.groups, {id: $scope.user.group}); 27 | return selected.length ? selected[0].text : 'Not set'; 28 | } else { 29 | return $scope.user.groupName; 30 | } 31 | }; 32 | 33 | $scope.checkName = function(data) { 34 | if (data !== 'awesome' && data !== 'error') { 35 | return "Username should be `awesome` or `error`"; 36 | } 37 | }; 38 | 39 | $scope.saveUser = function() { 40 | // $scope.user already updated! 41 | return $http.post('/saveUser', $scope.user).error(function(err) { 42 | if(err.field && err.msg) { 43 | // err like {field: "name", msg: "Server-side error for this username!"} 44 | $scope.editableForm.$setError(err.field, err.msg); 45 | } else { 46 | // unknown error 47 | $scope.editableForm.$setError('name', 'Unknown error!'); 48 | } 49 | }); 50 | }; 51 | }); -------------------------------------------------------------------------------- /docs/demos/editable-form/desc.md: -------------------------------------------------------------------------------- 1 | To show several editable elements together and submit at once you should wrap them into `
` tag. The `name` attribute of form will create variable in scope (normal angular behavior) and `editable-form` attribute will add a few methods to that variable: 2 | 3 | - $show() 4 | - $cancel() 5 | - $visible 6 | - $waiting 7 | 8 | Use it to toggle editable state of form. For example, you can call `myform.$show()`. 9 | 10 | Editable form supports 3 additional attributes: 11 | 12 | - **onshow**: called when form is shown 13 | - **onbeforesave**: called on submit before local models update 14 | - **onaftersave**: called on submit after local models update 15 | 16 | They work nearly the same as for individual editable elements. Use it instead of `ng-submit / submit` to get more control over saving process. 17 | 18 | When you submit editable form it performs following steps: 19 | 20 | 1. call child's `onbeforesave` 21 | 2. call form's `onbeforesave` 22 | 3. write data to local model (e.g. `$scope.user`) 23 | 4. call form's `onaftersave` 24 | 5. call child's `onaftersave` 25 | 26 | Any `onbeforesave / onaftersave` can be omited so in simplest case you will just write data to local model. 27 | 28 | But in more complex case it becomes usefull: 29 | 30 | If you need **validation of individual editable elements** then you should define `onbeforesave` on particular editable element. 31 | The result of child's `onbeforesave` is important for next step: 32 | 33 | - `string`: submit will be cancelled, form will stay opened, string will be shown as error message 34 | - `not string`: submit will be continued 35 | 36 | If you need to **send data on server *before* writing to local model** then you should define form's `onbeforesave`. 37 | The result of form's `onbeforesave` is important for next step: 38 | 39 | - `true` or `undefined`: local model will be updated and form will call `onaftersave` 40 | - `false`: local model **will not be updated** and form will just close (e.g. you update local model yourself) 41 | - `string`: local model **will not be updated** and **form will not close** (e.g. server error) 42 | 43 | 44 | If you need to **send data on server *after* writing to local model** then you should define form's `onaftersave`. 45 | The result of form's `onaftersave` is also important for next step: 46 | 47 | - `string`: form will not close (e.g. server error) 48 | - `not string`: form will be closed 49 | 50 | Commonly you should define `onbeforesave` for child elements to perform validation and `onaftersave` for whole form to send data on server. 51 | 52 | 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. 53 | 54 | Please have a look at examples. -------------------------------------------------------------------------------- /docs/demos/editable-form/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | User name: 6 | {{ user.name || 'empty' }} 7 |
8 | 9 |
10 | 11 | Status: 12 | 13 | {{ (statuses | filter:{value: user.status})[0].text || 'Not set' }} 14 | 15 |
16 | 17 |
18 | 19 | Group: 20 | 21 | {{ showGroup() }} 22 | 23 |
24 | 25 |
26 | 27 | 30 | 31 | 32 | 35 | 38 | 39 |
40 | 41 |
-------------------------------------------------------------------------------- /docs/demos/editable-popover/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditPopoverCtrl', function($scope) { 2 | $scope.user = { 3 | name: 'awesome user' 4 | }; 5 | }); -------------------------------------------------------------------------------- /docs/demos/editable-popover/desc.md: -------------------------------------------------------------------------------- 1 | To make a single editable field display in a pure css popover, wrap the editable in `
`. 2 | -------------------------------------------------------------------------------- /docs/demos/editable-popover/view.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
-------------------------------------------------------------------------------- /docs/demos/editable-row/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditableRowCtrl', function($scope, $filter, $http) { 2 | $scope.users = [ 3 | {id: 1, name: 'awesome user1', status: 2, group: 4, groupName: 'admin'}, 4 | {id: 2, name: 'awesome user2', status: undefined, group: 3, groupName: 'vip'}, 5 | {id: 3, name: 'awesome user3', status: 2, group: null} 6 | ]; 7 | 8 | $scope.statuses = [ 9 | {value: 1, text: 'status1'}, 10 | {value: 2, text: 'status2'}, 11 | {value: 3, text: 'status3'}, 12 | {value: 4, text: 'status4'} 13 | ]; 14 | 15 | $scope.groups = []; 16 | $scope.loadGroups = function() { 17 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 18 | $scope.groups = data; 19 | }); 20 | }; 21 | 22 | $scope.showGroup = function(user) { 23 | if(user.group && $scope.groups.length) { 24 | var selected = $filter('filter')($scope.groups, {id: user.group}); 25 | return selected.length ? selected[0].text : 'Not set'; 26 | } else { 27 | return user.groupName || 'Not set'; 28 | } 29 | }; 30 | 31 | $scope.showStatus = function(user) { 32 | var selected = []; 33 | if(user.status) { 34 | selected = $filter('filter')($scope.statuses, {value: user.status}); 35 | } 36 | return selected.length ? selected[0].text : 'Not set'; 37 | }; 38 | 39 | $scope.checkName = function(data, id) { 40 | if (id === 2 && data !== 'awesome') { 41 | return "Username 2 should be `awesome`"; 42 | } 43 | }; 44 | 45 | $scope.saveUser = function(data, id) { 46 | //$scope.user not updated yet 47 | angular.extend(data, {id: id}); 48 | return $http.post('/saveUser', data); 49 | }; 50 | 51 | // remove user 52 | $scope.removeUser = function(index) { 53 | $scope.users.splice(index, 1); 54 | }; 55 | 56 | // add user 57 | $scope.addUser = function() { 58 | $scope.inserted = { 59 | id: $scope.users.length+1, 60 | name: '', 61 | status: null, 62 | group: null 63 | }; 64 | $scope.users.push($scope.inserted); 65 | }; 66 | }); -------------------------------------------------------------------------------- /docs/demos/editable-row/desc.md: -------------------------------------------------------------------------------- 1 | To create editable row in table you should place editable elements in cells with `e-form` attribute pointing to form's name. The form itself can appear later (e.g. in last column) but it will work. Don't forget to add 2 | `editable-form` attribute to the form. The form behavior is absolutely the same as described in 3 | [Editable form section](#editable-form) 4 | -------------------------------------------------------------------------------- /docs/demos/editable-row/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 16 | 22 | 28 | 43 | 44 |
NameStatusGroupEdit
11 | 12 | 13 | {{ user.name || 'empty' }} 14 | 15 | 17 | 18 | 19 | {{ showStatus(user) }} 20 | 21 | 23 | 24 | 25 | {{ showGroup(user) }} 26 | 27 | 29 | 30 |
31 | 34 | 37 |
38 |
39 | 40 | 41 |
42 |
45 | 46 | 47 |
-------------------------------------------------------------------------------- /docs/demos/editable-table/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('EditableTableCtrl', function($scope, $filter, $http, $q) { 2 | $scope.users = [ 3 | {id: 1, name: 'awesome user1', status: 2, group: 4, groupName: 'admin'}, 4 | {id: 2, name: 'awesome user2', status: undefined, group: 3, groupName: 'vip'}, 5 | {id: 3, name: 'awesome user3', status: 2, group: null} 6 | ]; 7 | 8 | $scope.statuses = [ 9 | {value: 1, text: 'status1'}, 10 | {value: 2, text: 'status2'}, 11 | {value: 3, text: 'status3'}, 12 | {value: 4, text: 'status4'} 13 | ]; 14 | 15 | $scope.groups = []; 16 | $scope.loadGroups = function() { 17 | return $scope.groups.length ? null : $http.get('/groups').success(function(data) { 18 | $scope.groups = data; 19 | }); 20 | }; 21 | 22 | $scope.showGroup = function(user) { 23 | if(user.group && $scope.groups.length) { 24 | var selected = $filter('filter')($scope.groups, {id: user.group}); 25 | return selected.length ? selected[0].text : 'Not set'; 26 | } else { 27 | return user.groupName || 'Not set'; 28 | } 29 | }; 30 | 31 | $scope.showStatus = function(user) { 32 | var selected = []; 33 | if(user.status) { 34 | selected = $filter('filter')($scope.statuses, {value: user.status}); 35 | } 36 | return selected.length ? selected[0].text : 'Not set'; 37 | }; 38 | 39 | $scope.checkName = function(data, id) { 40 | if (id === 2 && data !== 'awesome') { 41 | return "Username 2 should be `awesome`"; 42 | } 43 | }; 44 | 45 | // filter users to show 46 | $scope.filterUser = function(user) { 47 | return user.isDeleted !== true; 48 | }; 49 | 50 | // mark user as deleted 51 | $scope.deleteUser = function(id) { 52 | var filtered = $filter('filter')($scope.users, {id: id}); 53 | if (filtered.length) { 54 | filtered[0].isDeleted = true; 55 | } 56 | }; 57 | 58 | // add user 59 | $scope.addUser = function() { 60 | $scope.users.push({ 61 | id: $scope.users.length+1, 62 | name: '', 63 | status: null, 64 | group: null, 65 | isNew: true 66 | }); 67 | }; 68 | 69 | // cancel all changes 70 | $scope.cancel = function() { 71 | for (var i = $scope.users.length; i--;) { 72 | var user = $scope.users[i]; 73 | // undelete 74 | if (user.isDeleted) { 75 | delete user.isDeleted; 76 | } 77 | // remove new 78 | if (user.isNew) { 79 | $scope.users.splice(i, 1); 80 | } 81 | }; 82 | }; 83 | 84 | // save edits 85 | $scope.saveTable = function() { 86 | var results = []; 87 | for (var i = $scope.users.length; i--;) { 88 | var user = $scope.users[i]; 89 | // actually delete user 90 | if (user.isDeleted) { 91 | $scope.users.splice(i, 1); 92 | } 93 | // mark as not new 94 | if (user.isNew) { 95 | user.isNew = false; 96 | } 97 | 98 | // send on server 99 | results.push($http.post('/saveUser', user)); 100 | } 101 | 102 | return $q.all(results); 103 | }; 104 | }); -------------------------------------------------------------------------------- /docs/demos/editable-table/desc.md: -------------------------------------------------------------------------------- 1 | Just wrap the whole table into `
` tag with `editable-form` attribute. 2 | Note that using `oncancel` hook allows you to revert all changes and put table into original state. -------------------------------------------------------------------------------- /docs/demos/editable-table/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 25 | 31 | 32 | 33 |
NameStatusGroupAction
14 | 15 | 16 | {{ user.name || 'empty' }} 17 | 18 | 20 | 21 | 22 | {{ showStatus(user) }} 23 | 24 | 26 | 27 | 28 | {{ showGroup(user) }} 29 | 30 |
34 | 35 | 36 |
37 | 40 |
41 |
42 | 43 | 44 | 45 |
46 | 47 | 48 |
-------------------------------------------------------------------------------- /docs/demos/html5-inputs/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('Html5InputsCtrl', function($scope) { 2 | $scope.user = { 3 | email: 'email@example.com', 4 | tel: '123-45-67', 5 | number: 29, 6 | range: 10, 7 | url: 'http://example.com', 8 | search: 'blabla', 9 | color: '#6a4415', 10 | date: null, 11 | time: new Date(1970, 0, 1, 12, 30), 12 | month: null, 13 | week: null, 14 | password: 'password', 15 | datetimeLocal: null, 16 | file: null 17 | }; 18 | }); -------------------------------------------------------------------------------- /docs/demos/html5-inputs/desc.md: -------------------------------------------------------------------------------- 1 | Following HTML5 types are supported via `editable-xxx` directive: 2 | 3 | * email 4 | * tel 5 | * number 6 | * search 7 | * range 8 | * url 9 | * color 10 | * date 11 | * time 12 | * month 13 | * week 14 | * password 15 | * datetime-local 16 | 17 | Please [check browser support](http://caniuse.com/) before using particular type in your project. -------------------------------------------------------------------------------- /docs/demos/html5-inputs/test.js: -------------------------------------------------------------------------------- 1 | describe('html5-inputs', function() { 2 | 3 | // var $filter; 4 | 5 | beforeEach(function() { 6 | browser().navigateTo(mainUrl); 7 | }); 8 | 9 | it('should show editor and submit new value', function($filter) { 10 | var s = '[ng-controller="Html5InputsCtrl"] '; 11 | var data0 = { 12 | email: 'email@example.com', 13 | tel: '123-45-67', 14 | number: 29, 15 | range: 10, 16 | url: 'http://example.com', 17 | search: 'blabla', 18 | color: '#6a4415', 19 | date: null, 20 | time: '12:30', 21 | month: null, 22 | week: null, 23 | password: 'password', 24 | 'datetime-local': null, 25 | file: null 26 | }; 27 | 28 | var data1 = { 29 | email: 'email@example1.com', 30 | tel: '123-45-63', 31 | number: 23, 32 | range: 15, 33 | url: 'http://example1.com', 34 | search: 'blabla1', 35 | color: '#000000', 36 | date: null, 37 | time: '12:40', 38 | month: null, 39 | week: null, 40 | password: 'password1', 41 | 'datetime-local': null, 42 | file: null 43 | }; 44 | 45 | function checkValues(data) { 46 | angular.forEach(data, function(v, k) { 47 | var e = s + 'a[editable-'+k+']'; 48 | expect(element(e).css('display')).not().toBe('none'); 49 | 50 | if (k === "time") { 51 | expect(element(e).text()).toMatch(v || 'empty'); 52 | } else { 53 | expect(element(e).text()).toMatch(v || 'empty'); 54 | } 55 | }); 56 | } 57 | 58 | // check initial state 59 | checkValues(data0); 60 | 61 | // change values 62 | angular.forEach(data1, function(v, k) { 63 | var e = s + 'a[editable-'+k+']'; 64 | element(e).click(); 65 | expect(element(e).css('display')).toBe('none'); 66 | expect(element(s+'form input[type="'+k+'"]:visible').count()).toBe(1); 67 | using(s).input('$parent.$data').enter(v); 68 | element(s+'form button[type="submit"]').click(); 69 | expect(element(s+'form input[type="'+k+'"]:visible').count()).toBe(0); 70 | }); 71 | 72 | // check final state 73 | checkValues(data1); 74 | }); 75 | 76 | }); -------------------------------------------------------------------------------- /docs/demos/html5-inputs/view.html: -------------------------------------------------------------------------------- 1 |
2 |
Email: {{ user.email || 'empty' }}
3 |
Tel: {{ user.tel || 'empty' }}
4 |
Number: {{ user.number || 'empty' }}
5 |
Range: {{ user.range || 'empty' }}
6 |
Url: {{ user.url || 'empty' }}
7 |
Search: {{ user.search || 'empty' }}
8 |
Color: {{ user.color || 'empty' }}
9 |
Date: {{ (user.date | date: "yyyy-MM-dd") || 'empty' }}
10 |
Time: {{ (user.time | date: "HH:mm") || 'empty' }}
11 |
Month: {{ (user.month | date: "yyyy-MM") || 'empty' }}
12 |
Week: {{ (user.week | date: "yyyy-Www") || 'empty'}}
13 |
Password: {{ user.password || 'empty' }}
14 |
Datetime-local: {{ (user.datetimeLocal | date: "yyyy-MM-ddTHH:mm:ss") || 'empty' }}
15 |
File: {{ user.file || 'empty' }}
16 |
-------------------------------------------------------------------------------- /docs/demos/ngtags/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('NgTagsCtrl', function($scope, $http) { 2 | $scope.user = { 3 | tags: [ 4 | { text: 'Tag1' }, 5 | { text: 'Tag2' }, 6 | { text: 'Tag3' } 7 | ], 8 | }; 9 | 10 | $scope.loadTags = function(query) { 11 | return $http.get('/tags?query=' + query); 12 | }; 13 | }); -------------------------------------------------------------------------------- /docs/demos/ngtags/desc.md: -------------------------------------------------------------------------------- 1 | ngTagsInput control is implemented via [Tags input directive for AngularJS ](http://mbenford.github.io/ngTagsInput/). 2 | You should include additional `ng-tags-input.min.js` and `ng-tags-input.min.css` and `ng-tags-input.bootstrap.min.css` (if using bootstrap): 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Then add `ngTagsInput` as module dependency: 11 | 12 | var app = angular.module("app", ["xeditable", "ngTagsInput"]); 13 | 14 | And finally set `editable-tags-input` attribute pointing to model and add `editable-tags-input-auto-complete` tag to do the auto complete criteria. -------------------------------------------------------------------------------- /docs/demos/ngtags/view.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{user.tags}} 5 | 6 |
7 |
8 |
9 | 10 | 13 | 14 | 15 |
16 | 19 | 22 |
23 |
24 |
25 |
-------------------------------------------------------------------------------- /docs/demos/onaftersave/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('OnaftersaveCtrl', function($scope, $http) { 2 | $scope.user = { 3 | id: 1, 4 | name: 'awesome user' 5 | }; 6 | 7 | $scope.updateUser = function() { 8 | return $http.post('/updateUser', $scope.user); 9 | }; 10 | }); -------------------------------------------------------------------------------- /docs/demos/onaftersave/desc.md: -------------------------------------------------------------------------------- 1 | Another way to submit data on server is to define `onaftersave` attribute pointing to some method of scope. 2 | Useful when you need to update local model first and only then send it to server. 3 | There are no input parameters as data already in local model. 4 | 5 | The result type of this method can be following: 6 | 7 | - anything except `string`: success, form will be closed 8 | - `string`: error, form will **not** close, string will be shown as error message 9 | 10 | Note that you can use both `onbeforesave` for validation and `onaftersave` for saving data. 11 | -------------------------------------------------------------------------------- /docs/demos/onaftersave/test.js: -------------------------------------------------------------------------------- 1 | describe('onaftersave', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show error for incorrect value and save correct', function() { 8 | var s = '[ng-controller="OnaftersaveCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('awesome user'); 11 | element(s+'a').click(); 12 | 13 | //not valid 14 | using(s).input('$parent.$data').enter('error'); 15 | element(s+'form button[type="submit"]').click(); 16 | 17 | //local model changed 18 | expect(element(s+'a').text()).toMatch('error'); 19 | 20 | //saving 21 | expect(element(s+'a').css('display')).toBe('none'); 22 | expect(element(s+'input[type="text"]:visible:disabled').count()).toBe(1); 23 | expect(element(s+'button:visible:disabled').count()).toBe(2); 24 | expect(element(s+'.editable-error:visible').count()).toBe(0); 25 | 26 | sleep(delay); 27 | 28 | //error shown 29 | expect(element(s+'a').css('display')).toBe('none'); 30 | expect(element(s+'a').text()).toMatch('error'); //local model updated! 31 | expect(element(s+'input[type="text"]:visible:enabled').count()).toBe(1); 32 | expect(element(s+'button:visible:enabled').count()).toBe(2); 33 | expect(element(s+'.editable-error:visible').count()).toBe(1); 34 | expect(element(s+'.editable-error').text()).toMatch('Server-side error'); 35 | 36 | //valid 37 | using(s).input('$parent.$data').enter('awesome'); 38 | element(s+'form button[type="submit"]').click(); 39 | 40 | //local model changed 41 | expect(element(s+'a').text()).toMatch('awesome'); 42 | 43 | //saving 44 | expect(element(s+'a').css('display')).toBe('none'); 45 | expect(element(s+'input[type="text"]:visible:disabled').count()).toBe(1); 46 | expect(element(s+'button:visible:disabled').count()).toBe(2); 47 | expect(element(s+'.editable-error:visible').count()).toBe(0); 48 | 49 | sleep(delay); 50 | 51 | //no error shown, form closed 52 | expect(element(s+'a').css('display')).not().toBe('none'); 53 | expect(element(s+'a').text()).toMatch('awesome'); 54 | expect(element(s+'form').count()).toBe(0); 55 | expect(element(s+'.editable-error').count()).toBe(0); 56 | }); 57 | 58 | }); -------------------------------------------------------------------------------- /docs/demos/onaftersave/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ user.name || 'empty' }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/onbeforesave/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('OnbeforesaveCtrl', function($scope, $http) { 2 | $scope.user = { 3 | id: 1, 4 | name: 'awesome user' 5 | }; 6 | 7 | $scope.updateUser = function(data) { 8 | return $http.post('/updateUser', {id: $scope.user.id, name: data}); 9 | }; 10 | }); -------------------------------------------------------------------------------- /docs/demos/onbeforesave/desc.md: -------------------------------------------------------------------------------- 1 | One way to submit data on server is to define `onbeforesave` attribute pointing to some method of scope. 2 | Useful when you need to send data on server first and only then update local model (e.g. `$scope.user`). 3 | New value can be passed as `$data` parameter (e.g. ``). 4 | 5 | The main thing is that local model will be updated only if method returns `true` or `undefined` (or promise resolved to `true/undefined`). Commonly there are 3 cases depending on result type: 6 | 7 | - `true` or `undefined`: 8 | Success. Local model will be updated automatically and form will close. 9 | - `false`: 10 | Success. But local model will **not** be updated and form will close. Useful when you want to update local model manually (e.g. server changed values). 11 | - `string`: 12 | Error. Local model will **not** be updated, form will **not** close, string will be shown as error message. 13 | Useful for validation and processing errors. 14 | -------------------------------------------------------------------------------- /docs/demos/onbeforesave/test.js: -------------------------------------------------------------------------------- 1 | describe('onbeforesave', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show error for incorrect value and save correct', function() { 8 | var s = '[ng-controller="OnbeforesaveCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('awesome user'); 11 | element(s+'a').click(); 12 | 13 | //not valid 14 | using(s).input('$parent.$data').enter('error'); 15 | element(s+'form button[type="submit"]').click(); 16 | 17 | //saving 18 | expect(element(s+'a').css('display')).toBe('none'); 19 | expect(element(s+'input[type="text"]:visible:disabled').count()).toBe(1); 20 | expect(element(s+'button:visible:disabled').count()).toBe(2); 21 | expect(element(s+'.editable-error:visible').count()).toBe(0); 22 | 23 | sleep(delay); 24 | 25 | //error shown 26 | expect(element(s+'a').css('display')).toBe('none'); 27 | expect(element(s+'a').text()).toMatch('awesome user'); 28 | expect(element(s+'input[type="text"]:visible:enabled').count()).toBe(1); 29 | expect(element(s+'button:visible:enabled').count()).toBe(2); 30 | expect(element(s+'.editable-error:visible').count()).toBe(1); 31 | expect(element(s+'.editable-error').text()).toMatch('Server-side error'); 32 | 33 | //valid 34 | using(s).input('$parent.$data').enter('awesome'); 35 | element(s+'form button[type="submit"]').click(); 36 | 37 | //saving 38 | expect(element(s+'a').css('display')).toBe('none'); 39 | expect(element(s+'input[type="text"]:visible:disabled').count()).toBe(1); 40 | expect(element(s+'button:visible:disabled').count()).toBe(2); 41 | expect(element(s+'.editable-error:visible').count()).toBe(0); 42 | 43 | sleep(delay); 44 | 45 | //no error shown, form closed 46 | expect(element(s+'a').css('display')).not().toBe('none'); 47 | expect(element(s+'a').text()).toMatch('awesome'); 48 | expect(element(s+'form').count()).toBe(0); 49 | expect(element(s+'.editable-error').count()).toBe(0); 50 | }); 51 | 52 | }); -------------------------------------------------------------------------------- /docs/demos/onbeforesave/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ user.name || 'empty' }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/radiolist/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('RadiolistCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | status: 2 4 | }; 5 | 6 | $scope.statuses = [ 7 | {value: 1, text: 'status1'}, 8 | {value: 2, text: 'status2'} 9 | ]; 10 | 11 | $scope.showStatus = function() { 12 | var selected = $filter('filter')($scope.statuses, {value: $scope.user.status}); 13 | return ($scope.user.status && selected.length) ? selected[0].text : 'Not set'; 14 | }; 15 | }); -------------------------------------------------------------------------------- /docs/demos/radiolist/desc.md: -------------------------------------------------------------------------------- 1 | To create list of radios use `editable-radiolist` attribute pointing to model. 2 | Also you should define `e-ng-options` attribute to set value and display items. 3 | By default, radioboxes aligned *horizontally*. To align *vertically* just add following **CSS**: 4 | 5 | .editable-radiolist label { 6 | display: block; 7 | } 8 | -------------------------------------------------------------------------------- /docs/demos/radiolist/test.js: -------------------------------------------------------------------------------- 1 | describe('radiolist', function() { 2 | 3 | beforeEach(function() { 4 | browser().navigateTo(mainUrl); 5 | }); 6 | 7 | it('should show radio options and submit new value', function() { 8 | var s = '[ng-controller="RadiolistCtrl"] '; 9 | 10 | expect(element(s+'a').text()).toMatch('status2'); 11 | element(s+'a').click(); 12 | 13 | expect(element(s+'a').css('display')).toBe('none'); 14 | expect(element(s+'form[editable-form="$form"]').count()).toBe(1); 15 | expect(element(s+'form input[type="radio"]:visible:enabled').count()).toBe(2); 16 | 17 | expect(using(s+'label:eq(0)').input('$parent.$parent.$data').val()).toBe('1'); 18 | expect(using(s+'label:eq(1)').input('$parent.$parent.$data').val()).toBe('2'); 19 | 20 | // select status1 21 | using(s+'label:eq(0)').input('$parent.$parent.$data').select('1'); 22 | element(s+'form button[type="submit"]').click(); 23 | 24 | expect(element(s+'a').css('display')).not().toBe('none'); 25 | expect(element(s+'a').text()).toMatch('status1'); 26 | expect(element(s+'form').count()).toBe(0); 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /docs/demos/radiolist/view.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ showStatus() }} 4 | 5 |
-------------------------------------------------------------------------------- /docs/demos/select-local/controller.js: -------------------------------------------------------------------------------- 1 | app.controller('SelectLocalCtrl', function($scope, $filter) { 2 | $scope.user = { 3 | status: 2 4 | }; 5 | 6 | $scope.statuses = [ 7 | {value: 1, text: 'status1'}, 8 | {value: 2, text: 'status2'}, 9 | {value: 3, text: 'status3'}, 10 | {value: 4, text: 'status4'} 11 | ]; 12 | 13 | $scope.showStatus = function() { 14 | var selected = $filter('filter')($scope.statuses, {value: $scope.user.status}); 15 | return ($scope.user.status && selected.length) ? selected[0].text : 'Not set'; 16 | }; 17 | }); -------------------------------------------------------------------------------- /docs/demos/select-local/desc.md: -------------------------------------------------------------------------------- 1 | To create editable select (dropdown) just set `editable-select` attribute pointing to model. 2 | To pass dropdown options you should define `e-ng-options` attribute 3 | that works like normal angular `ng-options` but is transfered to underlying `', 7 | render: function() { 8 | this.parent.render.call(this); 9 | this.inputEl.wrap(''); 10 | 11 | if (this.attrs.eTitle) { 12 | this.inputEl.parent().append('' + this.attrs.eTitle + ''); 13 | } 14 | }, 15 | autosubmit: function() { 16 | var self = this; 17 | self.inputEl.bind('change', function() { 18 | setTimeout(function() { 19 | self.scope.$apply(function() { 20 | self.scope.$form.$submit(); 21 | }); 22 | }, 500); 23 | }); 24 | } 25 | }); 26 | }]); 27 | -------------------------------------------------------------------------------- /src/js/directives/checklist.js: -------------------------------------------------------------------------------- 1 | // checklist 2 | angular.module('xeditable').directive('editableChecklist', [ 3 | 'editableDirectiveFactory', 4 | 'editableNgOptionsParser', 5 | function(editableDirectiveFactory, editableNgOptionsParser) { 6 | return editableDirectiveFactory({ 7 | directiveName: 'editableChecklist', 8 | inputTpl: '', 9 | useCopy: true, 10 | render: function() { 11 | this.parent.render.call(this); 12 | var parsed = editableNgOptionsParser(this.attrs.eNgOptions), 13 | ngChangeHtml = '', 14 | ngChecklistComparatorHtml = '', 15 | ngDisabled = '', 16 | ngNameHtml = ''; 17 | 18 | if (this.attrs.eNgChange) { 19 | ngChangeHtml = ' ng-change="' + this.attrs.eNgChange + '"'; 20 | } 21 | 22 | if (this.attrs.eChecklistComparator) { 23 | ngChecklistComparatorHtml = ' checklist-comparator="' + this.attrs.eChecklistComparator + '"'; 24 | } 25 | 26 | if (this.attrs.eNgDisabled) { 27 | ngDisabled = ' ng-disabled="' + this.attrs.eNgDisabled+'"'; 28 | } 29 | 30 | if (this.attrs.eName) { 31 | ngNameHtml = ' name="' + this.attrs.eName + '"'; 32 | } 33 | 34 | var html = ''; 38 | 39 | this.inputEl.removeAttr('ng-model'); 40 | this.inputEl.removeAttr('ng-options'); 41 | this.inputEl.removeAttr('ng-change'); 42 | this.inputEl.removeAttr('checklist-comparator'); 43 | this.inputEl.removeAttr('name'); 44 | this.inputEl.html(html); 45 | } 46 | }); 47 | }]); -------------------------------------------------------------------------------- /src/js/directives/combodate.js: -------------------------------------------------------------------------------- 1 | 2 | angular.module('xeditable').directive('editableCombodate', ['editableDirectiveFactory', 'editableCombodate', 3 | function(editableDirectiveFactory, editableCombodate) { 4 | return editableDirectiveFactory({ 5 | directiveName: 'editableCombodate', 6 | inputTpl: '', 7 | render: function() { 8 | this.parent.render.call(this); 9 | 10 | var options = { 11 | value: new Date(this.scope.$data) 12 | }; 13 | var self = this; 14 | angular.forEach(["format", "template", "minYear", "maxYear", "yearDescending", "minuteStep", "secondStep", "firstItem", "errorClass", "customClass", "roundTime", "smartDays"], function(name) { 15 | 16 | var attrName = "e" + name.charAt(0).toUpperCase() + name.slice(1); 17 | 18 | if (attrName in self.attrs) { 19 | if (name == "minYear" || name == "maxYear" || name == "minuteStep" || name == "secondStep") { 20 | options[name] = parseInt(self.attrs[attrName], 10); 21 | } else { 22 | options[name] = self.attrs[attrName]; 23 | } 24 | } 25 | }); 26 | 27 | var combodate = editableCombodate.getInstance(this.inputEl, options); 28 | combodate.$widget.find('select').bind('change', function(e) { 29 | self.scope.$data = combodate.getValue() ? 30 | moment(combodate.getValue(), combodate.options.format).toDate().toISOString() : null; 31 | }).change(); 32 | } 33 | }); 34 | } 35 | ]); -------------------------------------------------------------------------------- /src/js/directives/input.js: -------------------------------------------------------------------------------- 1 | /* 2 | Input types: text|password|email|tel|number|url|search|color|date|datetime|datetime-local|time|month|week|file 3 | */ 4 | 5 | (function() { 6 | 7 | var camelCase = function(dashDelimitedString) { 8 | return dashDelimitedString.toLowerCase().replace(/-(.)/g, function(match, word) { 9 | return word.toUpperCase(); 10 | }); 11 | }; 12 | 13 | var types = 'text|password|email|tel|number|url|search|color|date|datetime|datetime-local|time|month|week|file'.split('|'); 14 | 15 | //todo: datalist 16 | 17 | // generate directives 18 | angular.forEach(types, function(type) { 19 | var directiveName = camelCase('editable' + '-' + type); 20 | angular.module('xeditable').directive(directiveName, ['editableDirectiveFactory', 21 | function(editableDirectiveFactory) { 22 | return editableDirectiveFactory({ 23 | directiveName: directiveName, 24 | inputTpl: '', 25 | render: function() { 26 | this.parent.render.call(this); 27 | 28 | var attrs = this.attrs; 29 | var scope = this.scope; 30 | 31 | //Add bootstrap simple input groups 32 | if (attrs.eInputgroupleft || attrs.eInputgroupright) { 33 | this.inputEl.wrap('
'); 34 | 35 | if (attrs.eInputgroupleft) { 36 | var inputGroupLeft = angular.element(''); 37 | this.inputEl.parent().prepend(inputGroupLeft); 38 | } 39 | 40 | if (attrs.eInputgroupright) { 41 | var inputGroupRight = angular.element(''); 42 | this.inputEl.parent().append(inputGroupRight); 43 | } 44 | } 45 | 46 | // Add label to the input 47 | if (attrs.eLabel) { 48 | var label = angular.element(''); 49 | if (attrs.eInputgroupleft || attrs.eInputgroupright) { 50 | this.inputEl.parent().parent().prepend(label); 51 | } else { 52 | this.inputEl.parent().prepend(label); 53 | } 54 | } 55 | 56 | // Add classes to the form 57 | if (attrs.eFormclass) { 58 | this.editorEl.addClass(attrs.eFormclass); 59 | this.inputEl.removeAttr('formclass'); 60 | } 61 | }, 62 | autosubmit: function() { 63 | var self = this; 64 | self.inputEl.bind('keydown', function(e) { 65 | //submit on tab 66 | if (e.keyCode === 9 && self.editorEl.attr('blur') === 'submit') { 67 | self.scope.$apply(function() { 68 | self.scope.$form.$submit(); 69 | }); 70 | } 71 | }); 72 | } 73 | }); 74 | }]); 75 | }); 76 | 77 | //`range` is bit specific 78 | angular.module('xeditable').directive('editableRange', ['editableDirectiveFactory', '$interpolate', 79 | function(editableDirectiveFactory, $interpolate) { 80 | return editableDirectiveFactory({ 81 | directiveName: 'editableRange', 82 | inputTpl: '', 83 | render: function() { 84 | this.parent.render.call(this); 85 | this.inputEl.after('' + $interpolate.startSymbol() + '$data' + $interpolate.endSymbol() + ''); 86 | } 87 | }); 88 | }]); 89 | 90 | }()); 91 | 92 | -------------------------------------------------------------------------------- /src/js/directives/ngtags.js: -------------------------------------------------------------------------------- 1 | /* 2 | Tags input directive for AngularJS 3 | https://github.com/mbenford/ngTagsInput 4 | */ 5 | angular.module('xeditable').directive('editableTagsInput', ['editableDirectiveFactory', 'editableUtils', 6 | function(editableDirectiveFactory, editableUtils) { 7 | var dir = editableDirectiveFactory({ 8 | directiveName: 'editableTagsInput', 9 | inputTpl: '', 10 | useCopy: true, 11 | render: function () { 12 | this.parent.render.call(this); 13 | this.inputEl.append(editableUtils.rename('auto-complete', this.attrs.$autoCompleteElement)); 14 | this.inputEl.removeAttr('ng-model'); 15 | this.inputEl.attr('ng-model', '$parent.$data'); 16 | } 17 | }); 18 | 19 | var linkOrg = dir.link; 20 | 21 | dir.link = function (scope, el, attrs, ctrl) { 22 | var autoCompleteEl = el.find('editable-tags-input-auto-complete'); 23 | 24 | attrs.$autoCompleteElement = autoCompleteEl.clone(); 25 | 26 | autoCompleteEl.remove(); 27 | 28 | return linkOrg(scope, el, attrs, ctrl); 29 | }; 30 | 31 | return dir; 32 | }]); -------------------------------------------------------------------------------- /src/js/directives/radiolist.js: -------------------------------------------------------------------------------- 1 | // radiolist 2 | angular.module('xeditable').directive('editableRadiolist', [ 3 | 'editableDirectiveFactory', 4 | 'editableNgOptionsParser', 5 | '$interpolate', 6 | function(editableDirectiveFactory, editableNgOptionsParser, $interpolate) { 7 | return editableDirectiveFactory({ 8 | directiveName: 'editableRadiolist', 9 | inputTpl: '', 10 | render: function() { 11 | this.parent.render.call(this); 12 | var parsed = editableNgOptionsParser(this.attrs.eNgOptions), 13 | ngChangeHtml = '', 14 | ngNameHtml = '', 15 | ngValueFn = isNaN(parsed.locals.valueFn) ? "'" + parsed.locals.valueFn + "'" : parsed.locals.valueFn, 16 | ngDisabled = this.attrs.eNgDisabled ? this.attrs.eNgDisabled : false; 17 | 18 | if (this.attrs.eNgChange) { 19 | ngChangeHtml = ' ng-change="' + this.attrs.eNgChange + '"'; 20 | } 21 | 22 | if (this.attrs.eName) { 23 | ngNameHtml = ' name="' + this.attrs.eName + '"'; 24 | } 25 | 26 | var html = ''; 33 | 34 | this.inputEl.removeAttr('ng-model'); 35 | this.inputEl.removeAttr('ng-options'); 36 | this.inputEl.removeAttr('ng-change'); 37 | this.inputEl.html(html); 38 | }, 39 | autosubmit: function() { 40 | var self = this; 41 | self.inputEl.bind('change', function() { 42 | setTimeout(function() { 43 | self.scope.$apply(function() { 44 | self.scope.$form.$submit(); 45 | }); 46 | }, 500); 47 | }); 48 | } 49 | }); 50 | }]); 51 | -------------------------------------------------------------------------------- /src/js/directives/select.js: -------------------------------------------------------------------------------- 1 | //select 2 | angular.module('xeditable').directive('editableSelect', ['editableDirectiveFactory', 3 | function(editableDirectiveFactory) { 4 | return editableDirectiveFactory({ 5 | directiveName: 'editableSelect', 6 | inputTpl: '', 7 | render: function() { 8 | this.parent.render.call(this); 9 | 10 | if (this.attrs.ePlaceholder) { 11 | var placeholder = angular.element(''); 12 | this.inputEl.append(placeholder); 13 | } 14 | }, 15 | autosubmit: function() { 16 | var self = this; 17 | 18 | if (!self.attrs.hasOwnProperty("eMultiple")) { 19 | self.inputEl.bind('change', function () { 20 | self.scope.$apply(function () { 21 | self.scope.$form.$submit(); 22 | }); 23 | }); 24 | } 25 | } 26 | }); 27 | }]); -------------------------------------------------------------------------------- /src/js/directives/textarea.js: -------------------------------------------------------------------------------- 1 | //textarea 2 | angular.module('xeditable').directive('editableTextarea', ['editableDirectiveFactory', 3 | function(editableDirectiveFactory) { 4 | return editableDirectiveFactory({ 5 | directiveName: 'editableTextarea', 6 | inputTpl: '', 7 | render: function() { 8 | this.parent.render.call(this); 9 | 10 | // Add classes to the form 11 | if (this.attrs.eFormclass) { 12 | this.editorEl.addClass(this.attrs.eFormclass); 13 | this.inputEl.removeAttr('formclass'); 14 | } 15 | }, 16 | addListeners: function() { 17 | var self = this; 18 | self.parent.addListeners.call(self); 19 | // submit textarea by ctrl+enter even with buttons 20 | if (self.single && self.buttons !== 'no') { 21 | self.autosubmit(); 22 | } 23 | }, 24 | autosubmit: function() { 25 | var self = this; 26 | self.inputEl.bind('keydown', function(e) { 27 | if (self.attrs.submitOnEnter) { 28 | if (e.keyCode === 13 && !e.shiftKey) { 29 | self.scope.$apply(function() { 30 | self.scope.$form.$submit(); 31 | }); 32 | } 33 | } else if ((e.ctrlKey || e.metaKey) && (e.keyCode === 13) || 34 | (e.keyCode === 9 && self.editorEl.attr('blur') === 'submit')) { 35 | self.scope.$apply(function() { 36 | self.scope.$form.$submit(); 37 | }); 38 | } 39 | }); 40 | } 41 | }); 42 | }]); 43 | -------------------------------------------------------------------------------- /src/js/directives/uidate.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery UI Datepicker for AngularJS 3 | https://github.com/angular-ui/ui-date 4 | */ 5 | angular.module('xeditable').directive('editableUidate', ['editableDirectiveFactory', 6 | function(editableDirectiveFactory) { 7 | return editableDirectiveFactory({ 8 | directiveName: 'editableUidate', 9 | inputTpl: '', 10 | render: function() { 11 | this.parent.render.call(this); 12 | this.inputEl.attr('ui-date', this.attrs.eUiDate); 13 | this.inputEl.attr('placeholder', this.attrs.ePlaceholder); 14 | } 15 | }); 16 | }]); 17 | -------------------------------------------------------------------------------- /src/js/directives/uiselect.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS-native version of Select2 and Selectize 3 | https://github.com/angular-ui/ui-select 4 | */ 5 | angular.module('xeditable').directive('editableUiSelect',['editableDirectiveFactory', 'editableUtils', 6 | function(editableDirectiveFactory, editableUtils) { 7 | var dir = editableDirectiveFactory({ 8 | directiveName: 'editableUiSelect', 9 | inputTpl: '', 10 | render: function () { 11 | this.parent.render.call(this); 12 | this.inputEl.append(editableUtils.rename('ui-select-match', this.attrs.$matchElement)); 13 | this.inputEl.append(editableUtils.rename('ui-select-choices', this.attrs.$choicesElement)); 14 | this.inputEl.removeAttr('ng-model'); 15 | this.inputEl.attr('ng-model', '$parent.$parent.$data'); 16 | }, 17 | autosubmit: function() { 18 | var self = this; 19 | self.inputEl.bind('change', function() { 20 | setTimeout(function() { 21 | self.scope.$apply(function() { 22 | self.scope.$form.$submit(); 23 | }); 24 | }, 500); 25 | }); 26 | 27 | self.inputEl.bind('keydown', function(e) { 28 | //submit on tab 29 | if (e.keyCode === 9 && self.editorEl.attr('blur') === 'submit') { 30 | self.scope.$apply(function() { 31 | self.scope.$form.$submit(); 32 | }); 33 | } 34 | }); 35 | } 36 | }); 37 | 38 | var linkOrg = dir.link; 39 | 40 | dir.link = function (scope, el, attrs, ctrl) { 41 | var matchEl = el.find('editable-ui-select-match'); 42 | var choicesEl = el.find('editable-ui-select-choices'); 43 | 44 | attrs.$matchElement = matchEl.clone(); 45 | attrs.$choicesElement = choicesEl.clone(); 46 | 47 | matchEl.remove(); 48 | choicesEl.remove(); 49 | 50 | return linkOrg(scope, el, attrs, ctrl); 51 | }; 52 | 53 | return dir; 54 | }]); -------------------------------------------------------------------------------- /src/js/icons.js: -------------------------------------------------------------------------------- 1 | /* 2 | Editable icons: 3 | - default 4 | - font-awesome 5 | 6 | */ 7 | angular.module('xeditable').factory('editableIcons', function() { 8 | 9 | var icons = { 10 | //Icon-set to use, defaults to bootstrap icons 11 | default: { 12 | 'bs2': { 13 | ok: 'icon-ok icon-white', 14 | cancel: 'icon-remove', 15 | clear: 'icon-trash', 16 | calendar: 'icon-calendar' 17 | }, 18 | 'bs3': { 19 | ok: 'glyphicon glyphicon-ok', 20 | cancel: 'glyphicon glyphicon-remove', 21 | clear: 'glyphicon glyphicon-trash', 22 | calendar: 'glyphicon glyphicon-calendar' 23 | }, 24 | 'bs4': { 25 | ok: 'fa fa-check', 26 | cancel: 'fa fa-times', 27 | clear: 'fa fa-trash', 28 | calendar: 'fa fa-calendar' 29 | } 30 | }, 31 | external: { 32 | 'font-awesome': { 33 | ok: 'fa fa-check', 34 | cancel: 'fa fa-times', 35 | clear: 'fa fa-trash', 36 | calendar: 'fa fa-calendar' 37 | } 38 | } 39 | }; 40 | 41 | return icons; 42 | }); 43 | -------------------------------------------------------------------------------- /starter/angular-xeditable/css/xeditable.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | angular-xeditable - 0.10.2 3 | Edit-in-place for angular.js 4 | Build date: 2019-11-01 5 | */ 6 | 7 | .editable-wrap{display:inline-block;white-space:pre;margin:0}.editable-wrap .editable-controls,.editable-wrap .editable-error{margin-bottom:0}.editable-wrap .editable-controls>input,.editable-wrap .editable-controls>select,.editable-wrap .editable-controls>textarea{margin-bottom:0}.editable-wrap .editable-input{display:inline-block}.editable-buttons{display:inline-block;vertical-align:top}.editable-buttons button{margin-left:5px}.editable-input.editable-has-buttons{width:auto}.editable-text{white-space:nowrap}.editable-bsdate{white-space:nowrap}.editable-bstime{white-space:nowrap}.editable-bstime .editable-input input[type=text]{width:46px}.editable-bstime .well-small{margin-bottom:0;padding:10px}.editable-range output{display:inline-block;min-width:30px;vertical-align:top;text-align:center}.editable-color input[type=color]{width:50px}.editable-checkbox label span,.editable-checklist label span,.editable-radiolist label span{margin-left:7px;margin-right:10px}.editable-hide{display:none!important}.editable-click,a.editable-click{text-decoration:none;color:#428bca;border-bottom:dashed 1px #428bca}.editable-click:hover,a.editable-click:hover{text-decoration:none;color:#2a6496;border-bottom-color:#2a6496}.editable-empty,.editable-empty:hover,.editable-empty:focus,a.editable-empty,a.editable-empty:hover,a.editable-empty:focus{font-style:italic;color:#D14;text-decoration:none}.ui-popover-wrapper a{display:inline!important}.ui-popover-wrapper form{display:none!important}.popover-wrapper>a{display:inline!important}.popover-wrapper{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%;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}.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}@media screen and (max-width:750px){.popover-wrapper form{margin-left:-60px}.popover-wrapper form:before{left:50px}.popover-wrapper form:after{left:51px}}@media screen and (min-width:750px){.popover-wrapper form{margin-left:-110px}.popover-wrapper form:before{left:100px}.popover-wrapper form:after{left:101px}} -------------------------------------------------------------------------------- /starter/app.js: -------------------------------------------------------------------------------- 1 | var app = angular.module("app", ["xeditable"]); 2 | 3 | app.run(function(editableOptions) { 4 | editableOptions.theme = 'bs3'; // bootstrap3 theme. Can be also 'bs2', 'bs3', 'default' 5 | }); 6 | 7 | app.controller('Ctrl', function($scope) { 8 | $scope.user = { 9 | name: 'awesome user' 10 | }; 11 | }); -------------------------------------------------------------------------------- /starter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Angular-xeditable Starter Template 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Angular-xeditable Starter Template

20 |
21 | 22 | {{ user.name || "empty" }} 23 |
24 | {{ user | json }} 25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /test/e2e/dev-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dev Test Runner 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/e2e/docs-test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Docs Test Runner 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.1.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.10.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.10.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.11.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.11.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.12.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.12.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.2.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.3.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.4.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.5.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.6.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.6.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.7.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.8.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.8.1.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.8.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.8.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.1.9.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.1.9.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.10.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.10.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.10.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.10.1.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.10.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.10.2.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.2.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.3.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.3.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.4.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.4.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.5.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.5.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.6.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.6.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.7.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.7.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.7.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.7.1.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.8.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.8.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.8.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.8.1.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-0.9.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-0.9.0.zip -------------------------------------------------------------------------------- /zip/angular-xeditable-starter.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vitalets/angular-xeditable/40c4dfbfa33e396a263ed8c120bd17853256e1b6/zip/angular-xeditable-starter.zip --------------------------------------------------------------------------------