angular.module("ngRows",[]).directive("ngRows",function($compile){return{restrict:"A",scope:{ngRows:"<",ngSelected:"="},controller:function($scope){var vm=$scope;vm.Math=Math;vm.Date=Date;vm.selected=vm.ngSelected;vm.pages={current:1,sizes:["10","25","50","100"],totalPages:function(){return Math.ceil(vm.filteredRows.length/vm.pages.size)},};vm.pages.size=vm.pages.sizes[0];vm.toggleSelect=function(row){if(!vm.isSelected(row))vm.selected.add(row);else vm.selected.delete(row)};vm.isSelected=function(row){return vm.selected.has(row)};vm.allSelected=function(rows){var adds=0;rows.forEach(function(row){adds+=!vm.selected.has(row)});return!adds};vm.toggleSelectAll=function(rows){var adds=0;rows.forEach(function(row){adds+=!vm.selected.has(row);vm.selected.add(row)});if(!adds)vm.selected.clear()};vm.setPage=function(page,$event){if($event)$event.preventDefault();if(page>0&&page<=vm.pages.totalPages())vm.pages.current=page};vm.generatePages=function(current,total){if(total<=7){var result=[];for(var i=1;i<=total;i++)result.push(i);return result}else if(current<=4)return[1,2,3,4,5,0,total];else if(total-current<=3)return[1,0,total-4,total-3,total-2,total-1,total];else return[1,0,current-1,current,current+1,0,total]};vm.getPageRows=function(rows){if(rows){var start=(vm.pages.current-1)*vm.pages.size;var end=vm.pages.current*vm.pages.size;return rows.slice(start,end)}};vm.filterRows=function(newSort){if(vm.pages.search){var rows=!newSort&&vm.pages.search.indexOf(vm.pages.oldSearch)!==-1?vm.filteredRows:vm.sortedRows;vm.filteredRows=rows.filter(function(row){if(vm.pages.search){var toSearch=Object.keys(row).map(function(key){var value=row[key];return value&&typeof value!=="object"&&value.toString().toLowerCase()});var match=!0;vm.pages.search.toLowerCase().split(" ").forEach(function(search){match=match&&toSearch.some(function(x){return x&&x.indexOf(search)!==-1})});return match}else return!0})}else{vm.filteredRows=vm.sortedRows}vm.pages.oldSearch=vm.pages.search;vm.pages.current=1};vm.sortCol=function(i){var col=vm.pages.headers[i];if(!col.order)col.order=1;else if(col.order===1)col.order=-1;else col.order=0;vm.pages.sorting=col.order?col:null;Object.keys(vm.pages.headers).forEach(function(key){var header=vm.pages.headers[key];if(header!==col)header.order=0});sortRows()};function sortRows(){var col=vm.pages.sorting;if(col&&col.order){vm.sortedRows=vm.ngRows.slice().sort(function(a,b){if(a[col.key]instanceof Date&&b[col.key]instanceof Date)return col.order*(a[col.key].getTime()-b[col.key].getTime());if(col.order===1) if(a[col.key]>b[col.key]) return 1;else if(a[col.key]<b[col.key])return-1;else return 0;else if(a[col.key]<b[col.key])return 1;else if(a[col.key]>b[col.key])return-1;else return 0})}else vm.sortedRows=vm.ngRows;vm.filterRows(!0)}vm.commaString=function(n){if(n){return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}};vm.$watch("ngRows",function(){sortRows()});var ancestor=vm.$parent;while(ancestor){Object.keys(ancestor).forEach(function(key){if(vm[key]===undefined&&key.indexOf("$")===-1){var $ancestor=ancestor;Object.defineProperty(vm,key,{get:function(){return $ancestor[key]},})}});ancestor=ancestor.$parent}},compile:function(row){var$=angular.element;function find(_this,query){if(!query)return $();var ret=[];angular.forEach(_this,function(el){if(el.querySelectorAll){angular.forEach(el.querySelectorAll(query),function(item){ret.push(item)})}});return $(ret)}function insertBefore(_this,element){if(!element)return $();angular.forEach(_this,function(el){element.parent()[0].insertBefore(el,element[0])});return _this}return function(vm,parent){var $contents=$(parent.html());parent.html("");var $headerRow=find($contents,"thead tr");var $dataRow=find($contents,"tr[ng-row]");var rowName=$dataRow.attr("ng-row")||"row";$dataRow.attr("ng-repeat",rowName+" in getPageRows(filteredRows) track by $index");var $headerCols=find($headerRow,"th");var $dataCols=find($dataRow,"td");angular.forEach($headerCols,function(el,i){var $th=$(el);var sortable=$th.attr("ng-sortable")!==undefined;if(sortable){var $td=$($dataCols[i]);if($td.attr("ng-data")) match=new RegExp(rowName+"\\.(.*?)(?:\\s.*?)?$").exec($td.attr("ng-data"));else match=new RegExp("{{"+rowName+"\\.(.*?)(?:\\s.*?)?}}").exec($td.text());if(!match&&$td.attr("ng-bind-html")) match=new RegExp(rowName+"\\.(.*?)(?:\\s.*?)?$").exec($td.attr("ng-bind-html"));if(match){var key=match[1];$th.attr("ng-class","{ sorting: pages.headers["+i+"].order === 0, "+"sorting_asc: pages.headers["+i+"].order === 1, "+"sorting_desc: pages.headers["+i+"].order === -1 }");$th.attr("ng-click","sortCol("+i+")");vm.pages.headers[i]={order:0,key:key}}}});if(parent.attr("ng-selected")!==undefined){$dataRow.prepend('<td ng-selectable ng-click="toggleSelect('+rowName+')""></td>').attr("ng-selectable",null).attr("ng-class",(($dataRow.attr("ng-class")||"")+"{ selected: isSelected("+rowName+") }").replace("}{",","));$headerRow.prepend('<td ng-selectable ng-click="toggleSelectAll(filteredRows)" ng-class="{ selected: filteredRows.length && allSelected(filteredRows) }"></td>')}td[ng-selectable]{cursor:pointer;width:25px;padding:8px!important}td[ng-selectable]:after{content:"";display:block;width:25px;height:25px;background:#eee;box-shadow:inset 0 1px 3px rgb(0 0 0 / .4)}td[ng-selectable]:hover:after{background:#ccc}tr.selected td[ng-selectable]:after,td.selected[ng-selectable]:after{content:"\2713";color:#fff;text-align:center;font-weight:700;display:block;width:25px;height:25px;background:#2196f3}tr.selected td{background:#337ab7;color:#fff}