diff options
author | seshukm <seshu.kumar.m@huawei.com> | 2017-03-06 10:23:16 +0530 |
---|---|---|
committer | seshukm <seshu.kumar.m@huawei.com> | 2017-03-06 10:23:16 +0530 |
commit | 663394f188c4460ad889b70a82557db0f9754032 (patch) | |
tree | 09d5bea2b0684b5752f5cd8f74e1f3f4ffaa740a /vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js | |
parent | 194d6e19da729265130123b6638e0f57589c9367 (diff) |
thirdparty files updated for the vnf market place
IssueId : CLIENT-4
Change-Id: Id58c2d11985bda35dc482b122dc404aea2e477da
Signed-off-by: seshukm <seshu.kumar.m@huawei.com>
Diffstat (limited to 'vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js')
-rw-r--r-- | vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js | 1486 |
1 files changed, 1486 insertions, 0 deletions
diff --git a/vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js b/vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js new file mode 100644 index 00000000..8372a777 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material-data-table/dist/md-data-table.js @@ -0,0 +1,1486 @@ +/* + * Angular Material Data Table + * https://github.com/daniel-nagy/md-data-table + * @license MIT + * v0.10.9 + */ +(function (window, angular, undefined) { +'use strict'; + +angular.module('md.table.templates', ['md-table-pagination.html', 'md-table-progress.html', 'arrow-up.svg', 'navigate-before.svg', 'navigate-first.svg', 'navigate-last.svg', 'navigate-next.svg']); + +angular.module('md-table-pagination.html', []).run(['$templateCache', function($templateCache) { + $templateCache.put('md-table-pagination.html', + '<div class="page-select" ng-if="$pagination.showPageSelect()">\n' + + ' <div class="label">{{$pagination.label.page}}</div>\n' + + '\n' + + ' <md-select virtual-page-select total="{{$pagination.pages()}}" class="md-table-select" ng-model="$pagination.page" md-container-class="md-pagination-select" ng-change="$pagination.onPaginationChange()" ng-disabled="$pagination.disabled" aria-label="Page">\n' + + ' <md-content>\n' + + ' <md-option ng-repeat="page in $pageSelect.pages" ng-value="page">{{page}}</md-option>\n' + + ' </md-content>\n' + + ' </md-select>\n' + + '</div>\n' + + '\n' + + '<div class="limit-select" ng-if="$pagination.limitOptions">\n' + + ' <div class="label">{{$pagination.label.rowsPerPage}}</div>\n' + + '\n' + + ' <md-select class="md-table-select" ng-model="$pagination.limit" md-container-class="md-pagination-select" ng-disabled="$pagination.disabled" aria-label="Rows" placeholder="{{ $pagination.limitOptions[0] }}">\n' + + ' <md-option ng-repeat="option in $pagination.limitOptions" ng-value="option.value ? $pagination.eval(option.value) : option">{{::option.label ? option.label : option}}</md-option>\n' + + ' </md-select>\n' + + '</div>\n' + + '\n' + + '<div class="buttons">\n' + + ' <div class="label">{{$pagination.min()}} - {{$pagination.max()}} {{$pagination.label.of}} {{$pagination.total}}</div>\n' + + '\n' + + ' <md-button class="md-icon-button" type="button" ng-if="$pagination.showBoundaryLinks()" ng-click="$pagination.first()" ng-disabled="$pagination.disabled || !$pagination.hasPrevious()" aria-label="First">\n' + + ' <md-icon md-svg-icon="navigate-first.svg"></md-icon>\n' + + ' </md-button>\n' + + '\n' + + ' <md-button class="md-icon-button" type="button" ng-click="$pagination.previous()" ng-disabled="$pagination.disabled || !$pagination.hasPrevious()" aria-label="Previous">\n' + + ' <md-icon md-svg-icon="navigate-before.svg"></md-icon>\n' + + ' </md-button>\n' + + '\n' + + ' <md-button class="md-icon-button" type="button" ng-click="$pagination.next()" ng-disabled="$pagination.disabled || !$pagination.hasNext()" aria-label="Next">\n' + + ' <md-icon md-svg-icon="navigate-next.svg"></md-icon>\n' + + ' </md-button>\n' + + '\n' + + ' <md-button class="md-icon-button" type="button" ng-if="$pagination.showBoundaryLinks()" ng-click="$pagination.last()" ng-disabled="$pagination.disabled || !$pagination.hasNext()" aria-label="Last">\n' + + ' <md-icon md-svg-icon="navigate-last.svg"></md-icon>\n' + + ' </md-button>\n' + + '</div>'); +}]); + +angular.module('md-table-progress.html', []).run(['$templateCache', function($templateCache) { + $templateCache.put('md-table-progress.html', + '<tr>\n' + + ' <th colspan="{{columnCount()}}">\n' + + ' <md-progress-linear ng-show="deferred()" md-mode="indeterminate"></md-progress-linear>\n' + + ' </th>\n' + + '</tr>'); +}]); + +angular.module('arrow-up.svg', []).run(['$templateCache', function($templateCache) { + $templateCache.put('arrow-up.svg', + '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z"/></svg>'); +}]); + +angular.module('navigate-before.svg', []).run(['$templateCache', function($templateCache) { + $templateCache.put('navigate-before.svg', + '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>'); +}]); + +angular.module('navigate-first.svg', []).run(['$templateCache', function($templateCache) { + $templateCache.put('navigate-first.svg', + '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M7 6 v12 h2 v-12 h-2z M17.41 7.41L16 6l-6 6 6 6 1.41-1.41L12.83 12z"/></svg>'); +}]); + +angular.module('navigate-last.svg', []).run(['$templateCache', function($templateCache) { + $templateCache.put('navigate-last.svg', + '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 6 v12 h2 v-12 h-2z M8 6L6.59 7.41 11.17 12l-4.58 4.59L8 18l6-6z"/></svg>'); +}]); + +angular.module('navigate-next.svg', []).run(['$templateCache', function($templateCache) { + $templateCache.put('navigate-next.svg', + '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>'); +}]); + + +angular.module('md.data.table', ['md.table.templates']); + +angular.module('md.data.table').directive('mdBody', mdBody); + +function mdBody() { + + function compile(tElement) { + tElement.addClass('md-body'); + } + + return { + compile: compile, + restrict: 'A' + }; +} + +angular.module('md.data.table').directive('mdCell', mdCell); + +function mdCell() { + + function compile(tElement) { + var select = tElement.find('md-select'); + + if(select.length) { + select.addClass('md-table-select').attr('md-container-class', 'md-table-select'); + } + + tElement.addClass('md-cell'); + + return postLink; + } + + // empty controller to be bind properties to in postLink function + function Controller() { + + } + + function postLink(scope, element, attrs, ctrls) { + var select = element.find('md-select'); + var cellCtrl = ctrls.shift(); + var tableCtrl = ctrls.shift(); + + if(attrs.ngClick) { + element.addClass('md-clickable'); + } + + if(select.length) { + select.on('click', function (event) { + event.stopPropagation(); + }); + + element.addClass('md-clickable').on('click', function (event) { + event.stopPropagation(); + select[0].click(); + }); + } + + cellCtrl.getTable = tableCtrl.getElement; + + function getColumn() { + return tableCtrl.$$columns[getIndex()]; + } + + function getIndex() { + return Array.prototype.indexOf.call(element.parent().children(), element[0]); + } + + scope.$watch(getColumn, function (column) { + if(!column) { + return; + } + + if(column.numeric) { + element.addClass('md-numeric'); + } else { + element.removeClass('md-numeric'); + } + }); + } + + return { + controller: Controller, + compile: compile, + require: ['mdCell', '^^mdTable'], + restrict: 'A' + }; +} + +angular.module('md.data.table').directive('mdColumn', mdColumn); + +function mdColumn($compile, $mdUtil) { + + function compile(tElement) { + tElement.addClass('md-column'); + return postLink; + } + + function postLink(scope, element, attrs, ctrls) { + var headCtrl = ctrls.shift(); + var tableCtrl = ctrls.shift(); + + function attachSortIcon() { + var sortIcon = angular.element('<md-icon md-svg-icon="arrow-up.svg">'); + + $compile(sortIcon.addClass('md-sort-icon').attr('ng-class', 'getDirection()'))(scope); + + if(element.hasClass('md-numeric')) { + element.prepend(sortIcon); + } else { + element.append(sortIcon); + } + } + + function detachSortIcon() { + Array.prototype.some.call(element.find('md-icon'), function (icon) { + return icon.classList.contains('md-sort-icon') && element[0].removeChild(icon); + }); + } + + function disableSorting() { + detachSortIcon(); + element.removeClass('md-sort').off('click', setOrder); + } + + function enableSorting() { + attachSortIcon(); + element.addClass('md-sort').on('click', setOrder); + } + + function getIndex() { + return Array.prototype.indexOf.call(element.parent().children(), element[0]); + } + + function isActive() { + return scope.orderBy && (headCtrl.order === scope.orderBy || headCtrl.order === '-' + scope.orderBy); + } + + function isNumeric() { + return attrs.mdNumeric === '' || scope.numeric; + } + + function setOrder() { + scope.$applyAsync(function () { + if(isActive()) { + headCtrl.order = scope.getDirection() === 'md-asc' ? '-' + scope.orderBy : scope.orderBy; + } else { + headCtrl.order = scope.getDirection() === 'md-asc' ? scope.orderBy : '-' + scope.orderBy; + } + + if(angular.isFunction(headCtrl.onReorder)) { + $mdUtil.nextTick(function () { + headCtrl.onReorder(headCtrl.order); + }); + } + }); + } + + function updateColumn(index, column) { + tableCtrl.$$columns[index] = column; + + if(column.numeric) { + element.addClass('md-numeric'); + } else { + element.removeClass('md-numeric'); + } + } + + scope.getDirection = function () { + if(isActive()) { + return headCtrl.order.charAt(0) === '-' ? 'md-desc' : 'md-asc'; + } + + return attrs.mdDesc === '' || scope.$eval(attrs.mdDesc) ? 'md-desc' : 'md-asc'; + }; + + scope.$watch(isActive, function (active) { + if(active) { + element.addClass('md-active'); + } else { + element.removeClass('md-active'); + } + }); + + scope.$watch(getIndex, function (index) { + updateColumn(index, {'numeric': isNumeric()}); + }); + + scope.$watch(isNumeric, function (numeric) { + updateColumn(getIndex(), {'numeric': numeric}); + }); + + scope.$watch('orderBy', function (orderBy) { + if(orderBy) { + if(!element.hasClass('md-sort')) { + enableSorting(); + } + } else if(element.hasClass('md-sort')) { + disableSorting(); + } + }); + } + + return { + compile: compile, + require: ['^^mdHead', '^^mdTable'], + restrict: 'A', + scope: { + numeric: '=?mdNumeric', + orderBy: '@?mdOrderBy' + } + }; +} + +mdColumn.$inject = ['$compile', '$mdUtil']; + +angular.module('md.data.table') + .decorator('$controller', controllerDecorator) + .factory('$mdEditDialog', mdEditDialog); + +/* + * A decorator for ng.$controller to optionally bind properties to the + * controller before invoking the constructor. Stolen from the ngMock. + * + * https://docs.angularjs.org/api/ngMock/service/$controller + */ +function controllerDecorator($delegate) { + return function(expression, locals, later, ident) { + if(later && typeof later === 'object') { + var create = $delegate(expression, locals, true, ident); + angular.extend(create.instance, later); + return create(); + } + return $delegate(expression, locals, later, ident); + }; +} + +controllerDecorator.$inject = ['$delegate']; + +function mdEditDialog($compile, $controller, $document, $mdUtil, $q, $rootScope, $templateCache, $templateRequest, $window) { + /* jshint validthis: true */ + + var ESCAPE = 27; + + var busy = false; + var body = angular.element($document.prop('body')); + + /* + * bindToController + * controller + * controllerAs + * locals + * resolve + * scope + * targetEvent + * template + * templateUrl + */ + var defaultOptions = { + clickOutsideToClose: true, + disableScroll: true, + escToClose: true, + focusOnOpen: true + }; + + function build(template, options) { + var scope = $rootScope.$new(); + var element = $compile(template)(scope); + var backdrop = $mdUtil.createBackdrop(scope, 'md-edit-dialog-backdrop'); + var controller; + + if(options.controller) { + controller = getController(options, scope, {$element: element, $scope: scope}); + } else { + angular.extend(scope, options.scope); + } + + if(options.disableScroll) { + disableScroll(element); + } + + body.prepend(backdrop).append(element.addClass('md-whiteframe-1dp')); + + positionDialog(element, options.target); + + if(options.focusOnOpen) {
+ focusOnOpen(element);
+ }
+ + if(options.clickOutsideToClose) { + backdrop.on('click', function () { + element.remove(); + }); + } + + if(options.escToClose) { + escToClose(element); + } + + element.on('$destroy', function () { + busy = false; + backdrop.remove(); + }); + + return controller; + } + + function disableScroll(element) { + var restoreScroll = $mdUtil.disableScrollAround(element, body); + + element.on('$destroy', function () { + restoreScroll(); + }); + } + + function getController(options, scope, inject) { + if(!options.controller) { + return; + } + + if(options.resolve) { + angular.extend(inject, options.resolve); + } + + if(options.locals) { + angular.extend(inject, options.locals); + } + + if(options.controllerAs) { + scope[options.controllerAs] = {}; + + if(options.bindToController) { + angular.extend(scope[options.controllerAs], options.scope); + } else { + angular.extend(scope, options.scope); + } + } else { + angular.extend(scope, options.scope); + } + + if(options.bindToController) { + return $controller(options.controller, inject, scope[options.controllerAs]); + } else { + return $controller(options.controller, inject); + } + } + + function getTemplate(options) { + return $q(function (resolve, reject) { + var template = options.template; + + function illegalType(type) { + reject('Unexpected template value. Expected a string; received a ' + type + '.'); + } + + if(template) { + return angular.isString(template) ? resolve(template) : illegalType(typeof template); + } + + if(options.templateUrl) { + template = $templateCache.get(options.templateUrl); + + if(template) { + return resolve(template); + } + + var success = function (template) { + return resolve(template); + }; + + var error = function () { + return reject('Error retrieving template from URL.'); + }; + + return $templateRequest(options.templateUrl).then(success, error); + } + + reject('Template not provided.'); + }); + } + + function logError(error) { + busy = false; + console.error(error); + } + + function escToClose(element) { + var keyup = function (event) { + if(event.keyCode === ESCAPE) { + element.remove(); + } + }; + + body.on('keyup', keyup); + + element.on('$destroy', function () { + body.off('keyup', keyup); + }); + } + + function focusOnOpen(element) {
+ $mdUtil.nextTick(function () {
+ var autofocus = $mdUtil.findFocusTarget(element); + + if(autofocus) {
+ autofocus.focus();
+ }
+ }, false);
+ } + + function positionDialog(element, target) { + var table = angular.element(target).controller('mdCell').getTable(); + + var getHeight = function () { + return element.prop('clientHeight'); + }; + + var getSize = function () { + return { + width: getWidth(), + height: getHeight() + }; + }; + + var getTableBounds = function () { + var parent = table.parent(); + + if(parent.prop('tagName') === 'MD-TABLE-CONTAINER') { + return parent[0].getBoundingClientRect(); + } else { + return table[0].getBoundingClientRect(); + } + }; + + var getWidth = function () { + return element.prop('clientWidth'); + }; + + var reposition = function () { + var size = getSize(); + var cellBounds = target.getBoundingClientRect(); + var tableBounds = getTableBounds(); + + if(size.width > tableBounds.right - cellBounds.left) { + element.css('left', tableBounds.right - size.width + 'px'); + } else { + element.css('left', cellBounds.left + 'px'); + } + + if(size.height > tableBounds.bottom - cellBounds.top) { + element.css('top', tableBounds.bottom - size.height + 'px'); + } else { + element.css('top', cellBounds.top + 1 + 'px'); + } + + element.css('minWidth', cellBounds.width + 'px'); + }; + + var watchWidth = $rootScope.$watch(getWidth, reposition); + var watchHeight = $rootScope.$watch(getHeight, reposition); + + $window.addEventListener('resize', reposition); + + element.on('$destroy', function () { + watchWidth(); + watchHeight(); + + $window.removeEventListener('resize', reposition); + }); + } + + function preset(size, options) { + + function getAttrs() { + var attrs = 'type="' + (options.type || 'text') + '"'; + + for(var attr in options.validators) { + attrs += ' ' + attr + '="' + options.validators[attr] + '"'; + } + + return attrs; + } + + return { + controller: ['$element', '$q', 'save', '$scope', function ($element, $q, save, $scope) { + function update() { + if($scope.editDialog.$invalid) { + return $q.reject(); + } + + if(angular.isFunction(save)) { + return $q.when(save($scope.editDialog.input)); + } + + return $q.resolve(); + } + + this.dismiss = function () { + $element.remove(); + }; + + this.getInput = function () { + return $scope.editDialog.input; + }; + + $scope.dismiss = this.dismiss; + + $scope.submit = function () { + update().then(function () { + $scope.dismiss(); + }); + }; + }], + locals: { + save: options.save + }, + scope: { + cancel: options.cancel || 'Cancel', + messages: options.messages, + model: options.modelValue, + ok: options.ok || 'Save', + placeholder: options.placeholder, + title: options.title, + size: size + }, + template: + '<md-edit-dialog>' + + '<div layout="column" class="md-content">' + + '<div ng-if="size === \'large\'" class="md-title">{{title || \'Edit\'}}</div>' + + '<form name="editDialog" layout="column" ng-submit="submit(model)">' + + '<md-input-container md-no-float>' + + '<input name="input" ng-model="model" md-autofocus placeholder="{{placeholder}} "' + getAttrs() + '>' + + '<div ng-messages="editDialog.input.$error">' + + '<div ng-repeat="(key, message) in messages" ng-message="{{key}}">{{message}}</div>' + + '</div>' + + '</md-input-container>' + + '</form>' + + '</div>' + + '<div ng-if="size === \'large\'" layout="row" layout-align="end" class="md-actions">' + + '<md-button class="md-primary" ng-click="dismiss()">{{cancel}}</md-button>' + + '<md-button class="md-primary" ng-click="submit()">{{ok}}</md-button>' + + '</div>' + + '</md-edit-dialog>' + }; + } + + this.show = function (options) { + if(busy) { + return $q.reject(); + } + + busy = true; + options = angular.extend({}, defaultOptions, options); + + if(!options.targetEvent) { + return logError('options.targetEvent is required to align the dialog with the table cell.'); + } + + if(!options.targetEvent.currentTarget.classList.contains('md-cell')) { + return logError('The event target must be a table cell.'); + } + + if(options.bindToController && !options.controllerAs) { + return logError('You must define options.controllerAs when options.bindToController is true.'); + } + + options.target = options.targetEvent.currentTarget; + + var promise = getTemplate(options); + var promises = [promise]; + + for(var prop in options.resolve) { + promise = options.resolve[prop]; + promises.push($q.when(angular.isFunction(promise) ? promise() : promise)); + } + + promise = $q.all(promises); + + promise['catch'](logError); + + return promise.then(function (results) { + var template = results.shift(); + + for(var prop in options.resolve) { + options.resolve[prop] = results.shift(); + } + + return build(template, options); + }); + }; + + this.small = function (options) { + return this.show(angular.extend({}, options, preset('small', options))); + }.bind(this); + + this.large = function (options) { + return this.show(angular.extend({}, options, preset('large', options))); + }.bind(this); + + return this; +} + +mdEditDialog.$inject = ['$compile', '$controller', '$document', '$mdUtil', '$q', '$rootScope', '$templateCache', '$templateRequest', '$window']; + + +angular.module('md.data.table').directive('mdFoot', mdFoot); + +function mdFoot() { + + function compile(tElement) { + tElement.addClass('md-foot'); + } + + return { + compile: compile, + restrict: 'A' + }; +} + +angular.module('md.data.table').directive('mdHead', mdHead); + +function mdHead($compile) { + + function compile(tElement) { + tElement.addClass('md-head'); + return postLink; + } + + // empty controller to be bind scope properties to + function Controller() { + + } + + function postLink(scope, element, attrs, tableCtrl) { + // because scope.$watch is unpredictable + var oldValue = new Array(2); + + function addCheckboxColumn() { + element.children().prepend('<th class="md-column md-checkbox-column">'); + } + + function attatchCheckbox() { + element.prop('lastElementChild').firstElementChild.appendChild($compile(createCheckBox())(scope)[0]); + } + + function createCheckBox() { + return angular.element('<md-checkbox>').attr({ + 'aria-label': 'Select All', + 'ng-click': 'toggleAll()', + 'ng-checked': 'allSelected()', + 'ng-disabled': '!getSelectableRows().length' + }); + } + + function detachCheckbox() { + var cell = element.prop('lastElementChild').firstElementChild; + + if(cell.classList.contains('md-checkbox-column')) { + angular.element(cell).empty(); + } + } + + function enableRowSelection() { + return tableCtrl.$$rowSelect; + } + + function mdSelectCtrl(row) { + return angular.element(row).controller('mdSelect'); + } + + function removeCheckboxColumn() { + Array.prototype.some.call(element.find('th'), function (cell) { + return cell.classList.contains('md-checkbox-column') && cell.remove(); + }); + } + + scope.allSelected = function () { + var rows = scope.getSelectableRows(); + + return rows.length && rows.every(function (row) { + return row.isSelected(); + }); + }; + + scope.getSelectableRows = function () { + return tableCtrl.getBodyRows().map(mdSelectCtrl).filter(function (ctrl) { + return ctrl && !ctrl.disabled; + }); + }; + + scope.selectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if(ctrl && !ctrl.isSelected()) { + ctrl.select(); + } + }); + }; + + scope.toggleAll = function () { + return scope.allSelected() ? scope.unSelectAll() : scope.selectAll(); + }; + + scope.unSelectAll = function () { + tableCtrl.getBodyRows().map(mdSelectCtrl).forEach(function (ctrl) { + if(ctrl && ctrl.isSelected()) { + ctrl.deselect(); + } + }); + }; + + scope.$watchGroup([enableRowSelection, tableCtrl.enableMultiSelect], function (newValue) { + if(newValue[0] !== oldValue[0]) { + if(newValue[0]) { + addCheckboxColumn(); + + if(newValue[1]) { + attatchCheckbox(); + } + } else { + removeCheckboxColumn(); + } + } else if(newValue[0] && newValue[1] !== oldValue[1]) { + if(newValue[1]) { + attatchCheckbox(); + } else { + detachCheckbox(); + } + } + + angular.copy(newValue, oldValue); + }); + } + + return { + bindToController: true, + compile: compile, + controller: Controller, + controllerAs: '$mdHead', + require: '^^mdTable', + restrict: 'A', + scope: { + order: '=?mdOrder', + onReorder: '=?mdOnReorder' + } + }; +} + +mdHead.$inject = ['$compile']; + +angular.module('md.data.table').directive('mdRow', mdRow); + +function mdRow() { + + function compile(tElement) { + tElement.addClass('md-row'); + return postLink; + } + + function postLink(scope, element, attrs, tableCtrl) { + function enableRowSelection() { + return tableCtrl.$$rowSelect; + } + + function isBodyRow() { + return tableCtrl.getBodyRows().indexOf(element[0]) !== -1; + } + + function isChild(node) { + return element[0].contains(node[0]); + } + + if(isBodyRow()) { + var cell = angular.element('<td class="md-cell">'); + + scope.$watch(enableRowSelection, function (enable) { + // if a row is not selectable, prepend an empty cell to it + if(enable && !attrs.mdSelect) { + if(!isChild(cell)) { + element.prepend(cell); + } + return; + } + + if(isChild(cell)) { + cell.remove(); + } + }); + } + } + + return { + compile: compile, + require: '^^mdTable', + restrict: 'A' + }; +} + +angular.module('md.data.table').directive('mdSelect', mdSelect); + +function mdSelect($compile, $parse) { + + // empty controller to bind scope properties to + function Controller() { + + } + + function postLink(scope, element, attrs, ctrls) { + var self = ctrls.shift(); + var tableCtrl = ctrls.shift(); + var getId = $parse(attrs.mdSelectId); + + self.id = getId(self.model); + + if(tableCtrl.$$rowSelect && self.id) { + if(tableCtrl.$$hash.has(self.id)) { + var index = tableCtrl.selected.indexOf(tableCtrl.$$hash.get(self.id)); + + // if the item is no longer selected remove it + if(index === -1) { + tableCtrl.$$hash.purge(self.id); + } + + // if the item is not a reference to the current model update the reference + else if(!tableCtrl.$$hash.equals(self.id, self.model)) { + tableCtrl.$$hash.update(self.id, self.model); + tableCtrl.selected.splice(index, 1, self.model); + } + + } else { + + // check if the item has been selected + tableCtrl.selected.some(function (item, index) { + if(getId(item) === self.id) { + tableCtrl.$$hash.update(self.id, self.model); + tableCtrl.selected.splice(index, 1, self.model); + + return true; + } + }); + } + } + + self.isSelected = function () { + if(!tableCtrl.$$rowSelect) { + return false; + } + + if(self.id) { + return tableCtrl.$$hash.has(self.id); + } + + return tableCtrl.selected.indexOf(self.model) !== -1; + }; + + self.select = function () { + if(self.disabled) { + return; + } + + if(tableCtrl.enableMultiSelect()) { + tableCtrl.selected.push(self.model); + } else { + tableCtrl.selected.splice(0, tableCtrl.selected.length, self.model); + } + + if(angular.isFunction(self.onSelect)) { + self.onSelect(self.model); + } + }; + + self.deselect = function () { + if(self.disabled) { + return; + } + + tableCtrl.selected.splice(tableCtrl.selected.indexOf(self.model), 1); + + if(angular.isFunction(self.onDeselect)) { + self.onDeselect(self.model); + } + }; + + self.toggle = function (event) { + if(event && event.stopPropagation) { + event.stopPropagation(); + } + + return self.isSelected() ? self.deselect() : self.select(); + }; + + function autoSelect() { + return attrs.mdAutoSelect === '' || self.autoSelect; + } + + function createCheckbox() { + var checkbox = angular.element('<md-checkbox>').attr({ + 'aria-label': 'Select Row', + 'ng-click': '$mdSelect.toggle($event)', + 'ng-checked': '$mdSelect.isSelected()', + 'ng-disabled': '$mdSelect.disabled' + }); + + return angular.element('<td class="md-cell md-checkbox-cell">').append($compile(checkbox)(scope)); + } + + function disableSelection() { + Array.prototype.some.call(element.children(), function (child) { + return child.classList.contains('md-checkbox-cell') && element[0].removeChild(child); + }); + + if(autoSelect()) { + element.off('click', toggle); + } + } + + function enableSelection() { + element.prepend(createCheckbox()); + + if(autoSelect()) { + element.on('click', toggle); + } + } + + function enableRowSelection() { + return tableCtrl.$$rowSelect; + } + + function onSelectChange(selected) { + if(!self.id) { + return; + } + + if(tableCtrl.$$hash.has(self.id)) { + // check if the item has been deselected + if(selected.indexOf(tableCtrl.$$hash.get(self.id)) === -1) { + tableCtrl.$$hash.purge(self.id); + } + + return; + } + + // check if the item has been selected + if(selected.indexOf(self.model) !== -1) { + tableCtrl.$$hash.update(self.id, self.model); + } + } + + function toggle(event) { + scope.$applyAsync(function () { + self.toggle(event); + }); + } + + scope.$watch(enableRowSelection, function (enable) { + if(enable) { + enableSelection(); + } else { + disableSelection(); + } + }); + + scope.$watch(autoSelect, function (newValue, oldValue) { + if(newValue === oldValue) { + return; + } + + if(tableCtrl.$$rowSelect && newValue) { + element.on('click', toggle); + } else { + element.off('click', toggle); + } + }); + + scope.$watch(self.isSelected, function (isSelected) { + return isSelected ? element.addClass('md-selected') : element.removeClass('md-selected'); + }); + + scope.$watch(tableCtrl.enableMultiSelect, function (multiple) { + if(tableCtrl.$$rowSelect && !multiple) { + // remove all but the first selected item + tableCtrl.selected.splice(1); + } + }); + + tableCtrl.registerModelChangeListener(onSelectChange); + + element.on('$destroy', function () { + tableCtrl.removeModelChangeListener(onSelectChange); + }); + } + + return { + bindToController: true, + controller: Controller, + controllerAs: '$mdSelect', + link: postLink, + require: ['mdSelect', '^^mdTable'], + restrict: 'A', + scope: { + model: '=mdSelect', + disabled: '=ngDisabled', + onSelect: '=?mdOnSelect', + onDeselect: '=?mdOnDeselect', + autoSelect: '=mdAutoSelect' + } + }; +} + +mdSelect.$inject = ['$compile', '$parse']; + +angular.module('md.data.table').directive('mdTable', mdTable); + +function Hash() { + var keys = {}; + + this.equals = function (key, item) { + return keys[key] === item; + }; + + this.get = function (key) { + return keys[key]; + }; + + this.has = function (key) { + return keys.hasOwnProperty(key); + }; + + this.purge = function (key) { + delete keys[key]; + }; + + this.update = function (key, item) { + keys[key] = item; + }; +} + +function mdTable() { + + function compile(tElement, tAttrs) { + tElement.addClass('md-table'); + + if(tAttrs.hasOwnProperty('mdProgress')) { + var body = tElement.find('tbody')[0]; + var progress = angular.element('<thead class="md-table-progress" md-table-progress>'); + + if(body) { + tElement[0].insertBefore(progress[0], body); + } + } + } + + function Controller($attrs, $element, $q, $scope) { + var self = this; + var queue = []; + var watchListener; + var modelChangeListeners = []; + + self.$$hash = new Hash(); + self.$$columns = {}; + + function enableRowSelection() { + self.$$rowSelect = true; + + watchListener = $scope.$watchCollection('$mdTable.selected', function (selected) { + modelChangeListeners.forEach(function (listener) { + listener(selected); + }); + }); + + $element.addClass('md-row-select'); + } + + function disableRowSelection() { + self.$$rowSelect = false; + + if(angular.isFunction(watchListener)) { + watchListener(); + } + + $element.removeClass('md-row-select'); + } + + function resolvePromises() { + if(!queue.length) { + return $scope.$applyAsync(); + } + + queue[0]['finally'](function () { + queue.shift(); + resolvePromises(); + }); + } + + function rowSelect() { + return $attrs.mdRowSelect === '' || self.rowSelect; + } + + function validateModel() { + if(!self.selected) { + return console.error('Row selection: ngModel is not defined.'); + } + + if(!angular.isArray(self.selected)) { + return console.error('Row selection: Expected an array. Recived ' + typeof self.selected + '.'); + } + + return true; + } + + self.columnCount = function () { + return self.getRows($element[0]).reduce(function (count, row) { + return row.cells.length > count ? row.cells.length : count; + }, 0); + }; + + self.getRows = function (element) { + return Array.prototype.filter.call(element.rows, function (row) { + return !row.classList.contains('ng-leave'); + }); + }; + + self.getBodyRows = function () { + return Array.prototype.reduce.call($element.prop('tBodies'), function (result, tbody) { + return result.concat(self.getRows(tbody)); + }, []); + }; + + self.getElement = function () { + return $element; + }; + + self.getHeaderRows = function () { + return self.getRows($element.prop('tHead')); + }; + + self.enableMultiSelect = function () { + return $attrs.multiple === '' || $scope.$eval($attrs.multiple); + }; + + self.waitingOnPromise = function () { + return !!queue.length; + }; + + self.queuePromise = function (promise) { + if(!promise) { + return; + } + + if(queue.push(angular.isArray(promise) ? $q.all(promise) : $q.when(promise)) === 1) { + resolvePromises(); + } + }; + + self.registerModelChangeListener = function (listener) { + modelChangeListeners.push(listener); + }; + + self.removeModelChangeListener = function (listener) { + var index = modelChangeListeners.indexOf(listener); + + if(index !== -1) { + modelChangeListeners.splice(index, 1); + } + }; + + if($attrs.hasOwnProperty('mdProgress')) { + $scope.$watch('$mdTable.progress', self.queuePromise); + } + + $scope.$watch(rowSelect, function (enable) { + if(enable && !!validateModel()) { + enableRowSelection(); + } else { + disableRowSelection(); + } + }); + } + + Controller.$inject = ['$attrs', '$element', '$q', '$scope']; + + return { + bindToController: true, + compile: compile, + controller: Controller, + controllerAs: '$mdTable', + restrict: 'A', + scope: { + progress: '=?mdProgress', + selected: '=ngModel', + rowSelect: '=mdRowSelect' + } + }; +} + +angular.module('md.data.table').directive('mdTablePagination', mdTablePagination); + +function mdTablePagination() { + + function compile(tElement) { + tElement.addClass('md-table-pagination'); + } + + function Controller($attrs, $mdUtil, $scope) { + var self = this; + var defaultLabel = { + page: 'Page:', + rowsPerPage: 'Rows per page:', + of: 'of' + }; + + self.label = angular.copy(defaultLabel); + + function isPositive(number) { + return parseInt(number, 10) > 0; + } + + self.eval = function (expression) { + return $scope.$eval(expression); + }; + + self.first = function () { + self.page = 1; + self.onPaginationChange(); + }; + + self.hasNext = function () { + return self.page * self.limit < self.total; + }; + + self.hasPrevious = function () { + return self.page > 1; + }; + + self.last = function () { + self.page = self.pages(); + self.onPaginationChange(); + }; + + self.max = function () { + return self.hasNext() ? self.page * self.limit : self.total; + }; + + self.min = function () { + return isPositive(self.total) ? self.page * self.limit - self.limit + 1 : 0; + }; + + self.next = function () { + self.page++; + self.onPaginationChange(); + }; + + self.onPaginationChange = function () { + if(angular.isFunction(self.onPaginate)) { + $mdUtil.nextTick(function () { + self.onPaginate(self.page, self.limit); + }); + } + }; + + self.pages = function () { + return isPositive(self.total) ? Math.ceil(self.total / (isPositive(self.limit) ? self.limit : 1)) : 1; + }; + + self.previous = function () { + self.page--; + self.onPaginationChange(); + }; + + self.showBoundaryLinks = function () { + return $attrs.mdBoundaryLinks === '' || self.boundaryLinks; + }; + + self.showPageSelect = function () { + return $attrs.mdPageSelect === '' || self.pageSelect; + }; + + $scope.$watch('$pagination.limit', function (newValue, oldValue) { + if(isNaN(newValue) || isNaN(oldValue) || newValue === oldValue) { + return; + } + + // find closest page from previous min + self.page = Math.floor(((self.page * oldValue - oldValue) + newValue) / (isPositive(newValue) ? newValue : 1)); + self.onPaginationChange(); + }); + + $attrs.$observe('mdLabel', function (label) { + angular.extend(self.label, defaultLabel, $scope.$eval(label)); + }); + + $scope.$watch('$pagination.total', function (newValue, oldValue) { + if(isNaN(newValue) || newValue === oldValue) { + return; + } + + if(self.page > self.pages()) { + self.last(); + } + }); + } + + Controller.$inject = ['$attrs', '$mdUtil', '$scope']; + + return { + bindToController: { + boundaryLinks: '=?mdBoundaryLinks', + disabled: '=ngDisabled', + limit: '=mdLimit', + page: '=mdPage', + pageSelect: '=?mdPageSelect', + onPaginate: '=?mdOnPaginate', + limitOptions: '=?mdLimitOptions', + total: '@mdTotal' + }, + compile: compile, + controller: Controller, + controllerAs: '$pagination', + restrict: 'E', + scope: {}, + templateUrl: 'md-table-pagination.html' + }; +} + +angular.module('md.data.table').directive('mdTableProgress', mdTableProgress); + +function mdTableProgress() { + + function postLink(scope, element, attrs, tableCtrl) { + scope.columnCount = tableCtrl.columnCount; + scope.deferred = tableCtrl.waitingOnPromise; + } + + return { + link: postLink, + require: '^^mdTable', + restrict: 'A', + scope: {}, + templateUrl: 'md-table-progress.html' + }; +} + +angular.module('md.data.table').directive('virtualPageSelect', virtualPageSelect); + +function virtualPageSelect() { + + function Controller($element, $scope) { + var self = this; + var content = $element.find('md-content'); + + self.pages = []; + + function getMin(pages, total) { + return Math.min(pages, isFinite(total) && isPositive(total) ? total : 1); + } + + function isPositive(number) { + return number > 0; + } + + function setPages(max) { + if(self.pages.length > max) { + return self.pages.splice(max); + } + + for(var i = self.pages.length; i < max; i++) { + self.pages.push(i + 1); + } + } + + content.on('scroll', function () { + if((content.prop('clientHeight') + content.prop('scrollTop')) >= content.prop('scrollHeight')) { + $scope.$applyAsync(function () { + setPages(getMin(self.pages.length + 10, self.total)); + }); + } + }); + + $scope.$watch('$pageSelect.total', function (total) { + setPages(getMin(Math.max(self.pages.length, 10), total)); + }); + + $scope.$watch('$pagination.page', function (page) { + for(var i = self.pages.length; i < page; i++) { + self.pages.push(i + 1); + } + }); + } + + Controller.$inject = ['$element', '$scope']; + + return { + bindToController: { + total: '@' + }, + controller: Controller, + controllerAs: '$pageSelect' + }; +} + +})(window, angular);
\ No newline at end of file |