├── .eslintignore
├── .bowerrc
├── docs
├── font
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.ttf
│ └── fontawesome-webfont.woff
├── partials
│ └── api
│ │ ├── mdtHeaderRow.html
│ │ ├── mdtRow.html
│ │ ├── mdtCell.html
│ │ └── mdtColumn.html
├── css
│ ├── animations.css
│ ├── prettify.css
│ ├── doc_widgets.css
│ └── docs.css
└── js
│ └── docs-setup.js
├── .csslintrc
├── .gitignore
├── index.js
├── app
├── modules
│ ├── main
│ │ ├── templates
│ │ │ ├── cells
│ │ │ │ ├── generateCheckboxCell.html
│ │ │ │ ├── generateCellValue.html
│ │ │ │ ├── generateSortingIcons.html
│ │ │ │ └── generateCell.html
│ │ │ ├── rows
│ │ │ │ ├── errorIndicator.html
│ │ │ │ ├── noResultIndicator.html
│ │ │ │ ├── generateRowsVirtualRepeat.html
│ │ │ │ └── generateRows.html
│ │ │ ├── generateTable.html
│ │ │ ├── mdtAlternateHeaders.html
│ │ │ ├── smallEditDialog.html
│ │ │ ├── mdtGeneratedHeaderRow.html
│ │ │ ├── mdtCardHeader.html
│ │ │ ├── largeEditDialog.html
│ │ │ ├── mdtTable.html
│ │ │ ├── mdtDropdownColumnFilter.html
│ │ │ ├── mdtCardFooter.html
│ │ │ ├── mdtColumnSelector.html
│ │ │ ├── mdtCheckboxColumnFilter.html
│ │ │ ├── mdtChipsColumnFilter.html
│ │ │ └── mdtGeneratedHeaderCellContent.html
│ │ ├── factories
│ │ │ ├── mdtLodashFactory.js
│ │ │ ├── mdtPaginationHelperFactory.js
│ │ │ ├── TableDataStorageFactory.js
│ │ │ └── mdtAjaxPaginationHelperFactory.js
│ │ ├── directives
│ │ │ ├── header
│ │ │ │ ├── mdtGeneratedHeaderRowDirective.js
│ │ │ │ ├── mdtGeneratedHeaderCellContentDirective.js
│ │ │ │ ├── mdtHeaderRowDirective.js
│ │ │ │ └── mdtColumnDirective.js
│ │ │ ├── helpers
│ │ │ │ ├── mdtAnimateSortIconHandlerDirective.js
│ │ │ │ ├── mdtAddAlignClass.js
│ │ │ │ ├── mdtSelectAllRowsHandlerDirective.js
│ │ │ │ ├── mdtCustomCellDirective.js
│ │ │ │ └── mdtAddHtmlContentToCellDirective.js
│ │ │ ├── tablecard
│ │ │ │ ├── mdtCardFooterDirective.js
│ │ │ │ └── mdtCardHeaderDirective.js
│ │ │ ├── mdtAlternateHeadersDirective.js
│ │ │ └── body
│ │ │ │ ├── mdtRowDirective.js
│ │ │ │ └── mdtCellDirective.js
│ │ ├── providers
│ │ │ ├── PaginatorTypeProvider.js
│ │ │ └── ColumnOptionsProvider.js
│ │ ├── features
│ │ │ ├── ColumnSortFeature
│ │ │ │ ├── providers
│ │ │ │ │ └── ColumnSortDirection.js
│ │ │ │ ├── directive
│ │ │ │ │ └── mdtSortingIconsDirective.js
│ │ │ │ └── ColumnSortFeature.js
│ │ │ ├── SelectableRowsFeature.js
│ │ │ ├── EditCellFeature
│ │ │ │ └── EditCellFeature.js
│ │ │ ├── PaginationFeature.js
│ │ │ ├── ColumnFilterFeature
│ │ │ │ ├── directives
│ │ │ │ │ ├── mdtChipsColumnFilterDirective.js
│ │ │ │ │ ├── mdtDropdownColumnFilterDirective.js
│ │ │ │ │ └── mdtCheckboxColumnFilterDirective.js
│ │ │ │ └── ColumnFilterFeature.js
│ │ │ └── ColumnSelectorFeature
│ │ │ │ ├── ColumnSelectorFeature.js
│ │ │ │ └── directives
│ │ │ │ └── mdtColumnSelectorDirective.js
│ │ ├── helpers
│ │ │ └── ColumnAlignmentHelper.js
│ │ └── controllers
│ │ │ └── InlineEditModalCtrl.js
│ └── app.js
└── scss
│ └── main.scss
├── .travis.yml
├── test
├── helpers
│ └── environment.js
├── karma.conf.js
├── karma.unit.conf.js
└── unit
│ └── modules
│ ├── features
│ ├── PaginationFeatureTest.js
│ ├── EditCellFeature
│ │ └── EditCellFeatureTest.js
│ ├── ColumnSortFeature
│ │ └── ColumnSortFeatureTest.js
│ └── ColumnFilterFeature
│ │ └── directives
│ │ ├── mdtChipsColumnFilterDirectiveTest.js
│ │ └── mdtDropdownColumnFilterDirectiveTest.js
│ └── directives
│ ├── body
│ └── mdDataTableCellDirectiveTest.js
│ ├── mdDataTableDirectiveTest.js
│ └── header
│ └── mdDataTableColumnDirectiveTest.js
├── gulp-tasks
├── lint.js
├── test.js
├── gulp-utils.js
├── templates.js
├── compass.js
├── dist.js
├── index.js
└── copy.js
├── jsdocConf.json
├── .codeclimate.yml
├── .jshintrc
├── LICENSE
├── bower.json
├── gulpfile.js
├── wallaby.js
├── package.json
├── demo
├── developmentArea.html
├── index.html
└── demoApp.js
└── .eslintrc
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "app/bower_components"
3 | }
--------------------------------------------------------------------------------
/docs/font/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamisti/mdDataTable/HEAD/docs/font/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/font/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamisti/mdDataTable/HEAD/docs/font/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/font/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamisti/mdDataTable/HEAD/docs/font/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/font/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamisti/mdDataTable/HEAD/docs/font/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/.csslintrc:
--------------------------------------------------------------------------------
1 | --exclude-exts=.min.css
2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .sass-cache
2 | app/bower_components
3 | dist/main.css
4 | build
5 | node_modules
6 | reports
7 | typings
8 | .idea
9 | coverage
10 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require('angular-material-icons');
2 | require('./dist/md-data-table-templates.js');
3 | require('./dist/md-data-table.js');
4 |
5 | module.exports = 'mdDataTable';
6 |
--------------------------------------------------------------------------------
/app/modules/main/templates/cells/generateCheckboxCell.html:
--------------------------------------------------------------------------------
1 |
mdtHeaderRow
2 | Representing a header row which should be placed inside mdt-table element directive.
7 | The main responsibility of this directive is to execute all the transcluded mdt-column element directives.
mdtTable
11 | <mdt-header-row> 15 | </mdt-header-row>16 |
mdtRow
2 | Representing a row which should be placed inside mdt-table element directive.
Please note the following: This element has limited functionality. It cannot listen on data changes that happens outside of the 8 | component. E.g.: if you provide an ng-repeat to generate your data rows for the table, using this directive, 9 | it won't work well if this data will change. Since the way how transclusions work, it's (with my best 10 | knowledge) an impossible task to solve at the moment. If you intend to use dynamic data rows, it's still 11 | possible with using mdtRow attribute of mdtTable.
12 |mdtTable
15 | <mdt-row
19 | [table-row-id="{string|integer}"]>
20 | </mdt-row>
21 | | Param | Type | Details |
|---|---|---|
| tableRowId (optional) | stringinteger | when set table will have a uniqe id. In case of deleting a row will give 22 | back this id. 23 | |
26 | <mdt-table>
27 | <mdt-header-row>
28 | <mdt-column>Product name</mdt-column>
29 | <mdt-column>Price</mdt-column>
30 | </mdt-header-row>
31 |
32 | <mdt-row
33 | ng-repeat="product in products"
34 | table-row-id="{{product.id}}">
35 | <mdt-cell>{{product.name}}</mdt-cell>
36 | <mdt-cell>{{product.price}}</mdt-cell>
37 | </mdt-row>
38 | </mdt-table>
39 |
40 | 24 | *38 | */ 39 | function mdtRowDirective(){ 40 | return { 41 | restrict: 'E', 42 | transclude: true, 43 | require: '^mdtTable', 44 | scope: { 45 | tableRowId: '=' 46 | }, 47 | controller: function($scope){ 48 | var vm = this; 49 | 50 | vm.addToRowDataStorage = addToRowDataStorage; 51 | $scope.rowDataStorage = []; 52 | 53 | function addToRowDataStorage(value, attributes){ 54 | $scope.rowDataStorage.push({value: value, attributes: attributes}); 55 | } 56 | }, 57 | link: function($scope, element, attrs, ctrl, transclude){ 58 | appendColumns(); 59 | 60 | ctrl.dataStorage.addRowData($scope.tableRowId, $scope.rowDataStorage); 61 | 62 | function appendColumns(){ 63 | transclude(function (clone) { 64 | element.append(clone); 65 | }); 66 | } 67 | } 68 | }; 69 | } 70 | 71 | angular 72 | .module('mdDataTable') 73 | .directive('mdtRow', mdtRowDirective); 74 | }()); -------------------------------------------------------------------------------- /app/modules/main/features/ColumnFilterFeature/directives/mdtDropdownColumnFilterDirective.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function mdtDropdownColumnFilterDirective(ColumnFilterFeature, ColumnSortFeature){ 5 | return{ 6 | restrict: 'E', 7 | templateUrl: '/main/templates/mdtDropdownColumnFilter.html', 8 | scope: { 9 | confirmCallback: '=', 10 | cancelCallback: '&', 11 | headerRowData: '=' 12 | }, 13 | link: function($scope, element){ 14 | ColumnFilterFeature.positionColumnFilterBox(element); 15 | 16 | $scope.transformChip = transformChip; 17 | $scope.selectedItem = selectedItem; 18 | 19 | $scope.selectableItems = []; 20 | $scope.selectedItems = _.map($scope.headerRowData.columnFilter.filtersApplied, _.clone); 21 | $scope.oneSelectedItem = $scope.selectedItems.length ? transformChip($scope.selectedItems[0]) : undefined; 22 | $scope.placeholderText = $scope.headerRowData.columnFilter.placeholderText || 'Choose a value'; 23 | 24 | //TODO: simplify structure 25 | $scope.sortingData = { 26 | columnSort: { 27 | sort: $scope.headerRowData.columnSort.sort 28 | } 29 | }; 30 | $scope.sortingCallback = ColumnSortFeature.sortingCallback; 31 | 32 | //destroying scope doesn't remove element, since it belongs to the body directly 33 | $scope.$on('$destroy', function(){ 34 | element.remove(); 35 | }); 36 | 37 | //populating choosable values 38 | $scope.headerRowData.columnFilter.valuesProviderCallback().then(function(values){ 39 | if(values){ 40 | $scope.selectableItems = values; 41 | } 42 | }); 43 | 44 | function transformChip(chip) { 45 | if($scope.headerRowData.columnFilter.valuesTransformerCallback){ 46 | return $scope.headerRowData.columnFilter.valuesTransformerCallback(chip); 47 | } 48 | 49 | return chip; 50 | } 51 | 52 | function selectedItem(){ 53 | if(typeof $scope.oneSelectedItem !== 'undefined'){ 54 | var result = _.find($scope.selectableItems, function(anItem){ 55 | return transformChip(anItem) === $scope.oneSelectedItem 56 | }); 57 | 58 | if(result){ 59 | $scope.selectedItems = [result]; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | angular 68 | .module('mdDataTable') 69 | .directive('mdtDropdownColumnFilter', mdtDropdownColumnFilterDirective); 70 | })(); -------------------------------------------------------------------------------- /docs/partials/api/mdtCell.html: -------------------------------------------------------------------------------- 1 |25 | * 37 | *26 | * 29 | * 30 | *Product name 27 | *Price 28 | *33 | * 36 | *{{product.name}} 34 | *{{product.price}} 35 | *
mdtCell
2 | Representing a cell which should be placed inside mdt-row element directive.
<mdt-cell
16 | [html-content="{boolean}"]
17 | [editable-field="{string}"]
18 | [editable-field-title="{string}"]
19 | [editable-field-max-length="{number}"]>
20 | </mdt-cell>
21 | | Param | Type | Details |
|---|---|---|
| htmlContent (optional) | boolean | if set to true, then html content can be placed into the content of the directive. 22 | |
| editableField (optional) | string | if set, then content can be editable. 23 | |
| editableFieldTitle (optional) | string | if set, then it sets the title of the dialog. (only for |
| editableFieldMaxLength (optional) | number | if set, then it sets the maximum length of the field. 29 | |
32 | <mdt-table>
33 | <mdt-header-row>
34 | <mdt-column>Product name</mdt-column>
35 | <mdt-column>Price</mdt-column>
36 | <mdt-column>Details</mdt-column>
37 | </mdt-header-row>
38 |
39 | <mdt-row ng-repeat="product in ctrl.products">
40 | <mdt-cell>{{product.name}}</mdt-cell>
41 | <mdt-cell>{{product.price}}</mdt-cell>
42 | <mdt-cell html-content="true">
43 | <a href="productdetails/{{product.id}}">more details</a>
44 | </mdt-cell>
45 | </mdt-row>
46 | </mdt-table>
47 |
48 | 28 | *44 | */ 45 | function mdtCellDirective($interpolate){ 46 | return { 47 | restrict: 'E', 48 | replace: true, 49 | transclude: true, 50 | require: '^mdtRow', 51 | link: function($scope, element, attr, mdtRowCtrl, transclude){ 52 | 53 | var attributes = { 54 | htmlContent: attr.htmlContent ? attr.htmlContent : false, 55 | editableField: attr.editableField ? attr.editableField : false, 56 | editableFieldTitle: attr.editableFieldTitle ? attr.editableFieldTitle : false, 57 | editableFieldMaxLength: attr.editableFieldMaxLength ? attr.editableFieldMaxLength : false 58 | }; 59 | 60 | transclude(function (clone) { 61 | 62 | if(attr.htmlContent){ 63 | mdtRowCtrl.addToRowDataStorage(clone, attributes); 64 | }else{ 65 | //TODO: better idea? 66 | var cellValue = $interpolate(clone.html())($scope.$parent); 67 | 68 | mdtRowCtrl.addToRowDataStorage(cellValue, attributes); 69 | } 70 | }); 71 | } 72 | }; 73 | } 74 | 75 | angular 76 | .module('mdDataTable') 77 | .directive('mdtCell', mdtCellDirective); 78 | }()); -------------------------------------------------------------------------------- /app/modules/main/factories/mdtPaginationHelperFactory.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | function mdtPaginationHelperFactory(PaginatorTypeProvider, _){ 5 | 6 | function mdtPaginationHelper(dataStorage, paginationSetting){ 7 | this.paginatorType = PaginatorTypeProvider.ARRAY; 8 | 9 | this.dataStorage = dataStorage; 10 | 11 | if(paginationSetting && 12 | paginationSetting.hasOwnProperty('rowsPerPageValues') && 13 | paginationSetting.rowsPerPageValues.length > 0){ 14 | 15 | this.rowsPerPageValues = paginationSetting.rowsPerPageValues; 16 | }else{ 17 | this.rowsPerPageValues = [10,20,30,50,100]; 18 | } 19 | 20 | this.rowsPerPage = this.rowsPerPageValues[0]; 21 | this.page = 1; 22 | } 23 | 24 | mdtPaginationHelper.prototype.calculateVisibleRows = function (){ 25 | var that = this; 26 | 27 | _.each(this.dataStorage.storage, function (rowData, index) { 28 | if(index >= that.getStartRowIndex() && index <= that.getEndRowIndex()) { 29 | rowData.optionList.visible = true; 30 | } else { 31 | rowData.optionList.visible = false; 32 | } 33 | }); 34 | }; 35 | 36 | mdtPaginationHelper.prototype.getStartRowIndex = function(){ 37 | return (this.page-1) * this.rowsPerPage; 38 | }; 39 | 40 | mdtPaginationHelper.prototype.getEndRowIndex = function(){ 41 | var lastItem = this.getStartRowIndex() + this.rowsPerPage-1; 42 | 43 | if(this.dataStorage.storage.length < lastItem){ 44 | return this.dataStorage.storage.length - 1; 45 | } 46 | 47 | return lastItem; 48 | }; 49 | 50 | mdtPaginationHelper.prototype.getTotalRowsCount = function(){ 51 | return this.dataStorage.storage.length; 52 | }; 53 | 54 | mdtPaginationHelper.prototype.getRows = function(){ 55 | this.calculateVisibleRows(); 56 | 57 | return this.dataStorage.storage; 58 | }; 59 | 60 | mdtPaginationHelper.prototype.previousPage = function(){ 61 | if(this.hasPreviousPage()){ 62 | this.page--; 63 | } 64 | }; 65 | 66 | mdtPaginationHelper.prototype.nextPage = function(){ 67 | if(this.hasNextPage()){ 68 | this.page++; 69 | } 70 | }; 71 | 72 | mdtPaginationHelper.prototype.hasNextPage = function(){ 73 | var totalPages = Math.ceil(this.getTotalRowsCount() / this.rowsPerPage); 74 | 75 | return this.page < totalPages; 76 | }; 77 | 78 | mdtPaginationHelper.prototype.hasPreviousPage = function(){ 79 | return this.page > 1; 80 | }; 81 | 82 | mdtPaginationHelper.prototype.setRowsPerPage = function(rowsPerPage){ 83 | this.rowsPerPage = rowsPerPage; 84 | this.page = 1; 85 | }; 86 | 87 | return { 88 | getInstance: function(dataStorage, isEnabled){ 89 | return new mdtPaginationHelper(dataStorage, isEnabled); 90 | } 91 | }; 92 | } 93 | 94 | angular 95 | .module('mdDataTable') 96 | .service('mdtPaginationHelperFactory', mdtPaginationHelperFactory); 97 | }()); -------------------------------------------------------------------------------- /docs/css/doc_widgets.css: -------------------------------------------------------------------------------- 1 | ul.doc-example { 2 | list-style-type: none; 3 | position: relative; 4 | font-size: 14px; 5 | } 6 | 7 | ul.doc-example > li { 8 | border: 2px solid gray; 9 | border-radius: 5px; 10 | -moz-border-radius: 5px; 11 | -webkit-border-radius: 5px; 12 | background-color: white; 13 | margin-bottom: 20px; 14 | } 15 | 16 | ul.doc-example > li.doc-example-heading { 17 | border: none; 18 | border-radius: 0; 19 | margin-bottom: -10px; 20 | } 21 | 22 | span.nojsfiddle { 23 | float: right; 24 | font-size: 14px; 25 | margin-right:10px; 26 | margin-top: 10px; 27 | } 28 | 29 | form.jsfiddle { 30 | position: absolute; 31 | right: 0; 32 | z-index: 1; 33 | height: 14px; 34 | } 35 | 36 | form.jsfiddle button { 37 | cursor: pointer; 38 | padding: 4px 10px; 39 | margin: 10px; 40 | background-color: #FFF; 41 | font-weight: bold; 42 | color: #7989D6; 43 | border-color: #7989D6; 44 | -moz-border-radius: 8px; 45 | -webkit-border-radius:8px; 46 | border-radius: 8px; 47 | } 48 | 49 | form.jsfiddle textarea, form.jsfiddle input { 50 | display: none; 51 | } 52 | 53 | li.doc-example-live { 54 | padding: 10px; 55 | font-size: 1.2em; 56 | } 57 | 58 | div.syntaxhighlighter { 59 | padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars http://is.gd/gSMgC */ 60 | } 61 | 62 | /* TABS - tutorial environment navigation */ 63 | 64 | div.tabs-nav { 65 | height: 25px; 66 | position: relative; 67 | } 68 | 69 | div.tabs-nav ul li { 70 | list-style: none; 71 | display: inline-block; 72 | padding: 5px 10px; 73 | } 74 | 75 | div.tabs-nav ul li.current a { 76 | color: white; 77 | text-decoration: none; 78 | } 79 | 80 | div.tabs-nav ul li.current { 81 | background: #7989D6; 82 | -moz-box-shadow: 4px 4px 6px #48577D; 83 | -moz-border-radius-topright: 8px; 84 | -moz-border-radius-topleft: 8px; 85 | box-shadow: 4px 4px 6px #48577D; 86 | border-radius-topright: 8px; 87 | border-radius-topleft: 8px; 88 | -webkit-box-shadow: 4px 4px 6px #48577D; 89 | -webkit-border-top-right-radius: 8px; 90 | -webkit-border-top-left-radius: 8px; 91 | border-top-right-radius: 8px; 92 | border-top-left-radius: 8px; 93 | } 94 | 95 | div.tabs-content { 96 | padding: 4px; 97 | position: relative; 98 | background: #7989D6; 99 | -moz-border-radius: 8px; 100 | border-radius: 8px; 101 | -webkit-border-radius: 8px; 102 | } 103 | 104 | div.tabs-content-inner { 105 | margin: 1px; 106 | padding: 10px; 107 | background: white; 108 | border-radius: 6px; 109 | -moz-border-radius: 6px; 110 | -webkit-border-radius: 6px; 111 | } 112 | 113 | 114 | /* Tutorial Nav Bar */ 115 | 116 | #tutorial-nav { 117 | margin: 0.5em 0 1em 0; 118 | padding: 0; 119 | list-style-type: none; 120 | background: #7989D6; 121 | 122 | -moz-border-radius: 15px; 123 | -webkit-border-radius: 15px; 124 | border-radius: 15px; 125 | 126 | -moz-box-shadow: 4px 4px 6px #48577D; 127 | -webkit-box-shadow: 4px 4px 6px #48577D; 128 | box-shadow: 4px 4px 6px #48577D; 129 | } 130 | 131 | 132 | #tutorial-nav li { 133 | display: inline; 134 | } 135 | 136 | 137 | #tutorial-nav a:link, #tutorial-nav a:visited { 138 | font-size: 1.2em; 139 | color: #FFF; 140 | text-decoration: none; 141 | text-align: center; 142 | display: inline-block; 143 | width: 11em; 144 | padding: 0.2em 0; 145 | } 146 | 147 | 148 | #tutorial-nav a:hover { 149 | color: #000; 150 | } 151 | -------------------------------------------------------------------------------- /demo/developmentArea.html: -------------------------------------------------------------------------------- 1 |29 | * 43 | *30 | * 34 | * 35 | *Product name 31 | *Price 32 | *Details 33 | *36 | * 42 | *{{product.name}} 37 | *{{product.price}} 38 | *39 | * more details 40 | * 41 | *
mdtColumn
2 | Representing a header column cell which should be placed inside mdt-header-row element directive.
mdtTable
10 | <mdt-column
14 | [align-rule="{string}"]
15 | [column-sort="{boolean=|object}"]
16 | [column-filter="{object}"]
17 | [column-definition="{string}"]
18 | [exclude-from-column-selector="{boolean}"]
19 | [hide-column-by-default="{boolean}"]>
20 | </mdt-column>
21 | | Param | Type | Details |
|---|---|---|
| alignRule (optional) | string | align cell content. This settings will have affect on each data cells in the same 22 | column (e.g. every x.th cell in every row). 23 |Assignable values: 24 |
|
| columnSort (optional) | boolean=object | sort data and display a sorted state in the header. Clicking on a column 29 | which is already sorted will reverse the sort order and rotate the sort icon. 30 |When object is passed, then compare function can be passed for sorting the column data's. As every compare 31 | function, it gets two parameters and return with the compared result (-1,1,0) 32 |Assignable values: 33 |
|
| columnFilter (optional) | object | if provided, user can activate column filter feature on the selected column 38 |Assignable properties: 39 | |
| columnDefinition (optional) | string | displays a tooltip on hover. 44 | |
| excludeFromColumnSelector (optional) | boolean | disables the column selection for the applied column for the column select feature. 45 | |
| hideColumnByDefault (optional) | boolean | sets the target column as unselected for the column select feature. 46 | |
49 | <mdt-table>
50 | <mdt-header-row>
51 | <mdt-column align-rule="left">Product name</mdt-column>
52 | <mdt-column
53 | align-rule="right"
54 | column-definition="The price of the product in gross.">Price</mdt-column>
55 | </mdt-header-row>
56 |
57 | <mdt-row ng-repeat="product in ctrl.products">
58 | <mdt-cell>{{product.name}}</mdt-cell>
59 | <mdt-cell>{{product.price}}</mdt-cell>
60 | </mdt-row>
61 | </mdt-table>
62 |
63 | 46 | *60 | */ 61 | function mdtColumnDirective($interpolate, ColumnFilterFeature, ColumnSortFeature, ColumnSelectorFeature){ 62 | return { 63 | restrict: 'E', 64 | transclude: true, 65 | replace: true, 66 | scope: { 67 | alignRule: '@', 68 | columnDefinition: '@', 69 | columnSort: '=?', 70 | columnFilter: '=?', 71 | excludeFromColumnSelector: '=?', 72 | hideColumnByDefault: '=?' 73 | }, 74 | require: ['^mdtTable'], 75 | link: function ($scope, element, attrs, ctrl, transclude) { 76 | var mdtTableCtrl = ctrl[0]; 77 | 78 | transclude(function (clone) { 79 | // directive creates an isolate scope so use parent scope to resolve variables. 80 | var cellValue = $interpolate(clone.html())($scope.$parent); 81 | var cellDataToStore = { 82 | alignRule: $scope.alignRule, 83 | columnDefinition: $scope.columnDefinition, 84 | columnName: cellValue 85 | }; 86 | 87 | ColumnFilterFeature.appendHeaderCellData($scope, cellDataToStore, mdtTableCtrl.dataStorage); 88 | ColumnSortFeature.appendHeaderCellData(cellDataToStore, $scope.columnSort); 89 | ColumnSelectorFeature.appendHeaderCellData(cellDataToStore, mdtTableCtrl.columnSelectorFeature, $scope.excludeFromColumnSelector, $scope.hideColumnByDefault); 90 | 91 | mdtTableCtrl.dataStorage.addHeaderCellData(cellDataToStore); 92 | }); 93 | } 94 | }; 95 | } 96 | 97 | angular 98 | .module('mdDataTable') 99 | .directive('mdtColumn', mdtColumnDirective); 100 | }()); -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | ecmaFeatures: 2 | modules: true 3 | jsx: true 4 | 5 | env: 6 | amd: true 7 | browser: true 8 | es6: true 9 | jquery: true 10 | node: true 11 | 12 | # http://eslint.org/docs/rules/ 13 | rules: 14 | # Possible Errors 15 | comma-dangle: [2, never] 16 | no-cond-assign: 2 17 | no-console: 0 18 | no-constant-condition: 2 19 | no-control-regex: 2 20 | no-debugger: 2 21 | no-dupe-args: 2 22 | no-dupe-keys: 2 23 | no-duplicate-case: 2 24 | no-empty: 2 25 | no-empty-character-class: 2 26 | no-ex-assign: 2 27 | no-extra-boolean-cast: 2 28 | no-extra-parens: 0 29 | no-extra-semi: 2 30 | no-func-assign: 2 31 | no-inner-declarations: [2, functions] 32 | no-invalid-regexp: 2 33 | no-irregular-whitespace: 2 34 | no-negated-in-lhs: 2 35 | no-obj-calls: 2 36 | no-regex-spaces: 2 37 | no-sparse-arrays: 2 38 | no-unexpected-multiline: 2 39 | no-unreachable: 2 40 | use-isnan: 2 41 | valid-jsdoc: 0 42 | valid-typeof: 2 43 | 44 | # Best Practices 45 | accessor-pairs: 2 46 | block-scoped-var: 0 47 | complexity: [2, 6] 48 | consistent-return: 0 49 | curly: 0 50 | default-case: 0 51 | dot-location: 0 52 | dot-notation: 0 53 | eqeqeq: 2 54 | guard-for-in: 2 55 | no-alert: 2 56 | no-caller: 2 57 | no-case-declarations: 2 58 | no-div-regex: 2 59 | no-else-return: 0 60 | no-empty-label: 2 61 | no-empty-pattern: 2 62 | no-eq-null: 2 63 | no-eval: 2 64 | no-extend-native: 2 65 | no-extra-bind: 2 66 | no-fallthrough: 2 67 | no-floating-decimal: 0 68 | no-implicit-coercion: 0 69 | no-implied-eval: 2 70 | no-invalid-this: 0 71 | no-iterator: 2 72 | no-labels: 0 73 | no-lone-blocks: 2 74 | no-loop-func: 2 75 | no-magic-number: 0 76 | no-multi-spaces: 0 77 | no-multi-str: 0 78 | no-native-reassign: 2 79 | no-new-func: 2 80 | no-new-wrappers: 2 81 | no-new: 2 82 | no-octal-escape: 2 83 | no-octal: 2 84 | no-proto: 2 85 | no-redeclare: 2 86 | no-return-assign: 2 87 | no-script-url: 2 88 | no-self-compare: 2 89 | no-sequences: 0 90 | no-throw-literal: 0 91 | no-unused-expressions: 2 92 | no-useless-call: 2 93 | no-useless-concat: 2 94 | no-void: 2 95 | no-warning-comments: 0 96 | no-with: 2 97 | radix: 2 98 | vars-on-top: 0 99 | wrap-iife: 2 100 | yoda: 0 101 | 102 | # Strict 103 | strict: 0 104 | 105 | # Variables 106 | init-declarations: 0 107 | no-catch-shadow: 2 108 | no-delete-var: 2 109 | no-label-var: 2 110 | no-shadow-restricted-names: 2 111 | no-shadow: 0 112 | no-undef-init: 2 113 | no-undef: 0 114 | no-undefined: 0 115 | no-unused-vars: 0 116 | no-use-before-define: 0 117 | 118 | # Node.js and CommonJS 119 | callback-return: 2 120 | global-require: 2 121 | handle-callback-err: 2 122 | no-mixed-requires: 0 123 | no-new-require: 0 124 | no-path-concat: 2 125 | no-process-exit: 2 126 | no-restricted-modules: 0 127 | no-sync: 0 128 | 129 | # Stylistic Issues 130 | array-bracket-spacing: 0 131 | block-spacing: 0 132 | brace-style: 0 133 | camelcase: 0 134 | comma-spacing: 0 135 | comma-style: 0 136 | computed-property-spacing: 0 137 | consistent-this: 0 138 | eol-last: 0 139 | func-names: 0 140 | func-style: 0 141 | id-length: 0 142 | id-match: 0 143 | indent: 0 144 | jsx-quotes: 0 145 | key-spacing: 0 146 | linebreak-style: 0 147 | lines-around-comment: 0 148 | max-depth: 0 149 | max-len: 0 150 | max-nested-callbacks: 0 151 | max-params: 0 152 | max-statements: [2, 30] 153 | new-cap: 0 154 | new-parens: 0 155 | newline-after-var: 0 156 | no-array-constructor: 0 157 | no-bitwise: 0 158 | no-continue: 0 159 | no-inline-comments: 0 160 | no-lonely-if: 0 161 | no-mixed-spaces-and-tabs: 0 162 | no-multiple-empty-lines: 0 163 | no-negated-condition: 0 164 | no-nested-ternary: 0 165 | no-new-object: 0 166 | no-plusplus: 0 167 | no-restricted-syntax: 0 168 | no-spaced-func: 0 169 | no-ternary: 0 170 | no-trailing-spaces: 0 171 | no-underscore-dangle: 0 172 | no-unneeded-ternary: 0 173 | object-curly-spacing: 0 174 | one-var: 0 175 | operator-assignment: 0 176 | operator-linebreak: 0 177 | padded-blocks: 0 178 | quote-props: 0 179 | quotes: 0 180 | require-jsdoc: 0 181 | semi-spacing: 0 182 | semi: 0 183 | sort-vars: 0 184 | space-after-keywords: 0 185 | space-before-blocks: 0 186 | space-before-function-paren: 0 187 | space-before-keywords: 0 188 | space-in-parens: 0 189 | space-infix-ops: 0 190 | space-return-throw-case: 0 191 | space-unary-ops: 0 192 | spaced-comment: 0 193 | wrap-regex: 0 194 | 195 | # ECMAScript 6 196 | arrow-body-style: 0 197 | arrow-parens: 0 198 | arrow-spacing: 0 199 | constructor-super: 0 200 | generator-star-spacing: 0 201 | no-arrow-condition: 0 202 | no-class-assign: 0 203 | no-const-assign: 0 204 | no-dupe-class-members: 0 205 | no-this-before-super: 0 206 | no-var: 0 207 | object-shorthand: 0 208 | prefer-arrow-callback: 0 209 | prefer-const: 0 210 | prefer-reflect: 0 211 | prefer-spread: 0 212 | prefer-template: 0 213 | require-yield: 0 214 | -------------------------------------------------------------------------------- /app/modules/main/factories/TableDataStorageFactory.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | 4 | function TableDataStorageFactory($log, _){ 5 | 6 | function TableDataStorageService(){ 7 | this.storage = []; 8 | this.header = []; 9 | this.customCells = {}; 10 | } 11 | 12 | TableDataStorageService.prototype.addHeaderCellData = function(ops){ 13 | this.header.push(ops); 14 | }; 15 | 16 | TableDataStorageService.prototype.addRowData = function(explicitRowId, rowArray, className){ 17 | if(!(rowArray instanceof Array)){ 18 | $log.error('`rowArray` parameter should be array'); 19 | return; 20 | } 21 | 22 | this.storage.push({ 23 | rowId: explicitRowId, 24 | optionList: { 25 | selected: false, 26 | deleted: false, 27 | visible: true, 28 | className: className || false 29 | }, 30 | data: rowArray 31 | }); 32 | }; 33 | 34 | TableDataStorageService.prototype.getRowData = function(index){ 35 | if(!this.storage[index]){ 36 | $log.error('row is not exists at index: '+index); 37 | return; 38 | } 39 | 40 | return this.storage[index].data; 41 | }; 42 | 43 | TableDataStorageService.prototype.getRowOptions = function(index){ 44 | if(!this.storage[index]){ 45 | $log.error('row is not exists at index: '+index); 46 | return; 47 | } 48 | 49 | return this.storage[index].optionList; 50 | }; 51 | 52 | TableDataStorageService.prototype.setAllRowsSelected = function(isSelected, isPaginationEnabled){ 53 | if(typeof isSelected === 'undefined'){ 54 | $log.error('`isSelected` parameter is required'); 55 | return; 56 | } 57 | 58 | _.each(this.storage, function(rowData){ 59 | if(isPaginationEnabled) { 60 | if (rowData.optionList.visible) { 61 | rowData.optionList.selected = isSelected ? true : false; 62 | } 63 | }else{ 64 | rowData.optionList.selected = isSelected ? true : false; 65 | } 66 | }); 67 | }; 68 | 69 | TableDataStorageService.prototype.isAnyRowSelected = function(){ 70 | return _.some(this.storage, function(rowData){ 71 | return rowData.optionList.selected === true && rowData.optionList.deleted === false; 72 | }); 73 | }; 74 | 75 | TableDataStorageService.prototype.getNumberOfSelectedRows = function(){ 76 | var res = _.countBy(this.storage, function(rowData){ 77 | return rowData.optionList.selected === true && rowData.optionList.deleted === false ? 'selected' : 'unselected'; 78 | }); 79 | 80 | return res.selected ? res.selected : 0; 81 | }; 82 | 83 | TableDataStorageService.prototype.deleteSelectedRows = function(){ 84 | var deletedRows = []; 85 | 86 | _.each(this.storage, function(rowData){ 87 | if(rowData.optionList.selected && rowData.optionList.deleted === false){ 88 | 89 | if(rowData.rowId){ 90 | deletedRows.push(rowData.rowId); 91 | 92 | //Fallback when no id was specified 93 | } else{ 94 | deletedRows.push(rowData.data); 95 | } 96 | 97 | rowData.optionList.deleted = true; 98 | } 99 | }); 100 | 101 | return deletedRows; 102 | }; 103 | 104 | TableDataStorageService.prototype.getSelectedRows = function(){ 105 | var selectedRows = []; 106 | 107 | _.each(this.storage, function(rowData){ 108 | if(rowData.optionList.selected && rowData.optionList.deleted === false){ 109 | 110 | if(rowData.rowId){ 111 | selectedRows.push(rowData.rowId); 112 | 113 | //Fallback when no id was specified 114 | } else{ 115 | selectedRows.push(rowData.data); 116 | } 117 | } 118 | }); 119 | 120 | return selectedRows; 121 | }; 122 | 123 | TableDataStorageService.prototype.getSavedRowData = function(rowData){ 124 | var rawRowData = []; 125 | 126 | _.each(rowData.data, function(aCell){ 127 | rawRowData.push(aCell.value); 128 | }); 129 | 130 | return rawRowData; 131 | }; 132 | 133 | return { 134 | getInstance: function(){ 135 | return new TableDataStorageService(); 136 | } 137 | }; 138 | } 139 | 140 | angular 141 | .module('mdDataTable') 142 | .factory('TableDataStorageFactory', TableDataStorageFactory); 143 | }()); -------------------------------------------------------------------------------- /docs/js/docs-setup.js: -------------------------------------------------------------------------------- 1 | NG_DOCS={ 2 | "sections": { 3 | "api": "API Documentation" 4 | }, 5 | "pages": [ 6 | { 7 | "section": "api", 8 | "id": "mdtCell", 9 | "shortName": "mdtCell", 10 | "type": "directive", 11 | "moduleName": "mdtCell", 12 | "shortDescription": "Representing a cell which should be placed inside mdt-row element directive.", 13 | "keywords": "api cell click complex content ctrl details dialog directive edit editable editablefield editablefieldmaxlength editablefieldtitle element field flexible href html html-content htmlcontent inside largeeditdialog length maximum mdt-row mdtcell mdtrow mdttable modes ng-repeat one-field price product productdetails products representing set sets simple smalleditdialog title true" 14 | }, 15 | { 16 | "section": "api", 17 | "id": "mdtColumn", 18 | "shortName": "mdtColumn", 19 | "type": "directive", 20 | "moduleName": "mdtColumn", 21 | "shortDescription": "Representing a header column cell which should be placed inside mdt-header-row element directive.", 22 | "keywords": "activate affect align align-rule alignrule api applied array assignable cell cells checkbox chips clicking column column-definition columndefinition columnfilter columnsort comparator compare compared content ctrl data default defines directive disables display displays don dropdown element excludefromcolumnselector false feature filter filtertype function gross header hidecolumnbydefault hover icon inside left mdt-header-row mdtcolumn mdttable ng-repeat object objects optional options order parameters passed placeholder placeholdertext price product products promise properties provided representing required resolves result return reverse rotate row select selected selection sets settings sort sorted sorting strings target text tooltip transforms true type types unselected user values valuesprovidercallback valuestransformercallback visually" 23 | }, 24 | { 25 | "section": "api", 26 | "id": "mdtHeaderRow", 27 | "shortName": "mdtHeaderRow", 28 | "type": "directive", 29 | "moduleName": "mdtHeaderRow", 30 | "shortDescription": "Representing a header row which should be placed inside mdt-table element directive.", 31 | "keywords": "api directive directives element execute header inside main mdt-column mdt-table mdtheaderrow mdttable representing responsibility row transcluded" 32 | }, 33 | { 34 | "section": "api", 35 | "id": "mdtRow", 36 | "shortName": "mdtRow", 37 | "type": "directive", 38 | "moduleName": "mdtRow", 39 | "shortDescription": "Representing a row which should be placed inside mdt-table element directive.", 40 | "keywords": "api attribute best case change changes component data deleting directive dynamic element functionality generate impossible inside intend knowledge limited listen mdt-table mdtrow mdttable moment ng-repeat note price product products provide representing row rows set solve table table-row-id tablerowid task transclusions uniqe won work" 41 | }, 42 | { 43 | "section": "api", 44 | "id": "mdtTable", 45 | "shortName": "mdtTable", 46 | "type": "directive", 47 | "moduleName": "mdtTable", 48 | "shortDescription": "The base HTML tag for the component.", 49 | "keywords": "accepts actionicons actions activates additional ajax ajax-based alternateheaders animated animatesorticon api applied approaches argument array asc assignable assigned attribute base based basic benefit bottom callback called card cards change changes checkbox class clicked color column column-keys columnfilter columns columnselector columnsort compatible component configure contextual controller create created_by creator css currently custom customised data default delete deleted deleterowcallback deleting demo desc directive disable display docs dynamic element embedded enable enables error example exclude-from-column-selector explicitly field filter filtered fixed format function header headers height help html icon identifier implemented implementing indicator initialize input inside inspect isenabled item_name items key-value kind list listen ll loading manipulation manually md-virtual-repeat-container mdt-header-row mdt-row mdtloadingindicator mdtrow mdtrowpaginator mdtrowpaginatorerrormessage mdtrowpaginatornoresultsmessage mdttable mdttranslations mdttriggerrequest message names number options order overrides pagesize paginatedrows pagination paginator paging pairs parameters parse passed passing persistent persistentactions populate product promise properly properties property provide provided providing rejected request require returns ripple rippleeffect row rows rowsperpagevalues scrolling search selectablerows selected selectedrowcallback selecting selection set sets setup sizes sort sorted structure table table-row-class-name table-row-id table-row-id-key tablecard tag title titles tools top translations trigger triggering uniq update update_date values virtual virtualrepeat visible work working" 50 | } 51 | ], 52 | "apis": { 53 | "api": true 54 | }, 55 | "__file": "_FAKE_DEST_/js/docs-setup.js", 56 | "__options": { 57 | "startPage": "/api", 58 | "scripts": [ 59 | "js/angular.min.js", 60 | "js/angular-animate.min.js", 61 | "js/marked.js" 62 | ], 63 | "styles": [], 64 | "title": "API Documentation", 65 | "html5Mode": true, 66 | "editExample": true, 67 | "navTemplate": false, 68 | "navContent": "", 69 | "navTemplateData": {}, 70 | "loadDefaults": { 71 | "angular": true, 72 | "angularAnimate": true, 73 | "marked": true 74 | } 75 | }, 76 | "html5Mode": true, 77 | "editExample": true, 78 | "startPage": "/api", 79 | "scripts": [ 80 | "js/angular.min.js", 81 | "js/angular-animate.min.js", 82 | "js/marked.js" 83 | ] 84 | }; -------------------------------------------------------------------------------- /docs/css/docs.css: -------------------------------------------------------------------------------- 1 | img.AngularJS-small { 2 | width: 95px; 3 | height: 25px; 4 | } 5 | 6 | /* this is here to avoid the display=block shuffling of ngShow */ 7 | .breadcrumb li > * { 8 | float:left; 9 | margin:0 2px 0 0; 10 | } 11 | 12 | .breadcrumb { 13 | padding-top: 6px; 14 | padding-bottom: 0; 15 | line-height: 18px 16 | } 17 | 18 | .navbar img { 19 | max-height: 40px; 20 | padding-right: 20px; 21 | } 22 | 23 | .navbar img+.brand { 24 | padding: 10px 20px 10px 10px; 25 | } 26 | 27 | .clear-navbar { 28 | margin-top: 60px; 29 | } 30 | 31 | .footer { 32 | padding-top: 2em; 33 | background-color: #333; 34 | color: white; 35 | padding-bottom: 2em; 36 | } 37 | 38 | .spacer { 39 | height: 1em; 40 | } 41 | 42 | 43 | .icon-cog { 44 | line-height: 13px; 45 | } 46 | 47 | /* =============================== */ 48 | 49 | .form-search { 50 | margin-right: 10px; 51 | } 52 | 53 | .form-search .search-query { 54 | width: 180px; 55 | width: 200px \9; 56 | } 57 | 58 | .form-search .dropdown-menu { 59 | margin-left: 10px; 60 | } 61 | 62 | .form-search .code { 63 | font-family: monospace; 64 | font-weight: bold; 65 | font-size: 13px; 66 | color: black; 67 | } 68 | 69 | .form-search > ul.nav > li > a { 70 | margin: 0; 71 | overflow: auto; 72 | } 73 | 74 | .form-search > ul.nav > li.module { 75 | background-color: #d3d3d3; 76 | } 77 | 78 | .form-search > ul.nav > li.section { 79 | background-color: #ebebeb; 80 | min-height: 14px; 81 | } 82 | 83 | .form-search > ul.nav > li.first { 84 | padding-top: 6px; 85 | } 86 | 87 | .form-search > ul.nav > li.last { 88 | padding-bottom: 6px; 89 | } 90 | 91 | .form-search > ul.nav > li.last + li.api-list-item { 92 | margin-top: -6px; 93 | padding-bottom: 6px; 94 | } 95 | 96 | .form-search .well { 97 | border-color: #d3d3d3; 98 | padding: 0; 99 | margin-bottom: 15px; 100 | } 101 | 102 | .form-search .well .nav-header { 103 | text-transform: none; 104 | padding: 3px 1px; 105 | margin: 0; 106 | } 107 | 108 | .form-search .well .nav-header a { 109 | text-transform: none; 110 | color: black; 111 | } 112 | .form-search .well .nav-header a:hover { 113 | background-color: inherit; 114 | } 115 | 116 | .form-search .well li { 117 | line-height: 14px; 118 | } 119 | 120 | .form-search .well li a:focus { 121 | outline: none; 122 | } 123 | 124 | .form-search .well .guide { 125 | float: right; 126 | padding-top: 0; 127 | color: gray; 128 | } 129 | 130 | .form-search .module .guide { 131 | line-height: 20px; 132 | } 133 | 134 | .match > a, .nav > .match > a:hover { 135 | background-color: #dbeaf4; 136 | } 137 | 138 | /* =============================== */ 139 | /* Content */ 140 | /* =============================== */ 141 | 142 | .improve-docs { 143 | float: right; 144 | } 145 | 146 | .hint { 147 | font-size: .6em; 148 | color: #c0c0c0; 149 | display: block; 150 | } 151 | 152 | .content code { 153 | background-color: inherit; 154 | color: inherit; 155 | border: none; 156 | padding: 0; 157 | font-size: inherit; 158 | font-family: monospace; 159 | } 160 | 161 | .content h2, 162 | .content h3, 163 | .content h4, 164 | .content h5 { 165 | margin: 1em 0 5px; 166 | } 167 | 168 | .content h1 { 169 | font-size: 30px; 170 | line-height: 36px; 171 | } 172 | 173 | .content h2 { 174 | font-size: 24px; 175 | line-height: 36px; 176 | } 177 | 178 | .content h3 { 179 | line-height: 27px; 180 | font-size: 18px; 181 | } 182 | 183 | .content h4 { 184 | font-size: 15px; 185 | } 186 | 187 | ul.parameters > li > p, 188 | .returns > p { 189 | display: inline; 190 | } 191 | 192 | ul.methods > li, 193 | ul.properties > li, 194 | ul.events > li { 195 | list-style: none; 196 | min-height: 20px; 197 | padding: 19px; 198 | margin-bottom: 20px; 199 | background-color: #f5f5f5; 200 | border: 1px solid #eee; 201 | border: 1px solid rgba(0, 0, 0, 0.05); 202 | -webkit-border-radius: 4px; 203 | -moz-border-radius: 4px; 204 | border-radius: 4px; 205 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 206 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 207 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 208 | } 209 | 210 | .member.method > h2, 211 | .member.property > h2, 212 | .member.event > h2 { 213 | margin-bottom: .5em; 214 | } 215 | 216 | ul.methods > li > h3, 217 | ul.properties > li > h3, 218 | ul.events > li > h3 { 219 | margin: -19px -19px 1em -19px; 220 | padding: .25em 19px; 221 | background-color: #d3d3d3; 222 | font-family: monospace; 223 | } 224 | 225 | .center { 226 | display: block; 227 | margin: 2em auto; 228 | } 229 | 230 | .diagram { 231 | display: block; 232 | margin: 2em auto; 233 | padding: 1em; 234 | border: 1px solid black; 235 | 236 | -moz-box-shadow: 4px 4px 6px #48577D; 237 | -webkit-box-shadow: 4px 4px 6px #48577D; 238 | box-shadow: 4px 4px 6px #48577D; 239 | 240 | -moz-border-radius: 15px; 241 | -webkit-border-radius: 15px; 242 | border-radius: 15px; 243 | } 244 | 245 | .tutorial-nav { 246 | margin-left: 175px; 247 | color: black; 248 | margin-top: 2em; 249 | margin-bottom: 2em; 250 | } 251 | 252 | .tutorial-nav a { 253 | color: white; 254 | } 255 | 256 | .tutorial-nav a:hover { 257 | color: white; 258 | text-decoration: none; 259 | } 260 | 261 | .clear { 262 | clear: both; 263 | } 264 | 265 | .variables-matrix td { 266 | vertical-align:top; 267 | padding:5px; 268 | } 269 | 270 | .type-hint { 271 | display:inline-block; 272 | } 273 | 274 | .variables-matrix .type-hint { 275 | text-align:center; 276 | display:block; 277 | min-width:60px; 278 | } 279 | 280 | .type-hint + .type-hint { 281 | margin-top:5px; 282 | } 283 | 284 | .type-hint-string { 285 | background:#3a87ad; 286 | } 287 | 288 | .type-hint-object { 289 | background:#999; 290 | } 291 | 292 | .type-hint-array { 293 | background:#F90;; 294 | } 295 | 296 | .type-hint-boolean { 297 | background:rgb(18, 131, 39); 298 | } 299 | 300 | .type-hint-number { 301 | background:rgb(189, 63, 66); 302 | } 303 | -------------------------------------------------------------------------------- /test/unit/modules/features/ColumnFilterFeature/directives/mdtDropdownColumnFilterDirectiveTest.js: -------------------------------------------------------------------------------- 1 | describe('DropdownColumnFilterDirective', function(){ 2 | 3 | var DIRECTIVE_DEFAULT_CASE = 'DIRECTIVE_DEFAULT_CASE'; 4 | var _$compile; 5 | 6 | beforeEach(module('mdtTemplates')); 7 | beforeEach(module('mdDataTable')); 8 | 9 | beforeEach(inject(function($compile, ColumnFilterFeature){ 10 | _$compile = $compile; 11 | 12 | spyOn(ColumnFilterFeature, 'positionColumnFilterBox'); 13 | })); 14 | 15 | describe('WHEN initializing', function(){ 16 | var scope; 17 | 18 | beforeEach(inject(function($q, $rootScope){ 19 | scope = $rootScope.$new(); 20 | 21 | scope.confirmCallback = function(){}; 22 | scope.cancelCallback = function(){}; 23 | scope.headerRowData = { 24 | columnFilter: { 25 | filtersApplied: [], 26 | valuesProviderCallback: function(){ return $q.resolve();} 27 | }, 28 | columnSort: {} 29 | }; 30 | })); 31 | 32 | it('THEN default values must be set', inject(function(){ 33 | //given/when 34 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 35 | 36 | //then 37 | expect(element.isolateScope().selectableItems).toEqual([]); 38 | expect(element.isolateScope().selectedItems).toEqual([]); 39 | })); 40 | 41 | it('AND selectable items must be filled', inject(function($q){ 42 | //given 43 | scope.headerRowData.columnFilter = { 44 | filtersApplied: [], 45 | valuesProviderCallback: function(){ return $q.resolve(['one', 'two', 'three']); } 46 | }; 47 | 48 | //when 49 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 50 | 51 | //then 52 | expect(element.isolateScope().selectableItems).toEqual(['one', 'two', 'three']); 53 | })); 54 | 55 | it('WHEN selected items are defined THEN it must be set', inject(function($q){ 56 | //given 57 | scope.headerRowData.columnFilter = { 58 | filtersApplied: ['two'], 59 | valuesProviderCallback: function(){ return $q.resolve(['one', 'two', 'three']); } 60 | }; 61 | 62 | //when 63 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 64 | 65 | //then 66 | expect(element.isolateScope().oneSelectedItem).toEqual('two'); 67 | })); 68 | }); 69 | 70 | describe('WHEN transforming items', function(){ 71 | var scope; 72 | 73 | beforeEach(inject(function($q, $rootScope){ 74 | scope = $rootScope.$new(); 75 | 76 | scope.confirmCallback = function(){}; 77 | scope.cancelCallback = function(){}; 78 | scope.headerRowData = { 79 | columnFilter: { 80 | filtersApplied: [], 81 | valuesProviderCallback: function(){ return $q.resolve();} 82 | }, 83 | columnSort: {} 84 | }; 85 | })); 86 | 87 | it('AND transform function were not provided THEN it needs to return with the item itself', inject(function(){ 88 | //given 89 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 90 | 91 | //when 92 | var result = element.isolateScope().transformChip('Ice Cream Sandwitch'); 93 | 94 | //then 95 | expect(result).toEqual('Ice Cream Sandwitch'); 96 | })); 97 | 98 | it('AND transform function were provided THEN it needs to return with the transformed value of the item', inject(function(){ 99 | //given 100 | scope.headerRowData.columnFilter.valuesTransformerCallback = function(item){ 101 | return item.name; 102 | }; 103 | 104 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 105 | 106 | //when 107 | var result = element.isolateScope().transformChip({name: 'Ice Cream Sandwitch'}); 108 | 109 | //then 110 | expect(result).toEqual('Ice Cream Sandwitch'); 111 | })); 112 | }); 113 | 114 | describe('WHEN selecting an item', function(){ 115 | var scope; 116 | 117 | beforeEach(inject(function($q, $rootScope){ 118 | scope = $rootScope.$new(); 119 | 120 | scope.confirmCallback = function(){}; 121 | scope.cancelCallback = function(){}; 122 | scope.headerRowData = { 123 | columnFilter: { 124 | filtersApplied: [], 125 | valuesProviderCallback: function(){ return $q.resolve(['one', 'two', 'three']);} 126 | }, 127 | columnSort: {} 128 | }; 129 | })); 130 | 131 | it('THEN if value is undefined THEN it should not set', inject(function(){ 132 | //given 133 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 134 | 135 | //when 136 | element.isolateScope().selectedItem(); 137 | 138 | //then 139 | expect(element.isolateScope().selectedItems).toEqual([]); 140 | })); 141 | 142 | it('THEN if value is not undefined THEN it should set the selected items', inject(function(){ 143 | //given 144 | var element = compileDirective(scope, DIRECTIVE_DEFAULT_CASE); 145 | 146 | element.isolateScope().oneSelectedItem = 'two'; 147 | 148 | //when 149 | element.isolateScope().selectedItem(); 150 | 151 | //then 152 | expect(element.isolateScope().selectedItems).toEqual(['two']); 153 | })); 154 | }); 155 | 156 | function compileDirective(scope, status){ 157 | var mainElement; 158 | 159 | switch(status){ 160 | case DIRECTIVE_DEFAULT_CASE: 161 | mainElement = _$compile('' + 162 | '47 | * 59 | *48 | * 53 | * 54 | *Product name 49 | *Price 52 | *55 | * 58 | *{{product.name}} 56 | *{{product.price}} 57 | *