diff --git a/Gruntfile.js b/Gruntfile.js index 5453f14b3..44335dd0d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -116,6 +116,7 @@ module.exports = function (grunt) { 'lib/patternfly/components/d3/d3.js', 'lib/angular/angular.js', 'lib/angular-animate/angular-animate.js', + 'lib/lodash/lodash.min.js', 'dist/angular-patternfly.js', 'lib/patternfly/dist/js/patternfly.js'], html5Mode: false, @@ -156,6 +157,11 @@ module.exports = function (grunt) { cwd: 'src/', src: ['charts/**/*.html'], dest: 'templates/charts.js' + }, + 'patternfly.views': { + cwd: 'src/', + src: ['views/**/*.html'], + dest: 'templates/views.js' } }, // ng-annotate tries to make the code safe for minification automatically diff --git a/bower.json b/bower.json index 89e32b3ac..c62e3f198 100644 --- a/bower.json +++ b/bower.json @@ -40,6 +40,7 @@ "angular-sanitize": "1.3.*", "angular-touch": "1.3.*", "angular-route": "1.3.*", + "lodash": "3.x", "patternfly": "~2.0.0" } } diff --git a/dist/angular-patternfly.js b/dist/angular-patternfly.js index 003b0c5fa..5633e9ac4 100644 --- a/dist/angular-patternfly.js +++ b/dist/angular-patternfly.js @@ -34,9 +34,21 @@ angular.module('patternfly', [ 'patternfly.form', 'patternfly.notification', 'patternfly.select', - 'patternfly.validation' + 'patternfly.utils', + 'patternfly.validation', + 'patternfly.views' ]); +; +angular.module( 'patternfly.utils', [] ); +;/** + * @name patternfly + * + * @description + * Views module for patternfly. + * + */ +angular.module('patternfly.views', ['patternfly.utils']); ;/** * @ngdoc directive * @name patternfly.autofocus:pfFocused @@ -1959,7 +1971,181 @@ angular.module('patternfly.select', []).directive('pfSelect', ["$timeout", funct }); } }; +<<<<<<< HEAD }]); +======= +}); +; +/** + * @ngdoc directive + * @name patternfly.utils.directive:pfTransclude + * @restrict A + * @element ANY + * @param {string} pfTransclude specifies the type of transclusion to use.
+ * Values: + * + * + * @description + * Directive for transcluding in directives and setting up scope of children of parent directives. This is a workaround + * for https://github.com/angular/angular.js/issues/5489 + * + * @example + + + +
+ Here the scope id is: {{$id}} + + +
This content was transcluded using pf-transclude or pf-transclude="sibling".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+ + +
This content was transcluded using pf-transclude="parent".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+ + +
This content was transcluded using pf-transclude="child".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+
+
+ + + angular.module('patternfly.utils') + .controller( 'UtilCtrl', function($scope) { + + }) + + .config(function($provide){ + $provide.decorator('ngTranscludeDirective', ['$delegate', function($delegate) { + // Remove the original directive + $delegate.shift(); + return $delegate; + }]); + }) + + .directive( 'transcludeSibling', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + + .directive( 'transcludeParent', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + + .directive( 'transcludeChild', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + ; +
+
+ */ +angular + .module('patternfly.utils').directive('pfTransclude', function () { + 'use strict'; + return { + restrict: 'A', + link: function ($scope, $element, $attrs, controller, $transclude) { + var iChildScope; + var iScopeType; + + if (!$transclude) { + throw new Error('pfTransclude - ' + + 'Illegal use of pfTransclude directive in the template! ' + + 'No parent directive that requires a transclusion found. ' + + 'Element: {0}'); + } + + iScopeType = $attrs.pfTransclude || 'sibling'; + + switch (iScopeType) { + case 'sibling': + $transclude(function (clone) { + $element.empty(); + $element.append(clone); + }); + break; + case 'parent': + $transclude($scope, function (clone) { + $element.empty(); + $element.append( clone ); + }); + break; + case 'child': + iChildScope = $scope.$new(); + $transclude( iChildScope, function (clone) { + $element.empty(); + $element.append( clone ); + $element.on( '$destroy', function () { + iChildScope.$destroy(); + }); + }); + break; + } + } + }; + }); +>>>>>>> Add Data List Directive ;/** * @ngdoc directive * @name patternfly.validation:pfValidation @@ -2126,7 +2312,322 @@ angular.module('patternfly.validation', []).directive('pfValidation', ["$timeout } } }; +<<<<<<< HEAD }]); +======= +}); +;/** + * @ngdoc directive + * @name patternfly.views.directive:pfDataList + * + * @description + * Directive for rendering a data list. + *

+ * + * @param {object} config configuration settings for the data list:
+ * + * + * @param {Array} items the data to be shown in the data list
+ * + * @example + + + +
+
+
+
+
+ {{item.name}} +
+
+ {{item.address}} +
+
+ {{item.city}} +
+
+ {{item.state}} +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ +
+
+
+
+ + +
+
+ +
+
+ +
+
+
+ + + angular.module('patternfly.views').controller('ViewCtrl', ['$scope', + function ($scope) { + $scope.eventText = ''; + var handleSelect = function (item, e) { + $scope.eventText = item.name + ' selected\n' + $scope.eventText; + }; + var handleSelectionChange = function (selectedItems, e) { + $scope.eventText = selectedItems.length + ' items selected\n' + $scope.eventText; + }; + var handleClick = function (item, e) { + $scope.eventText = item.name + ' clicked\n' + $scope.eventText; + }; + var handleDblClick = function (item, e) { + $scope.eventText = item.name + ' double clicked\n' + $scope.eventText; + }; + var handleCheckBoxChange = function (item, selected, e) { + $scope.eventText = item.name + ' checked: ' + item.selected + '\n' + $scope.eventText; + }; + + var checkDisabledItem = function(item) { + return $scope.showDisabled && (item.name === "John Smith"); + }; + + $scope.showDisabled = false; + + $scope.config = { + selectItems: false, + multiSelect: false, + dblClick: false, + selectionMatchProp: 'name', + selectedItems: [], + checkDisabled: checkDisabledItem, + showSelectBox: true, + rowHeight: 36, + onSelect: handleSelect, + onSelectionChange: handleSelectionChange, + onCheckBoxChange: handleCheckBoxChange, + onClick: handleClick, + onDblClick: handleDblClick + }; + + $scope.items = [ + { + name: "Fred Flintstone", + address: "20 Dinosaur Way", + city: "Bedrock", + state: "Washingstone" + }, + { + name: "John Smith", + address: "415 East Main Street", + city: "Norfolk", + state: "Virginia" + }, + { + name: "Frank Livingston", + address: "234 Elm Street", + city: "Pittsburgh", + state: "Pennsylvania" + }, + { + name: "Judy Green", + address: "2 Apple Boulevard", + city: "Cincinatti", + state: "Ohio" + }, + { + name: "Pat Thomas", + address: "50 Second Street", + city: "New York", + state: "New York" + }, + ] + } + ]); + +
+ */ +angular.module('patternfly.views').directive('pfDataList', [ + function () { + 'use strict'; + return { + restrict: 'A', + scope: { + config: '=?', + items: '=', + eventId: '@id' + }, + transclude: true, + templateUrl: 'views/datalist/data-list.html', + controller: ['$scope', + function ($scope) { + $scope.defaultConfig = { + selectItems: false, + multiSelect: false, + dblClick: false, + selectionMatchProp: 'uuid', + selectedItems: [], + checkDisabled: false, + showSelectBox: true, + rowHeight: 36, + onSelect: null, + onSelectionChange: null, + onCheckBoxChange: null, + onClick: null, + onDblClick: null + }; + + $scope.config = $.extend(true, angular.copy($scope.defaultConfig), $scope.config); + } + ], + + link: function (scope, element, attrs) { + attrs.$observe('config', function () { + scope.config = $.extend(true, angular.copy(scope.defaultConfig), scope.config); + if (!scope.config.selectItems) { + scope.config.selectedItems = []; + } + if (!scope.config.multiSelect && scope.config.selectedItems && scope.config.selectedItems.length > 0) { + scope.config.selectedItems = [scope.config.selectedItems[0]]; + } + }); + + scope.itemClick = function (e, item) { + var alreadySelected; + var selectionChanged = false; + var continueEvent = true; + + // Ignore disabled item clicks completely + if (scope.checkDisabled(item)) { + return continueEvent; + } + + if (scope.config && scope.config.selectItems && item) { + if (scope.config.multiSelect && !scope.config.dblClick) { + + alreadySelected = _.find(scope.config.selectedItems, function (itemObj) { + return itemObj === item; + }); + + if (alreadySelected) { + // already selected so deselect + scope.config.selectedItems = _.without(scope.config.selectedItems, item); + } else { + // add the item to the selected items + scope.config.selectedItems.push(item); + selectionChanged = true; + } + } else { + if (scope.config.selectedItems[0] === item) { + if (!scope.config.dblClick) { + scope.config.selectedItems = []; + selectionChanged = true; + } + continueEvent = false; + } else { + scope.config.selectedItems = [item]; + selectionChanged = true; + } + } + + if (selectionChanged && scope.config.onSelect) { + scope.config.onSelect(item, e); + } + if (selectionChanged && scope.config.onSelectionChange) { + scope.config.onSelectionChange(scope.config.selectedItems, e); + } + } + if (scope.config.onClick) { + scope.config.onClick(item, e); + } + + return continueEvent; + }; + + scope.dblClick = function (e, item) { + if (scope.config.onDblClick) { + scope.config.onDblClick(item, e); + } + }; + + scope.checkBoxChange = function (item) { + if (scope.config.onCheckBoxChange) { + scope.config.onCheckBoxChange(item); + } + }; + + scope.isSelected = function (item) { + var matchProp = scope.config.selectionMatchProp; + if (scope.config.selectedItems.length) { + return _.find(scope.config.selectedItems, function (itemObj) { + return itemObj[matchProp] === item[matchProp]; + }); + } + return false; + }; + + scope.checkDisabled = function (item) { + return scope.config.checkDisabled && scope.config.checkDisabled(item); + }; + } + }; + } +]); +>>>>>>> Add Data List Directive ;angular.module('patternfly.card').run(['$templateCache', function($templateCache) { 'use strict'; @@ -2184,3 +2685,11 @@ angular.module('patternfly.validation', []).directive('pfValidation', ["$timeout ); }]); +;angular.module('patternfly.views').run(['$templateCache', function($templateCache) { + 'use strict'; + + $templateCache.put('views/datalist/data-list.html', + "
" + ); + +}]); diff --git a/dist/angular-patternfly.min.js b/dist/angular-patternfly.min.js index cf77e615a..73b48b00e 100644 --- a/dist/angular-patternfly.min.js +++ b/dist/angular-patternfly.min.js @@ -1 +1,5 @@ -angular.module("patternfly.card",[]),angular.module("patternfly.charts",[]),angular.module("patternfly.form",[]),angular.module("patternfly",["patternfly.autofocus","patternfly.card","patternfly.form","patternfly.notification","patternfly.select","patternfly.validation"]),angular.module("patternfly.autofocus",[]).directive("pfFocused",["$timeout",function($timeout){"use strict";return{restrict:"A",link:function(scope,element,attrs){scope.$watch(attrs.pfFocused,function(newValue){$timeout(function(){newValue&&(element[0].focus(),element[0].select&&element[0].select())})})}}}]),angular.module("patternfly.card").directive("pfCard",function(){"use strict";return{restrict:"A",transclude:!0,templateUrl:"card/basic/card.html",scope:{headTitle:"@",subTitle:"@?",showTopBorder:"@?"}}}),function(){"use strict";angular.module("patternfly.charts").constant("c3ChartDefaults",{getDefaultDonut:function(title){return{title:title,label:{show:!1},width:10}},getDefaultDonutSize:function(){return{height:130}},getDefaultDonutColor:function(){return{pattern:["#0088CE","#D1D1D1"]}},getDefaultDonutTooltip:function(){return{show:!1}},getDefaultDonutLegend:function(){return{show:!1}},getDefaultDonutConfig:function(title){return{donut:this.getDefaultDonut(title),size:this.getDefaultDonutSize(),legend:this.getDefaultDonutLegend(),color:this.getDefaultDonutColor(),tooltip:this.getDefaultDonutTooltip()}},getDefaultSparklineArea:function(){return{zerobased:!0}},getDefaultSparklineSize:function(){return{height:60}},getDefaultSparklineAxis:function(){return{x:{show:!1},y:{show:!1}}},getDefaultSparklineColor:function(){return{pattern:["#0088ce","#00659c","#3f9c35","#ec7a08","#cc0000"]}},getDefaultSparklineLegend:function(){return{show:!1}},getDefaultSparklinePoint:function(){return{r:1,focus:{expand:{r:4}}}},getDefaultSparklineTooltip:function(){return{contents:function(d){return''+d[0].value+" "+d[0].name+""}}},getDefaultSparklineConfig:function(){return{area:this.getDefaultSparklineArea(),size:this.getDefaultSparklineSize(),axis:this.getDefaultSparklineAxis(),color:this.getDefaultSparklineColor(),legend:this.getDefaultSparklineLegend(),point:this.getDefaultSparklinePoint(),tooltip:this.getDefaultSparklineTooltip()}}})}(),function(c3){"use strict";angular.module("patternfly.charts").directive("pfC3Chart",["$timeout",function($timeout){return{restrict:"A",scope:{config:"="},template:'
',replace:!0,link:function(scope,element,attrs){scope.$watch("config",function(){$timeout(function(){var chartData=scope.config;chartData.bindto="#"+attrs.id,c3.generate(chartData)})},!0)}}}])}(c3),angular.module("patternfly.charts").directive("pfDonutPctChart",["c3ChartDefaults","$timeout",function(c3ChartDefaults,$timeout){"use strict";return{restrict:"A",scope:{config:"=",data:"=",centerLabel:"=?"},replace:!0,templateUrl:"charts/donut/donut-pct-chart.html",controller:["$scope",function($scope){var donutTooltip;$scope.donutChartId="donutChart",$scope.config.chartId&&($scope.donutChartId=$scope.config.chartId+$scope.donutChartId),$scope.updateAvailable=function(){$scope.data.available=$scope.data.total-$scope.data.used},void 0===$scope.data.available&&$scope.updateAvailable(),$scope.getStatusColor=function(used,thresholds){var color="#0088CE";return thresholds&&(used>=thresholds.error?color="#CC0000":used>=thresholds.warning&&(color="#EC7A08")),color},$scope.statusDonutColor=function(scope){var color,percentUsed;return color={pattern:[]},percentUsed=scope.data.used/scope.data.total*100,color.pattern[0]=$scope.getStatusColor(percentUsed,scope.config.thresholds),color.pattern[1]="#D1D1D1",color},donutTooltip=function(scope){return{contents:function(d){var tooltipHtml;return tooltipHtml=scope.config.tooltipFn?''+scope.config.tooltipFn(d)+"":''+Math.round(100*d[0].ratio)+"% "+$scope.config.units+" "+d[0].name+""}}},$scope.getDonutData=function(scope){return{columns:[["Used",scope.data.used],["Available",scope.data.available]],type:"donut",donut:{label:{show:!1}},groups:[["used","available"]],order:null}},$scope.updateAll=function(scope){$scope.updateAvailable(),$scope.config.data=$scope.getDonutData($scope),$scope.config.color=$scope.statusDonutColor($scope),$scope.config.tooltip=donutTooltip(scope)},$scope.config=$.extend(!0,c3ChartDefaults.getDefaultDonutConfig(),$scope.config),$scope.updateAll($scope)}],link:function(scope,element){var setupDonutChartTitle=function(){$timeout(function(){var donutChartTitle,bigText,smText;donutChartTitle=element[0].querySelector("text.c3-chart-arcs-title"),scope.config.centerLabelFn?donutChartTitle.innerHTML=scope.config.centerLabelFn(scope):"none"===scope.centerLabel?donutChartTitle.innerHTML="":(bigText=scope.data.used,smText=scope.config.units+" Used","available"===scope.centerLabel?(bigText=scope.data.available,smText=scope.config.units+" Available"):"percent"===scope.centerLabel&&(bigText=Math.round(scope.data.used/scope.data.total*100)+"%",smText="of "+scope.data.total+" "+scope.config.units),donutChartTitle&&(donutChartTitle.innerHTML=''+bigText+''+smText+""))},300)};scope.$watch("config",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("data",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("centerLabel",function(){setupDonutChartTitle()})}}}]),angular.module("patternfly.charts").directive("pfSparklineChart",["c3ChartDefaults",function(c3ChartDefaults){"use strict";return{restrict:"A",scope:{config:"=",chartData:"=",chartHeight:"=?",showXAxis:"=?",showYAxis:"=?"},replace:!0,templateUrl:"charts/sparkline/sparkline-chart.html",controller:["$scope",function($scope){$scope.sparklineChartId="sparklineChart",$scope.config.chartId&&($scope.sparklineChartId=$scope.config.chartId+$scope.sparklineChartId),$scope.getSparklineData=function(chartData){return{x:chartData.xData[0],columns:[chartData.xData,chartData.yData],type:"area"}},$scope.getTooltipTableHTML=function(tipRows){return'
'+tipRows+"
"},$scope.sparklineTooltip=function(){return{contents:function(d){var tipRows,percentUsed;if($scope.config.tooltipFn)tipRows=$scope.config.tooltipFn(d);else switch($scope.config.tooltipType){case"usagePerDay":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+d[0].x.toLocaleDateString()+' '+percentUsed+'%: '+d[0].value+" "+$scope.config.units+" "+d[0].name+"";break;case"valuePerDay":tipRows=' '+d[0].x.toLocaleDateString()+' '+d[0].value+" "+d[0].name+"";break;case"percentage":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+percentUsed+"%";break;default:tipRows=c3ChartDefaults.getDefaultSparklineTooltip().contents(d)}return $scope.getTooltipTableHTML(tipRows)},position:function(data,width,height,element){var center,top,chartBox,graphOffsetX,x;try{return center=parseInt(element.getAttribute("x")),top=parseInt(element.getAttribute("y")),chartBox=document.querySelector("#"+$scope.sparklineChartId).getBoundingClientRect(),graphOffsetX=document.querySelector("#"+$scope.sparklineChartId+" g.c3-axis-y").getBoundingClientRect().right,x=Math.max(0,center+graphOffsetX-chartBox.left-Math.floor(width/2)),{top:top-height,left:Math.min(x,chartBox.width-width)}}catch(e){}}}},void 0===$scope.showXAxis&&($scope.showXAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),void 0===$scope.showYAxis&&($scope.showYAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),$scope.defaultConfig=c3ChartDefaults.getDefaultSparklineConfig(),$scope.defaultConfig.axis={x:{show:$scope.showXAxis===!0,type:"timeseries",tick:{format:function(){return""}}},y:{show:$scope.showYAxis===!0,tick:{format:function(){return""}}}},$scope.defaultConfig.tooltip=$scope.sparklineTooltip(),$scope.chartHeight&&($scope.defaultConfig.size.height=$scope.chartHeight),$scope.defaultConfig.units="",$scope.config=$.extend(!0,angular.copy($scope.defaultConfig),$scope.config),$scope.config.data=$scope.getSparklineData($scope.chartData)}],link:function(scope){scope.$watch("config",function(){scope.config=$.extend(!0,angular.copy(scope.defaultConfig),scope.config)},!0),scope.$watch("chartHeight",function(){scope.config.size.height=scope.chartHeight}),scope.$watch("showXAxis",function(){scope.config.axis.x.show=scope.showXAxis===!0}),scope.$watch("showYAxis",function(){scope.config.axis.y.show=scope.showYAxis===!0}),scope.$watch("chartData",function(){scope.config.data=scope.getSparklineData(scope.chartData)},!0)}}}]),angular.module("patternfly.charts").directive("pfUtilizationChart",function(){"use strict";return{restrict:"A",scope:{chartData:"=",config:"=",centerLabel:"=?",donutConfig:"=",sparklineConfig:"=",sparklineChartHeight:"=?",showSparklineXAxis:"=?",showSparklineYAxis:"=?"},replace:!0,templateUrl:"charts/utilization/utilization-chart.html",controller:["$scope",function($scope){void 0===$scope.centerLabel&&($scope.centerLabel="used"),void 0===$scope.donutConfig.units&&($scope.donutConfig.units=$scope.config.units),void 0===$scope.chartData.available&&($scope.chartData.available=$scope.chartData.total-$scope.chartData.used),$scope.config.units=$scope.config.units||$scope.units}],link:function(scope){var setupCurrentValues=function(){"available"===scope.centerLabel?(scope.currentValue=scope.chartData.used,scope.currentText="Used"):(scope.currentValue=scope.chartData.total-scope.chartData.used,scope.currentText="Available")};scope.$watch("centerLabel",function(){setupCurrentValues()})}}}),angular.module("patternfly.form").directive("pfDatepicker",function(){"use strict";return{replace:!0,restrict:"A",require:"^form",templateUrl:"form/datepicker/datepicker.html",scope:{options:"=",date:"="},link:function($scope,element){element.datepicker($scope.options),element.datepicker("update",$scope.date),element.datepicker($scope.date).on("changeDate",function(elem){$scope.$apply(function(){$scope.date=elem.date})}),$scope.$watch("date",function(newValue,oldValue){oldValue!==newValue&&element.datepicker("update",newValue)})}}}),angular.module("patternfly.form").directive("pfFormButtons",function(){"use strict";return{replace:!0,require:"^form",templateUrl:"form/form-buttons/form-buttons.html",scope:{pfHandleCancel:"&pfOnCancel",pfHandleSave:"&pfOnSave",pfWorking:"=",pfButtonContainerClass:"@"},link:function(scope,iElement,iAttrs,controller){void 0===scope.pfWorking&&(scope.pfWorking=!1),scope.isInvalid=function(){var invalid=controller.$invalid;return angular.forEach(controller,function(value){value&&value.$error&&value.$error.server&&(invalid=!1)}),invalid}}}}),angular.module("patternfly.form").directive("pfFormGroup",function(){"use strict";function getInput(element){var input=element.find("table");return 0===input.length&&(input=element.find("input"),0===input.length&&(input=element.find("select"),0===input.length&&(input=element.find("textarea")))),input}return{transclude:!0,replace:!0,require:"^form",templateUrl:"form/form-group/form-group.html",scope:{pfLabel:"@",pfField:"@",pfLabelClass:"@",pfInputClass:"@"},link:function(scope,iElement,iAttrs,controller){var field,input=getInput(iElement),type=input.attr("type");iAttrs.pfLabelClass||(iAttrs.pfLabelClass="col-sm-2"),iAttrs.pfInputClass||(iAttrs.pfInputClass="col-sm-5"),scope.pfField||(scope.pfField=input.attr("id")),field=scope.pfField,-1===["checkbox","radio","time"].indexOf(type)&&input.addClass("form-control"),input.attr("required")&&iElement.addClass("required"),controller[field]&&(scope.error=controller[field].$error),scope.hasErrors=function(){return controller[field]&&controller[field].$invalid&&controller[field].$dirty}}}}),angular.module("patternfly.notification",[]).provider("Notifications",function(){"use strict";this.delay=5e3,this.verbose=!0,this.notifications={},this.persist={error:!0,httpError:!0},this.setDelay=function(delay){return this.delay=delay,this},this.setVerbose=function(verbose){return this.verbose=verbose,this},this.setPersist=function(persist){this.persist=persist},this.$get=["$rootScope","$timeout","$log",function($rootScope,$timeout,$log){function createNotifyMethod(mode){return function(message){notifications.message(modes[mode].type,modes[mode].header,message,persist[mode]),verbose&&$log[modes[mode].log](message)}}var delay=this.delay,notifications=this.notifications,verbose=this.verbose,persist=this.persist,scheduleMessagePop=function(){$timeout(function(){var i;for(i=0;i<$rootScope.notifications.data.length;i++)$rootScope.notifications.data[i].isPersistent||$rootScope.notifications.data.splice(i,1)},delay)},modes={info:{type:"info",header:"Info!",log:"info"},success:{type:"success",header:"Success!",log:"info"},error:{type:"danger",header:"Error!",log:"error"},warn:{type:"warning",header:"Warning!",log:"warn"}};return $rootScope.notifications={},$rootScope.notifications.data=[],$rootScope.notifications.remove=function(index){$rootScope.notifications.data.splice(index,1)},$rootScope.notifications||($rootScope.notifications.data=[]),notifications.message=function(type,header,message,isPersistent){$rootScope.notifications.data.push({type:type,header:header,message:message,isPersistent:isPersistent}),scheduleMessagePop()},angular.forEach(modes,function(mode,index){notifications[index]=createNotifyMethod(index)}),notifications.httpError=function(message,httpResponse){message+=" ("+(httpResponse.data.message||httpResponse.data.cause||httpResponse.data.cause||httpResponse.data.errorMessage)+")",notifications.message("danger","Error!",message,persist.httpError),verbose&&$log.error(message)},notifications}]}),angular.module("patternfly.notification").directive("pfNotification",function(){"use strict";return{scope:{pfNotificationType:"=",pfNotificationMessage:"=",pfNotificationHeader:"=",pfNotificationPersistent:"=",pfNotificationIndex:"="},restrict:"E",templateUrl:"notification/notification.html"}}),angular.module("patternfly.notification").directive("pfNotificationList",function(){"use strict";return{restrict:"E",templateUrl:"notification/notification-list.html"}}),angular.module("patternfly.select",[]).directive("pfSelect",["$timeout",function($timeout){"use strict";return{restrict:"A",require:"?ngModel",scope:{selectPickerOptions:"=pfSelect"},link:function(scope,element,attrs,ngModel){var optionCollectionList,optionCollection,$render=ngModel.$render;element.selectpicker(scope.selectPickerOptions),ngModel.$render=function(){$render.apply(this,arguments),$timeout(function(){element.selectpicker("refresh")},0,!1)},attrs.ngOptions&&(optionCollectionList=attrs.ngOptions.split("in "),optionCollection=optionCollectionList[optionCollectionList.length-1],scope.$watchCollection(optionCollection,function(){element.selectpicker("refresh")})),attrs.$observe("disabled",function(){element.selectpicker("refresh")})}}}]),angular.module("patternfly.validation",[]).directive("pfValidation",["$timeout",function($timeout){"use strict";return{restrict:"A",require:"ngModel",scope:{pfValidation:"&",pfValidationDisabled:"="},link:function(scope,element,attrs,ctrl){function validate(){var valid,val=scope.inputCtrl.$modelValue,valFunc=scope.pfValidation({input:val});attrs.pfValidation||(valFunc=!0),valid=!val||valFunc||""===val,toggleErrorClass(scope.valEnabled&&!valid?!0:!1)}function toggleErrorClass(add){var messageElement=element.next(),parentElement=element.parent(),hasErrorM=parentElement.hasClass("has-error"),wasHidden=messageElement.hasClass("ng-hide");scope.inputCtrl.$setValidity("pf-validation",!add),add&&(hasErrorM||parentElement.addClass("has-error"),wasHidden&&messageElement.removeClass("ng-hide")),add||(hasErrorM&&parentElement.removeClass("has-error"),wasHidden||messageElement.addClass("ng-hide"))}scope.inputCtrl=ctrl,scope.valEnabled=!attrs.pfValidationDisabled,scope.$watch("pfValidationDisabled",function(newVal){scope.valEnabled=!newVal,newVal?(scope.inputCtrl.$setValidity("pfValidation",!0),toggleErrorClass(!1)):validate()}),attrs.pfValidation?$timeout(function(){validate()},0):!scope.inputCtrl.$valid&&scope.inputCtrl.$dirty&&toggleErrorClass(!0),scope.$watch("inputCtrl.$valid",function(isValid){toggleErrorClass(isValid?!1:!0)}),scope.$watch("inputCtrl.$modelValue",function(){validate()})}}}]),angular.module("patternfly.card").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("card/basic/card.html","

{{headTitle}}

{{subTitle}}
")}]),angular.module("patternfly.charts").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("charts/donut/donut-pct-chart.html","
"),$templateCache.put("charts/sparkline/sparkline-chart.html","
"),$templateCache.put("charts/utilization/utilization-chart.html",'
{{config.title}}
{{currentValue}}
{{currentText}}
of {{chartData.total}} {{config.units}}
{{legendLeftText}} {{legendRightText}}
')}]),angular.module("patternfly.form").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("form/datepicker/datepicker.html",'
'),$templateCache.put("form/form-buttons/form-buttons.html",'
'),$templateCache.put("form/form-group/form-group.html",'
  • {{ message }}
')}]),angular.module("patternfly.notification").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("notification/notification-list.html",'
'),$templateCache.put("notification/notification.html",'
{{pfNotificationHeader}} {{pfNotificationMessage}}
')}]); \ No newline at end of file +<<<<<<< HEAD +angular.module("patternfly.card",[]),angular.module("patternfly.charts",[]),angular.module("patternfly.form",[]),angular.module("patternfly",["patternfly.autofocus","patternfly.card","patternfly.form","patternfly.notification","patternfly.select","patternfly.validation"]),angular.module("patternfly.autofocus",[]).directive("pfFocused",["$timeout",function($timeout){"use strict";return{restrict:"A",link:function(scope,element,attrs){scope.$watch(attrs.pfFocused,function(newValue){$timeout(function(){newValue&&(element[0].focus(),element[0].select&&element[0].select())})})}}}]),angular.module("patternfly.card").directive("pfCard",function(){"use strict";return{restrict:"A",transclude:!0,templateUrl:"card/basic/card.html",scope:{headTitle:"@",subTitle:"@?",showTopBorder:"@?"}}}),function(){"use strict";angular.module("patternfly.charts").constant("c3ChartDefaults",{getDefaultDonut:function(title){return{title:title,label:{show:!1},width:10}},getDefaultDonutSize:function(){return{height:130}},getDefaultDonutColor:function(){return{pattern:["#0088CE","#D1D1D1"]}},getDefaultDonutTooltip:function(){return{show:!1}},getDefaultDonutLegend:function(){return{show:!1}},getDefaultDonutConfig:function(title){return{donut:this.getDefaultDonut(title),size:this.getDefaultDonutSize(),legend:this.getDefaultDonutLegend(),color:this.getDefaultDonutColor(),tooltip:this.getDefaultDonutTooltip()}},getDefaultSparklineArea:function(){return{zerobased:!0}},getDefaultSparklineSize:function(){return{height:60}},getDefaultSparklineAxis:function(){return{x:{show:!1},y:{show:!1}}},getDefaultSparklineColor:function(){return{pattern:["#0088ce","#00659c","#3f9c35","#ec7a08","#cc0000"]}},getDefaultSparklineLegend:function(){return{show:!1}},getDefaultSparklinePoint:function(){return{r:1,focus:{expand:{r:4}}}},getDefaultSparklineTooltip:function(){return{contents:function(d){return''+d[0].value+" "+d[0].name+""}}},getDefaultSparklineConfig:function(){return{area:this.getDefaultSparklineArea(),size:this.getDefaultSparklineSize(),axis:this.getDefaultSparklineAxis(),color:this.getDefaultSparklineColor(),legend:this.getDefaultSparklineLegend(),point:this.getDefaultSparklinePoint(),tooltip:this.getDefaultSparklineTooltip()}}})}(),function(c3){"use strict";angular.module("patternfly.charts").directive("pfC3Chart",["$timeout",function($timeout){return{restrict:"A",scope:{config:"="},template:'
',replace:!0,link:function(scope,element,attrs){scope.$watch("config",function(){$timeout(function(){var chartData=scope.config;chartData.bindto="#"+attrs.id,c3.generate(chartData)})},!0)}}}])}(c3),angular.module("patternfly.charts").directive("pfDonutPctChart",["c3ChartDefaults","$timeout",function(c3ChartDefaults,$timeout){"use strict";return{restrict:"A",scope:{config:"=",data:"=",centerLabel:"=?"},replace:!0,templateUrl:"charts/donut/donut-pct-chart.html",controller:["$scope",function($scope){var donutTooltip;$scope.donutChartId="donutChart",$scope.config.chartId&&($scope.donutChartId=$scope.config.chartId+$scope.donutChartId),$scope.updateAvailable=function(){$scope.data.available=$scope.data.total-$scope.data.used},void 0===$scope.data.available&&$scope.updateAvailable(),$scope.getStatusColor=function(used,thresholds){var color="#0088CE";return thresholds&&(used>=thresholds.error?color="#CC0000":used>=thresholds.warning&&(color="#EC7A08")),color},$scope.statusDonutColor=function(scope){var color,percentUsed;return color={pattern:[]},percentUsed=scope.data.used/scope.data.total*100,color.pattern[0]=$scope.getStatusColor(percentUsed,scope.config.thresholds),color.pattern[1]="#D1D1D1",color},donutTooltip=function(scope){return{contents:function(d){var tooltipHtml;return tooltipHtml=scope.config.tooltipFn?''+scope.config.tooltipFn(d)+"":''+Math.round(100*d[0].ratio)+"% "+$scope.config.units+" "+d[0].name+""}}},$scope.getDonutData=function(scope){return{columns:[["Used",scope.data.used],["Available",scope.data.available]],type:"donut",donut:{label:{show:!1}},groups:[["used","available"]],order:null}},$scope.updateAll=function(scope){$scope.updateAvailable(),$scope.config.data=$scope.getDonutData($scope),$scope.config.color=$scope.statusDonutColor($scope),$scope.config.tooltip=donutTooltip(scope)},$scope.config=$.extend(!0,c3ChartDefaults.getDefaultDonutConfig(),$scope.config),$scope.updateAll($scope)}],link:function(scope,element){var setupDonutChartTitle=function(){$timeout(function(){var donutChartTitle,bigText,smText;donutChartTitle=element[0].querySelector("text.c3-chart-arcs-title"),scope.config.centerLabelFn?donutChartTitle.innerHTML=scope.config.centerLabelFn(scope):"none"===scope.centerLabel?donutChartTitle.innerHTML="":(bigText=scope.data.used,smText=scope.config.units+" Used","available"===scope.centerLabel?(bigText=scope.data.available,smText=scope.config.units+" Available"):"percent"===scope.centerLabel&&(bigText=Math.round(scope.data.used/scope.data.total*100)+"%",smText="of "+scope.data.total+" "+scope.config.units),donutChartTitle&&(donutChartTitle.innerHTML=''+bigText+''+smText+""))},300)};scope.$watch("config",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("data",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("centerLabel",function(){setupDonutChartTitle()})}}}]),angular.module("patternfly.charts").directive("pfSparklineChart",["c3ChartDefaults",function(c3ChartDefaults){"use strict";return{restrict:"A",scope:{config:"=",chartData:"=",chartHeight:"=?",showXAxis:"=?",showYAxis:"=?"},replace:!0,templateUrl:"charts/sparkline/sparkline-chart.html",controller:["$scope",function($scope){$scope.sparklineChartId="sparklineChart",$scope.config.chartId&&($scope.sparklineChartId=$scope.config.chartId+$scope.sparklineChartId),$scope.getSparklineData=function(chartData){return{x:chartData.xData[0],columns:[chartData.xData,chartData.yData],type:"area"}},$scope.getTooltipTableHTML=function(tipRows){return'
'+tipRows+"
"},$scope.sparklineTooltip=function(){return{contents:function(d){var tipRows,percentUsed;if($scope.config.tooltipFn)tipRows=$scope.config.tooltipFn(d);else switch($scope.config.tooltipType){case"usagePerDay":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+d[0].x.toLocaleDateString()+' '+percentUsed+'%: '+d[0].value+" "+$scope.config.units+" "+d[0].name+"";break;case"valuePerDay":tipRows=' '+d[0].x.toLocaleDateString()+' '+d[0].value+" "+d[0].name+"";break;case"percentage":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+percentUsed+"%";break;default:tipRows=c3ChartDefaults.getDefaultSparklineTooltip().contents(d)}return $scope.getTooltipTableHTML(tipRows)},position:function(data,width,height,element){var center,top,chartBox,graphOffsetX,x;try{return center=parseInt(element.getAttribute("x")),top=parseInt(element.getAttribute("y")),chartBox=document.querySelector("#"+$scope.sparklineChartId).getBoundingClientRect(),graphOffsetX=document.querySelector("#"+$scope.sparklineChartId+" g.c3-axis-y").getBoundingClientRect().right,x=Math.max(0,center+graphOffsetX-chartBox.left-Math.floor(width/2)),{top:top-height,left:Math.min(x,chartBox.width-width)}}catch(e){}}}},void 0===$scope.showXAxis&&($scope.showXAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),void 0===$scope.showYAxis&&($scope.showYAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),$scope.defaultConfig=c3ChartDefaults.getDefaultSparklineConfig(),$scope.defaultConfig.axis={x:{show:$scope.showXAxis===!0,type:"timeseries",tick:{format:function(){return""}}},y:{show:$scope.showYAxis===!0,tick:{format:function(){return""}}}},$scope.defaultConfig.tooltip=$scope.sparklineTooltip(),$scope.chartHeight&&($scope.defaultConfig.size.height=$scope.chartHeight),$scope.defaultConfig.units="",$scope.config=$.extend(!0,angular.copy($scope.defaultConfig),$scope.config),$scope.config.data=$scope.getSparklineData($scope.chartData)}],link:function(scope){scope.$watch("config",function(){scope.config=$.extend(!0,angular.copy(scope.defaultConfig),scope.config)},!0),scope.$watch("chartHeight",function(){scope.config.size.height=scope.chartHeight}),scope.$watch("showXAxis",function(){scope.config.axis.x.show=scope.showXAxis===!0}),scope.$watch("showYAxis",function(){scope.config.axis.y.show=scope.showYAxis===!0}),scope.$watch("chartData",function(){scope.config.data=scope.getSparklineData(scope.chartData)},!0)}}}]),angular.module("patternfly.charts").directive("pfUtilizationChart",function(){"use strict";return{restrict:"A",scope:{chartData:"=",config:"=",centerLabel:"=?",donutConfig:"=",sparklineConfig:"=",sparklineChartHeight:"=?",showSparklineXAxis:"=?",showSparklineYAxis:"=?"},replace:!0,templateUrl:"charts/utilization/utilization-chart.html",controller:["$scope",function($scope){void 0===$scope.centerLabel&&($scope.centerLabel="used"),void 0===$scope.donutConfig.units&&($scope.donutConfig.units=$scope.config.units),void 0===$scope.chartData.available&&($scope.chartData.available=$scope.chartData.total-$scope.chartData.used),$scope.config.units=$scope.config.units||$scope.units}],link:function(scope){var setupCurrentValues=function(){"available"===scope.centerLabel?(scope.currentValue=scope.chartData.used,scope.currentText="Used"):(scope.currentValue=scope.chartData.total-scope.chartData.used,scope.currentText="Available")};scope.$watch("centerLabel",function(){setupCurrentValues()})}}}),angular.module("patternfly.form").directive("pfDatepicker",function(){"use strict";return{replace:!0,restrict:"A",require:"^form",templateUrl:"form/datepicker/datepicker.html",scope:{options:"=",date:"="},link:function($scope,element){element.datepicker($scope.options),element.datepicker("update",$scope.date),element.datepicker($scope.date).on("changeDate",function(elem){$scope.$apply(function(){$scope.date=elem.date})}),$scope.$watch("date",function(newValue,oldValue){oldValue!==newValue&&element.datepicker("update",newValue)})}}}),angular.module("patternfly.form").directive("pfFormButtons",function(){"use strict";return{replace:!0,require:"^form",templateUrl:"form/form-buttons/form-buttons.html",scope:{pfHandleCancel:"&pfOnCancel",pfHandleSave:"&pfOnSave",pfWorking:"=",pfButtonContainerClass:"@"},link:function(scope,iElement,iAttrs,controller){void 0===scope.pfWorking&&(scope.pfWorking=!1),scope.isInvalid=function(){var invalid=controller.$invalid;return angular.forEach(controller,function(value){value&&value.$error&&value.$error.server&&(invalid=!1)}),invalid}}}}),angular.module("patternfly.form").directive("pfFormGroup",function(){"use strict";function getInput(element){var input=element.find("table");return 0===input.length&&(input=element.find("input"),0===input.length&&(input=element.find("select"),0===input.length&&(input=element.find("textarea")))),input}return{transclude:!0,replace:!0,require:"^form",templateUrl:"form/form-group/form-group.html",scope:{pfLabel:"@",pfField:"@",pfLabelClass:"@",pfInputClass:"@"},link:function(scope,iElement,iAttrs,controller){var field,input=getInput(iElement),type=input.attr("type");iAttrs.pfLabelClass||(iAttrs.pfLabelClass="col-sm-2"),iAttrs.pfInputClass||(iAttrs.pfInputClass="col-sm-5"),scope.pfField||(scope.pfField=input.attr("id")),field=scope.pfField,-1===["checkbox","radio","time"].indexOf(type)&&input.addClass("form-control"),input.attr("required")&&iElement.addClass("required"),controller[field]&&(scope.error=controller[field].$error),scope.hasErrors=function(){return controller[field]&&controller[field].$invalid&&controller[field].$dirty}}}}),angular.module("patternfly.notification",[]).provider("Notifications",function(){"use strict";this.delay=5e3,this.verbose=!0,this.notifications={},this.persist={error:!0,httpError:!0},this.setDelay=function(delay){return this.delay=delay,this},this.setVerbose=function(verbose){return this.verbose=verbose,this},this.setPersist=function(persist){this.persist=persist},this.$get=["$rootScope","$timeout","$log",function($rootScope,$timeout,$log){function createNotifyMethod(mode){return function(message){notifications.message(modes[mode].type,modes[mode].header,message,persist[mode]),verbose&&$log[modes[mode].log](message)}}var delay=this.delay,notifications=this.notifications,verbose=this.verbose,persist=this.persist,scheduleMessagePop=function(){$timeout(function(){var i;for(i=0;i<$rootScope.notifications.data.length;i++)$rootScope.notifications.data[i].isPersistent||$rootScope.notifications.data.splice(i,1)},delay)},modes={info:{type:"info",header:"Info!",log:"info"},success:{type:"success",header:"Success!",log:"info"},error:{type:"danger",header:"Error!",log:"error"},warn:{type:"warning",header:"Warning!",log:"warn"}};return $rootScope.notifications={},$rootScope.notifications.data=[],$rootScope.notifications.remove=function(index){$rootScope.notifications.data.splice(index,1)},$rootScope.notifications||($rootScope.notifications.data=[]),notifications.message=function(type,header,message,isPersistent){$rootScope.notifications.data.push({type:type,header:header,message:message,isPersistent:isPersistent}),scheduleMessagePop()},angular.forEach(modes,function(mode,index){notifications[index]=createNotifyMethod(index)}),notifications.httpError=function(message,httpResponse){message+=" ("+(httpResponse.data.message||httpResponse.data.cause||httpResponse.data.cause||httpResponse.data.errorMessage)+")",notifications.message("danger","Error!",message,persist.httpError),verbose&&$log.error(message)},notifications}]}),angular.module("patternfly.notification").directive("pfNotification",function(){"use strict";return{scope:{pfNotificationType:"=",pfNotificationMessage:"=",pfNotificationHeader:"=",pfNotificationPersistent:"=",pfNotificationIndex:"="},restrict:"E",templateUrl:"notification/notification.html"}}),angular.module("patternfly.notification").directive("pfNotificationList",function(){"use strict";return{restrict:"E",templateUrl:"notification/notification-list.html"}}),angular.module("patternfly.select",[]).directive("pfSelect",["$timeout",function($timeout){"use strict";return{restrict:"A",require:"?ngModel",scope:{selectPickerOptions:"=pfSelect"},link:function(scope,element,attrs,ngModel){var optionCollectionList,optionCollection,$render=ngModel.$render;element.selectpicker(scope.selectPickerOptions),ngModel.$render=function(){$render.apply(this,arguments),$timeout(function(){element.selectpicker("refresh")},0,!1)},attrs.ngOptions&&(optionCollectionList=attrs.ngOptions.split("in "),optionCollection=optionCollectionList[optionCollectionList.length-1],scope.$watchCollection(optionCollection,function(){element.selectpicker("refresh")})),attrs.$observe("disabled",function(){element.selectpicker("refresh")})}}}]),angular.module("patternfly.validation",[]).directive("pfValidation",["$timeout",function($timeout){"use strict";return{restrict:"A",require:"ngModel",scope:{pfValidation:"&",pfValidationDisabled:"="},link:function(scope,element,attrs,ctrl){function validate(){var valid,val=scope.inputCtrl.$modelValue,valFunc=scope.pfValidation({input:val});attrs.pfValidation||(valFunc=!0),valid=!val||valFunc||""===val,toggleErrorClass(scope.valEnabled&&!valid?!0:!1)}function toggleErrorClass(add){var messageElement=element.next(),parentElement=element.parent(),hasErrorM=parentElement.hasClass("has-error"),wasHidden=messageElement.hasClass("ng-hide");scope.inputCtrl.$setValidity("pf-validation",!add),add&&(hasErrorM||parentElement.addClass("has-error"),wasHidden&&messageElement.removeClass("ng-hide")),add||(hasErrorM&&parentElement.removeClass("has-error"),wasHidden||messageElement.addClass("ng-hide"))}scope.inputCtrl=ctrl,scope.valEnabled=!attrs.pfValidationDisabled,scope.$watch("pfValidationDisabled",function(newVal){scope.valEnabled=!newVal,newVal?(scope.inputCtrl.$setValidity("pfValidation",!0),toggleErrorClass(!1)):validate()}),attrs.pfValidation?$timeout(function(){validate()},0):!scope.inputCtrl.$valid&&scope.inputCtrl.$dirty&&toggleErrorClass(!0),scope.$watch("inputCtrl.$valid",function(isValid){toggleErrorClass(isValid?!1:!0)}),scope.$watch("inputCtrl.$modelValue",function(){validate()})}}}]),angular.module("patternfly.card").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("card/basic/card.html","

{{headTitle}}

{{subTitle}}
")}]),angular.module("patternfly.charts").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("charts/donut/donut-pct-chart.html","
"),$templateCache.put("charts/sparkline/sparkline-chart.html","
"),$templateCache.put("charts/utilization/utilization-chart.html",'
{{config.title}}
{{currentValue}}
{{currentText}}
of {{chartData.total}} {{config.units}}
{{legendLeftText}} {{legendRightText}}
')}]),angular.module("patternfly.form").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("form/datepicker/datepicker.html",'
'),$templateCache.put("form/form-buttons/form-buttons.html",'
'),$templateCache.put("form/form-group/form-group.html",'
  • {{ message }}
')}]),angular.module("patternfly.notification").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("notification/notification-list.html",'
'),$templateCache.put("notification/notification.html",'
{{pfNotificationHeader}} {{pfNotificationMessage}}
')}]); +======= +angular.module("patternfly.card",[]),angular.module("patternfly.charts",[]),angular.module("patternfly.form",[]),angular.module("patternfly",["patternfly.autofocus","patternfly.card","patternfly.form","patternfly.notification","patternfly.select","patternfly.utils","patternfly.validation","patternfly.views"]),angular.module("patternfly.utils",[]),angular.module("patternfly.views",["patternfly.utils"]),angular.module("patternfly.autofocus",[]).directive("pfFocused",function($timeout){"use strict";return{restrict:"A",link:function(scope,element,attrs){scope.$watch(attrs.pfFocused,function(newValue){$timeout(function(){newValue&&(element[0].focus(),element[0].select&&element[0].select())})})}}}),angular.module("patternfly.card").directive("pfCard",function(){"use strict";return{restrict:"A",transclude:!0,templateUrl:"card/basic/card.html",scope:{headTitle:"@",subTitle:"@?",showTopBorder:"@?"}}}),function(){"use strict";angular.module("patternfly.charts").constant("c3ChartDefaults",{getDefaultDonut:function(title){return{title:title,label:{show:!1},width:10}},getDefaultDonutSize:function(){return{height:130}},getDefaultDonutColor:function(){return{pattern:["#0088CE","#D1D1D1"]}},getDefaultDonutTooltip:function(){return{show:!1}},getDefaultDonutLegend:function(){return{show:!1}},getDefaultDonutConfig:function(title){return{donut:this.getDefaultDonut(title),size:this.getDefaultDonutSize(),legend:this.getDefaultDonutLegend(),color:this.getDefaultDonutColor(),tooltip:this.getDefaultDonutTooltip()}},getDefaultSparklineArea:function(){return{zerobased:!0}},getDefaultSparklineSize:function(){return{height:60}},getDefaultSparklineAxis:function(){return{x:{show:!1},y:{show:!1}}},getDefaultSparklineColor:function(){return{pattern:["#0088ce","#00659c","#3f9c35","#ec7a08","#cc0000"]}},getDefaultSparklineLegend:function(){return{show:!1}},getDefaultSparklinePoint:function(){return{r:1,focus:{expand:{r:4}}}},getDefaultSparklineTooltip:function(){return{contents:function(d){return''+d[0].value+" "+d[0].name+""}}},getDefaultSparklineConfig:function(){return{area:this.getDefaultSparklineArea(),size:this.getDefaultSparklineSize(),axis:this.getDefaultSparklineAxis(),color:this.getDefaultSparklineColor(),legend:this.getDefaultSparklineLegend(),point:this.getDefaultSparklinePoint(),tooltip:this.getDefaultSparklineTooltip()}}})}(),function(c3){"use strict";angular.module("patternfly.charts").directive("pfC3Chart",["$timeout",function($timeout){return{restrict:"A",scope:{config:"="},template:'
',replace:!0,link:function(scope,element,attrs){scope.$watch("config",function(){$timeout(function(){var chartData=scope.config;chartData.bindto="#"+attrs.id,c3.generate(chartData)})},!0)}}}])}(c3),angular.module("patternfly.charts").directive("pfDonutPctChart",["c3ChartDefaults","$timeout",function(c3ChartDefaults,$timeout){"use strict";return{restrict:"A",scope:{config:"=",data:"=",centerLabel:"=?"},replace:!0,templateUrl:"charts/donut/donut-pct-chart.html",controller:["$scope",function($scope){var donutTooltip;$scope.donutChartId="donutChart",$scope.config.chartId&&($scope.donutChartId=$scope.config.chartId+$scope.donutChartId),$scope.updateAvailable=function(){$scope.data.available=$scope.data.total-$scope.data.used},void 0===$scope.data.available&&$scope.updateAvailable(),$scope.getStatusColor=function(used,thresholds){var color="#0088CE";return thresholds&&(used>=thresholds.error?color="#CC0000":used>=thresholds.warning&&(color="#EC7A08")),color},$scope.statusDonutColor=function(scope){var color,percentUsed;return color={pattern:[]},percentUsed=scope.data.used/scope.data.total*100,color.pattern[0]=$scope.getStatusColor(percentUsed,scope.config.thresholds),color.pattern[1]="#D1D1D1",color},donutTooltip=function(scope){return{contents:function(d){var tooltipHtml;return tooltipHtml=scope.config.tooltipFn?''+scope.config.tooltipFn(d)+"":''+Math.round(100*d[0].ratio)+"% "+$scope.config.units+" "+d[0].name+""}}},$scope.getDonutData=function(scope){return{columns:[["Used",scope.data.used],["Available",scope.data.available]],type:"donut",donut:{label:{show:!1}},groups:[["used","available"]],order:null}},$scope.updateAll=function(scope){$scope.updateAvailable(),$scope.config.data=$scope.getDonutData($scope),$scope.config.color=$scope.statusDonutColor($scope),$scope.config.tooltip=donutTooltip(scope)},$scope.config=$.extend(!0,c3ChartDefaults.getDefaultDonutConfig(),$scope.config),$scope.updateAll($scope)}],link:function(scope,element){var setupDonutChartTitle=function(){$timeout(function(){var donutChartTitle,bigText,smText;donutChartTitle=element[0].querySelector("text.c3-chart-arcs-title"),scope.config.centerLabelFn?donutChartTitle.innerHTML=scope.config.centerLabelFn(scope):"none"===scope.centerLabel?donutChartTitle.innerHTML="":(bigText=scope.data.used,smText=scope.config.units+" Used","available"===scope.centerLabel?(bigText=scope.data.available,smText=scope.config.units+" Available"):"percent"===scope.centerLabel&&(bigText=Math.round(scope.data.used/scope.data.total*100)+"%",smText="of "+scope.data.total+" "+scope.config.units),donutChartTitle&&(donutChartTitle.innerHTML=''+bigText+''+smText+""))},300)};scope.$watch("config",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("data",function(){scope.updateAll(scope),setupDonutChartTitle()},!0),scope.$watch("centerLabel",function(){setupDonutChartTitle()})}}}]),angular.module("patternfly.charts").directive("pfSparklineChart",["c3ChartDefaults",function(c3ChartDefaults){"use strict";return{restrict:"A",scope:{config:"=",chartData:"=",chartHeight:"=?",showXAxis:"=?",showYAxis:"=?"},replace:!0,templateUrl:"charts/sparkline/sparkline-chart.html",controller:["$scope",function($scope){$scope.sparklineChartId="sparklineChart",$scope.config.chartId&&($scope.sparklineChartId=$scope.config.chartId+$scope.sparklineChartId),$scope.getSparklineData=function(chartData){return{x:chartData.xData[0],columns:[chartData.xData,chartData.yData],type:"area"}},$scope.getTooltipTableHTML=function(tipRows){return'
'+tipRows+"
"},$scope.sparklineTooltip=function(){return{contents:function(d){var tipRows,percentUsed;if($scope.config.tooltipFn)tipRows=$scope.config.tooltipFn(d);else switch($scope.config.tooltipType){case"usagePerDay":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+d[0].x.toLocaleDateString()+' '+percentUsed+'%: '+d[0].value+" "+$scope.config.units+" "+d[0].name+"";break;case"valuePerDay":tipRows=' '+d[0].x.toLocaleDateString()+' '+d[0].value+" "+d[0].name+"";break;case"percentage":percentUsed=Math.round(d[0].value/$scope.chartData.total*100),tipRows=' '+percentUsed+"%";break;default:tipRows=c3ChartDefaults.getDefaultSparklineTooltip().contents(d)}return $scope.getTooltipTableHTML(tipRows)},position:function(data,width,height,element){var center,top,chartBox,graphOffsetX,x;try{return center=parseInt(element.getAttribute("x")),top=parseInt(element.getAttribute("y")),chartBox=document.querySelector("#"+$scope.sparklineChartId).getBoundingClientRect(),graphOffsetX=document.querySelector("#"+$scope.sparklineChartId+" g.c3-axis-y").getBoundingClientRect().right,x=Math.max(0,center+graphOffsetX-chartBox.left-Math.floor(width/2)),{top:top-height,left:Math.min(x,chartBox.width-width)}}catch(e){}}}},void 0===$scope.showXAxis&&($scope.showXAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),void 0===$scope.showYAxis&&($scope.showYAxis=void 0!==$scope.config.showAxis&&$scope.config.showAxis),$scope.defaultConfig=c3ChartDefaults.getDefaultSparklineConfig(),$scope.defaultConfig.axis={x:{show:$scope.showXAxis===!0,type:"timeseries",tick:{format:function(){return""}}},y:{show:$scope.showYAxis===!0,tick:{format:function(){return""}}}},$scope.defaultConfig.tooltip=$scope.sparklineTooltip(),$scope.chartHeight&&($scope.defaultConfig.size.height=$scope.chartHeight),$scope.defaultConfig.units="",$scope.config=$.extend(!0,angular.copy($scope.defaultConfig),$scope.config),$scope.config.data=$scope.getSparklineData($scope.chartData)}],link:function(scope){scope.$watch("config",function(){scope.config=$.extend(!0,angular.copy(scope.defaultConfig),scope.config)},!0),scope.$watch("chartHeight",function(){scope.config.size.height=scope.chartHeight}),scope.$watch("showXAxis",function(){scope.config.axis.x.show=scope.showXAxis===!0}),scope.$watch("showYAxis",function(){scope.config.axis.y.show=scope.showYAxis===!0}),scope.$watch("chartData",function(){scope.config.data=scope.getSparklineData(scope.chartData)},!0)}}}]),angular.module("patternfly.charts").directive("pfUtilizationChart",function(){"use strict";return{restrict:"A",scope:{chartData:"=",config:"=",centerLabel:"=?",donutConfig:"=",sparklineConfig:"=",sparklineChartHeight:"=?",showSparklineXAxis:"=?",showSparklineYAxis:"=?"},replace:!0,templateUrl:"charts/utilization/utilization-chart.html",controller:["$scope",function($scope){void 0===$scope.centerLabel&&($scope.centerLabel="used"),void 0===$scope.donutConfig.units&&($scope.donutConfig.units=$scope.config.units),void 0===$scope.chartData.available&&($scope.chartData.available=$scope.chartData.total-$scope.chartData.used),$scope.config.units=$scope.config.units||$scope.units}],link:function(scope,element){var setupCurrentValues=function(){"available"===scope.centerLabel?(scope.currentValue=scope.chartData.used,scope.currentText="Used"):(scope.currentValue=scope.chartData.total-scope.chartData.used,scope.currentText="Available")};scope.$watch("centerLabel",function(){setupCurrentValues()})}}}),angular.module("patternfly.form").directive("pfDatepicker",function(){"use strict";return{replace:!0,restrict:"A",require:"^form",templateUrl:"form/datepicker/datepicker.html",scope:{options:"=",date:"="},link:function($scope,element){element.datepicker($scope.options),element.datepicker("update",$scope.date),element.datepicker($scope.date).on("changeDate",function(elem){$scope.$apply(function(){$scope.date=elem.date})}),$scope.$watch("date",function(newValue,oldValue){oldValue!==newValue&&element.datepicker("update",newValue)})}}}),angular.module("patternfly.form").directive("pfFormButtons",function(){"use strict";return{replace:!0,require:"^form",templateUrl:"form/form-buttons/form-buttons.html",scope:{pfHandleCancel:"&pfOnCancel",pfHandleSave:"&pfOnSave",pfWorking:"=",pfButtonContainerClass:"@"},link:function(scope,iElement,iAttrs,controller){void 0===scope.pfWorking&&(scope.pfWorking=!1),scope.isInvalid=function(){var invalid=controller.$invalid;return angular.forEach(controller,function(value){value&&value.$error&&value.$error.server&&(invalid=!1)}),invalid}}}}),angular.module("patternfly.form").directive("pfFormGroup",function(){"use strict";function getInput(element){var input=element.find("table");return 0===input.length&&(input=element.find("input"),0===input.length&&(input=element.find("select"),0===input.length&&(input=element.find("textarea")))),input}return{transclude:!0,replace:!0,require:"^form",templateUrl:"form/form-group/form-group.html",scope:{pfLabel:"@",pfField:"@",pfLabelClass:"@",pfInputClass:"@"},link:function(scope,iElement,iAttrs,controller){var field,input=getInput(iElement),type=input.attr("type");iAttrs.pfLabelClass||(iAttrs.pfLabelClass="col-sm-2"),iAttrs.pfInputClass||(iAttrs.pfInputClass="col-sm-5"),scope.pfField||(scope.pfField=input.attr("id")),field=scope.pfField,-1===["checkbox","radio","time"].indexOf(type)&&input.addClass("form-control"),input.attr("required")&&iElement.addClass("required"),controller[field]&&(scope.error=controller[field].$error),scope.hasErrors=function(){return controller[field]&&controller[field].$invalid&&controller[field].$dirty}}}}),angular.module("patternfly.notification",[]).provider("Notifications",function(){"use strict";this.delay=5e3,this.verbose=!0,this.notifications={},this.persist={error:!0,httpError:!0},this.setDelay=function(delay){return this.delay=delay,this},this.setVerbose=function(verbose){return this.verbose=verbose,this},this.setPersist=function(persist){this.persist=persist},this.$get=["$rootScope","$timeout","$log",function($rootScope,$timeout,$log){function createNotifyMethod(mode){return function(message){notifications.message(modes[mode].type,modes[mode].header,message,persist[mode]),verbose&&$log[modes[mode].log](message)}}var delay=this.delay,notifications=this.notifications,verbose=this.verbose,persist=this.persist,scheduleMessagePop=function(){$timeout(function(){var i;for(i=0;i<$rootScope.notifications.data.length;i++)$rootScope.notifications.data[i].isPersistent||$rootScope.notifications.data.splice(i,1)},delay)},modes={info:{type:"info",header:"Info!",log:"info"},success:{type:"success",header:"Success!",log:"info"},error:{type:"danger",header:"Error!",log:"error"},warn:{type:"warning",header:"Warning!",log:"warn"}};return $rootScope.notifications={},$rootScope.notifications.data=[],$rootScope.notifications.remove=function(index){$rootScope.notifications.data.splice(index,1)},$rootScope.notifications||($rootScope.notifications.data=[]),notifications.message=function(type,header,message,isPersistent){$rootScope.notifications.data.push({type:type,header:header,message:message,isPersistent:isPersistent}),scheduleMessagePop()},angular.forEach(modes,function(mode,index){notifications[index]=createNotifyMethod(index)}),notifications.httpError=function(message,httpResponse){message+=" ("+(httpResponse.data.message||httpResponse.data.cause||httpResponse.data.cause||httpResponse.data.errorMessage)+")",notifications.message("danger","Error!",message,persist.httpError),verbose&&$log.error(message)},notifications}]}),angular.module("patternfly.notification").directive("pfNotification",function(){"use strict";return{scope:{pfNotificationType:"=",pfNotificationMessage:"=",pfNotificationHeader:"=",pfNotificationPersistent:"=",pfNotificationIndex:"="},restrict:"E",templateUrl:"notification/notification.html"}}),angular.module("patternfly.notification").directive("pfNotificationList",function(){"use strict";return{restrict:"E",templateUrl:"notification/notification-list.html"}}),angular.module("patternfly.select",[]).directive("pfSelect",function($timeout){"use strict";return{restrict:"A",require:"?ngModel",scope:{selectPickerOptions:"=pfSelect"},link:function(scope,element,attrs,ngModel){var optionCollectionList,optionCollection,$render=ngModel.$render;element.selectpicker(scope.selectPickerOptions),ngModel.$render=function(){$render.apply(this,arguments),$timeout(function(){element.selectpicker("refresh")},0,!1)},attrs.ngOptions&&(optionCollectionList=attrs.ngOptions.split("in "),optionCollection=optionCollectionList[optionCollectionList.length-1],scope.$watchCollection(optionCollection,function(){element.selectpicker("refresh")})),attrs.$observe("disabled",function(){element.selectpicker("refresh")})}}}),angular.module("patternfly.utils").directive("pfTransclude",function(){"use strict";return{restrict:"A",link:function($scope,$element,$attrs,controller,$transclude){var iChildScope,iScopeType;if(!$transclude)throw new Error("pfTransclude - Illegal use of pfTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}");switch(iScopeType=$attrs.pfTransclude||"sibling"){case"sibling":$transclude(function(clone){$element.empty(),$element.append(clone)});break;case"parent":$transclude($scope,function(clone){$element.empty(),$element.append(clone)});break;case"child":iChildScope=$scope.$new(),$transclude(iChildScope,function(clone){$element.empty(),$element.append(clone),$element.on("$destroy",function(){iChildScope.$destroy()})})}}}}),angular.module("patternfly.validation",[]).directive("pfValidation",function($timeout){"use strict";return{restrict:"A",require:"ngModel",scope:{pfValidation:"&",pfValidationDisabled:"="},link:function(scope,element,attrs,ctrl){function validate(){var valid,val=scope.inputCtrl.$modelValue,valFunc=scope.pfValidation({input:val});attrs.pfValidation||(valFunc=!0),valid=!val||valFunc||""===val,toggleErrorClass(scope.valEnabled&&!valid?!0:!1)}function toggleErrorClass(add){var messageElement=element.next(),parentElement=element.parent(),hasErrorM=parentElement.hasClass("has-error"),wasHidden=messageElement.hasClass("ng-hide");scope.inputCtrl.$setValidity("pf-validation",!add),add&&(hasErrorM||parentElement.addClass("has-error"),wasHidden&&messageElement.removeClass("ng-hide")),add||(hasErrorM&&parentElement.removeClass("has-error"),wasHidden||messageElement.addClass("ng-hide"))}scope.inputCtrl=ctrl,scope.valEnabled=!attrs.pfValidationDisabled,scope.$watch("pfValidationDisabled",function(newVal){scope.valEnabled=!newVal,newVal?(scope.inputCtrl.$setValidity("pfValidation",!0),toggleErrorClass(!1)):validate()}),attrs.pfValidation?$timeout(function(){validate()},0):!scope.inputCtrl.$valid&&scope.inputCtrl.$dirty&&toggleErrorClass(!0),scope.$watch("inputCtrl.$valid",function(isValid){toggleErrorClass(isValid?!1:!0)}),scope.$watch("inputCtrl.$modelValue",function(){validate()})}}}),angular.module("patternfly.views").directive("pfDataList",[function(){"use strict";return{restrict:"A",scope:{config:"=?",items:"=",eventId:"@id"},transclude:!0,templateUrl:"views/datalist/data-list.html",controller:["$scope",function($scope){$scope.defaultConfig={selectItems:!1,multiSelect:!1,dblClick:!1,selectionMatchProp:"uuid",selectedItems:[],checkDisabled:!1,showSelectBox:!0,rowHeight:36,onSelect:null,onSelectionChange:null,onCheckBoxChange:null,onClick:null,onDblClick:null},$scope.config=$.extend(!0,angular.copy($scope.defaultConfig),$scope.config)}],link:function(scope,element,attrs){attrs.$observe("config",function(){scope.config=$.extend(!0,angular.copy(scope.defaultConfig),scope.config),scope.config.selectItems||(scope.config.selectedItems=[]),!scope.config.multiSelect&&scope.config.selectedItems&&scope.config.selectedItems.length>0&&(scope.config.selectedItems=[scope.config.selectedItems[0]])}),scope.itemClick=function(e,item){var alreadySelected,selectionChanged=!1,continueEvent=!0;return scope.checkDisabled(item)?continueEvent:(scope.config&&scope.config.selectItems&&item&&(scope.config.multiSelect&&!scope.config.dblClick?(alreadySelected=_.find(scope.config.selectedItems,function(itemObj){return itemObj===item}),alreadySelected?scope.config.selectedItems=_.without(scope.config.selectedItems,item):(scope.config.selectedItems.push(item),selectionChanged=!0)):scope.config.selectedItems[0]===item?(scope.config.dblClick||(scope.config.selectedItems=[],selectionChanged=!0),continueEvent=!1):(scope.config.selectedItems=[item],selectionChanged=!0),selectionChanged&&scope.config.onSelect&&scope.config.onSelect(item,e),selectionChanged&&scope.config.onSelectionChange&&scope.config.onSelectionChange(scope.config.selectedItems,e)),scope.config.onClick&&scope.config.onClick(item,e),continueEvent)},scope.dblClick=function(e,item){scope.config.onDblClick&&scope.config.onDblClick(item,e)},scope.checkBoxChange=function(item){scope.config.onCheckBoxChange&&scope.config.onCheckBoxChange(item)},scope.isSelected=function(item){var matchProp=scope.config.selectionMatchProp;return scope.config.selectedItems.length?_.find(scope.config.selectedItems,function(itemObj){return itemObj[matchProp]===item[matchProp]}):!1},scope.checkDisabled=function(item){return scope.config.checkDisabled&&scope.config.checkDisabled(item)}}}}]),angular.module("patternfly.card").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("card/basic/card.html","

{{headTitle}}

{{subTitle}}
")}]),angular.module("patternfly.charts").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("charts/donut/donut-pct-chart.html","
"),$templateCache.put("charts/sparkline/sparkline-chart.html","
"),$templateCache.put("charts/utilization/utilization-chart.html",'
{{config.title}}
{{currentValue}}
{{currentText}}
of {{chartData.total}} {{config.units}}
{{legendLeftText}} {{legendRightText}}
')}]),angular.module("patternfly.form").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("form/datepicker/datepicker.html",'
'),$templateCache.put("form/form-buttons/form-buttons.html",'
'),$templateCache.put("form/form-group/form-group.html",'
  • {{ message }}
')}]),angular.module("patternfly.notification").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("notification/notification-list.html",'
'),$templateCache.put("notification/notification.html",'
{{pfNotificationHeader}} {{pfNotificationMessage}}
')}]),angular.module("patternfly.views").run(["$templateCache",function($templateCache){"use strict";$templateCache.put("views/datalist/data-list.html",'
')}]); +>>>>>>> Add Data List Directive diff --git a/dist/styles/angular-patternfly.css b/dist/styles/angular-patternfly.css index bd07ad018..79bea122e 100644 --- a/dist/styles/angular-patternfly.css +++ b/dist/styles/angular-patternfly.css @@ -79,3 +79,75 @@ margin-left: 0; } +.data-list-pf { + background: #fff; + overflow-x: hidden; + overflow-y: auto; + padding-bottom: 1px; +} +.data-list-pf .list-row { + margin-right: 0px; + position: relative; + padding-right: 0px; + width: 100%; +} +.data-list-pf .list-content { + left: 15px; + position: relative; +} +.data-list-pf .list-content.with-check-box { + border-left: solid 2px #d2d2d2; + left: 30px; + margin-left: 10px; +} +.data-list-pf .list-content.with-menu { + margin-right: 30px; + right: 15px; +} +.data-list-pf .list-check-box { + bottom: 0px; + left: 20px; + position: absolute; + top: 0px; + width: 20px; +} +.data-list-pf .data-list-loading { + background: rgba(0, 0, 0, 0.05); +} +.data-list-pf .list-group-item:first-of-type { + margin-top: 0; +} +.data-list-pf .list-group-item .list-column { + float: left; + padding: 5px 0px; +} +.data-list-pf .list-group-item .pficon { + -webkit-align-items: center; + align-items: center; + color: #1186C1; + font-size: 26px; + width: 26px; +} + +.data-list-pf .list-group-item.active, +.data-list-pf .list-group-item.active:hover, +.data-list-pf .list-group-item.active:focus { + background-color: #def3ff; + border-color: #def3ff; + color: #000000; +} + +.data-list-pf .list-group-item:hover, +.data-list-pf .list-group-item:focus { + background-color: #ededed; + border-color: #ededed; +} + +.data-list-pf .list-group-item.active .pficon, +.data-list-pf .list-group-item.active:hover .pficon, +.data-list-pf .list-group-item.active:focus .pficon { + color: #ffffff; +} +.data-list-pf .row-column { + padding-right: 5px; +} diff --git a/dist/styles/angular-patternfly.min.css b/dist/styles/angular-patternfly.min.css index ac86dca04..4bdef5f22 100644 --- a/dist/styles/angular-patternfly.min.css +++ b/dist/styles/angular-patternfly.min.css @@ -1 +1 @@ -.donut-chart-pf{width:100%;float:left;padding-top:10px}.donut-tooltip-pf{background:#434343;color:#fff;opacity:.9;filter:alpha(opacity=90);padding:2px 6px}.donut-title-big-pf{font-size:22px;font-weight:400;color:#333}.donut-title-small-pf{font-size:12px;font-weight:400;color:#333}.utilization-chart-pf .current-values{border-bottom:1px solid #d1d1d1;float:left;padding:0 5px 10px 0;width:100%}.utilization-chart-pf .available-count{font-size:22px;font-weight:300;line-height:22px;margin-bottom:2px;padding-left:0;padding-right:5px}.utilization-chart-pf .title{font-size:15px;font-weight:400}.utilization-chart-pf .available-text{color:#333;font-size:12px;font-weight:400;line-height:12px;margin-bottom:2px;padding-left:5px;padding-right:5px}.utilization-chart-pf .radial-chart{float:left;padding-top:10px;width:100%}.utilization-chart-pf .sparkline-chart{float:left;margin-left:-5px;margin-right:-5px;width:100%}.utilization-chart-pf .legend-text{color:inherit;display:block;font-size:12px;font-weight:400;margin-left:0} \ No newline at end of file +.donut-chart-pf{width:100%;float:left;padding-top:10px}.donut-tooltip-pf{background:#434343;color:#fff;opacity:.9;filter:alpha(opacity=90);padding:2px 6px}.donut-title-big-pf{font-size:22px;font-weight:400;color:#333}.donut-title-small-pf{font-size:12px;font-weight:400;color:#333}.utilization-chart-pf .current-values{border-bottom:1px solid #d1d1d1;float:left;padding:0 5px 10px 0;width:100%}.utilization-chart-pf .available-count{font-size:22px;font-weight:300;line-height:22px;margin-bottom:2px;padding-left:0;padding-right:5px}.utilization-chart-pf .title{font-size:15px;font-weight:400}.utilization-chart-pf .available-text{color:#333;font-size:12px;font-weight:400;line-height:12px;margin-bottom:2px;padding-left:5px;padding-right:5px}.utilization-chart-pf .radial-chart{float:left;padding-top:10px;width:100%}.utilization-chart-pf .sparkline-chart{float:left;margin-left:-5px;margin-right:-5px;width:100%}.utilization-chart-pf .legend-text{color:inherit;display:block;font-size:12px;font-weight:400;margin-left:0}.data-list-pf{background:#fff;overflow-x:hidden;overflow-y:auto;padding-bottom:1px}.data-list-pf .list-row{margin-right:0;position:relative;padding-right:0;width:100%}.data-list-pf .list-content{left:15px;position:relative}.data-list-pf .list-content.with-check-box{border-left:solid 2px #d2d2d2;left:30px;margin-left:10px}.data-list-pf .list-content.with-menu{margin-right:30px;right:15px}.data-list-pf .list-check-box{bottom:0;left:20px;position:absolute;top:0;width:20px}.data-list-pf .data-list-loading{background:rgba(0,0,0,.05)}.data-list-pf .list-group-item:first-of-type{margin-top:0}.data-list-pf .list-group-item .list-column{float:left;padding:5px 0}.data-list-pf .list-group-item .pficon{-webkit-align-items:center;align-items:center;color:#1186C1;font-size:26px;width:26px}.data-list-pf .list-group-item.active,.data-list-pf .list-group-item.active:focus,.data-list-pf .list-group-item.active:hover{background-color:#def3ff;border-color:#def3ff;color:#000}.data-list-pf .list-group-item:focus,.data-list-pf .list-group-item:hover{background-color:#ededed;border-color:#ededed}.data-list-pf .list-group-item.active .pficon,.data-list-pf .list-group-item.active:focus .pficon,.data-list-pf .list-group-item.active:hover .pficon{color:#fff}.data-list-pf .row-column{padding-right:5px} \ No newline at end of file diff --git a/src/patternfly.module.js b/src/patternfly.module.js index 746e5ba37..a3d781297 100644 --- a/src/patternfly.module.js +++ b/src/patternfly.module.js @@ -10,6 +10,8 @@ angular.module('patternfly', [ 'patternfly.form', 'patternfly.notification', 'patternfly.select', - 'patternfly.validation' + 'patternfly.utils', + 'patternfly.validation', + 'patternfly.views' ]); diff --git a/src/utils/transclude-directive.js b/src/utils/transclude-directive.js new file mode 100644 index 000000000..fad0ca244 --- /dev/null +++ b/src/utils/transclude-directive.js @@ -0,0 +1,169 @@ + +/** + * @ngdoc directive + * @name patternfly.utils.directive:pfTransclude + * @restrict A + * @element ANY + * @param {string} pfTransclude specifies the type of transclusion to use.
+ * Values: + * + * + * @description + * Directive for transcluding in directives and setting up scope of children of parent directives. This is a workaround + * for https://github.com/angular/angular.js/issues/5489 + * + * @example + + + .pf-transclude-example div { + border: 1px solid #337ab7; + margin-bottom: 20px; + margin-left: 20px; + } + + .pf-transclude-example p { + background-color: #337ab7; + margin: 0; + padding: 5px 10px; + } + + .pf-transclude-example id { + display: inline-block; + background-color: #def3ff; + color: #000000; + border-radius: 10px; + width: 20px; + height: 20px; + text-align: center; + line-height: 20px; + margin-left: 5px; + } + + .pf-transclude-example pre { + padding: 5px; + border-width: 0px; + } + + +
+ Here the scope id is: {{$id}} + + +
This content was transcluded using pf-transclude or pf-transclude="sibling".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+ + +
This content was transcluded using pf-transclude="parent".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+ + +
This content was transcluded using pf-transclude="child".
Its scope is: {{$id}} the parent of which is {{$parent.$id}}
+
+
+
+ + + angular.module('patternfly.utils') + .controller( 'UtilCtrl', function($scope) { + + }) + + .config(function($provide){ + $provide.decorator('ngTranscludeDirective', ['$delegate', function($delegate) { + // Remove the original directive + $delegate.shift(); + return $delegate; + }]); + }) + + .directive( 'transcludeSibling', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + + .directive( 'transcludeParent', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + + .directive( 'transcludeChild', function() { + return { + restrict: 'E', + transclude: true, + scope: {}, + template: + '
' + + '

I am a directive with scope {{$id}}

' + + '' + + '
' + } + }) + ; +
+
+ */ +angular + .module('patternfly.utils').directive('pfTransclude', function () { + 'use strict'; + return { + restrict: 'A', + link: function ($scope, $element, $attrs, controller, $transclude) { + var iChildScope; + var iScopeType; + + if (!$transclude) { + throw new Error('pfTransclude - ' + + 'Illegal use of pfTransclude directive in the template! ' + + 'No parent directive that requires a transclusion found. ' + + 'Element: {0}'); + } + + iScopeType = $attrs.pfTransclude || 'sibling'; + + switch (iScopeType) { + case 'sibling': + $transclude(function (clone) { + $element.empty(); + $element.append(clone); + }); + break; + case 'parent': + $transclude($scope, function (clone) { + $element.empty(); + $element.append( clone ); + }); + break; + case 'child': + iChildScope = $scope.$new(); + $transclude( iChildScope, function (clone) { + $element.empty(); + $element.append( clone ); + $element.on( '$destroy', function () { + iChildScope.$destroy(); + }); + }); + break; + } + } + }; + }); diff --git a/src/utils/utils.module.js b/src/utils/utils.module.js new file mode 100644 index 000000000..27fa9dbaa --- /dev/null +++ b/src/utils/utils.module.js @@ -0,0 +1,2 @@ + +angular.module( 'patternfly.utils', [] ); diff --git a/src/views/datalist/data-list-directive.js b/src/views/datalist/data-list-directive.js new file mode 100644 index 000000000..ebf8c9e3c --- /dev/null +++ b/src/views/datalist/data-list-directive.js @@ -0,0 +1,311 @@ +/** + * @ngdoc directive + * @name patternfly.views.directive:pfDataList + * + * @description + * Directive for rendering a data list. + *

+ * + * @param {object} config configuration settings for the data list:
+ * + * + * @param {Array} items the data to be shown in the data list
+ * + * @example + + + +
+
+
+
+
+ {{item.name}} +
+
+ {{item.address}} +
+
+ {{item.city}} +
+
+ {{item.state}} +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+
+ +
+
+
+
+ + +
+
+ +
+
+ +
+
+
+ + + angular.module('patternfly.views').controller('ViewCtrl', ['$scope', + function ($scope) { + $scope.eventText = ''; + var handleSelect = function (item, e) { + $scope.eventText = item.name + ' selected\n' + $scope.eventText; + }; + var handleSelectionChange = function (selectedItems, e) { + $scope.eventText = selectedItems.length + ' items selected\n' + $scope.eventText; + }; + var handleClick = function (item, e) { + $scope.eventText = item.name + ' clicked\n' + $scope.eventText; + }; + var handleDblClick = function (item, e) { + $scope.eventText = item.name + ' double clicked\n' + $scope.eventText; + }; + var handleCheckBoxChange = function (item, selected, e) { + $scope.eventText = item.name + ' checked: ' + item.selected + '\n' + $scope.eventText; + }; + + var checkDisabledItem = function(item) { + return $scope.showDisabled && (item.name === "John Smith"); + }; + + $scope.showDisabled = false; + + $scope.config = { + selectItems: false, + multiSelect: false, + dblClick: false, + selectionMatchProp: 'name', + selectedItems: [], + checkDisabled: checkDisabledItem, + showSelectBox: true, + rowHeight: 36, + onSelect: handleSelect, + onSelectionChange: handleSelectionChange, + onCheckBoxChange: handleCheckBoxChange, + onClick: handleClick, + onDblClick: handleDblClick + }; + + $scope.items = [ + { + name: "Fred Flintstone", + address: "20 Dinosaur Way", + city: "Bedrock", + state: "Washingstone" + }, + { + name: "John Smith", + address: "415 East Main Street", + city: "Norfolk", + state: "Virginia" + }, + { + name: "Frank Livingston", + address: "234 Elm Street", + city: "Pittsburgh", + state: "Pennsylvania" + }, + { + name: "Judy Green", + address: "2 Apple Boulevard", + city: "Cincinatti", + state: "Ohio" + }, + { + name: "Pat Thomas", + address: "50 Second Street", + city: "New York", + state: "New York" + }, + ] + } + ]); + +
+ */ +angular.module('patternfly.views').directive('pfDataList', [ + function () { + 'use strict'; + return { + restrict: 'A', + scope: { + config: '=?', + items: '=', + eventId: '@id' + }, + transclude: true, + templateUrl: 'views/datalist/data-list.html', + controller: ['$scope', + function ($scope) { + $scope.defaultConfig = { + selectItems: false, + multiSelect: false, + dblClick: false, + selectionMatchProp: 'uuid', + selectedItems: [], + checkDisabled: false, + showSelectBox: true, + rowHeight: 36, + onSelect: null, + onSelectionChange: null, + onCheckBoxChange: null, + onClick: null, + onDblClick: null + }; + + $scope.config = $.extend(true, angular.copy($scope.defaultConfig), $scope.config); + } + ], + + link: function (scope, element, attrs) { + attrs.$observe('config', function () { + scope.config = $.extend(true, angular.copy(scope.defaultConfig), scope.config); + if (!scope.config.selectItems) { + scope.config.selectedItems = []; + } + if (!scope.config.multiSelect && scope.config.selectedItems && scope.config.selectedItems.length > 0) { + scope.config.selectedItems = [scope.config.selectedItems[0]]; + } + }); + + scope.itemClick = function (e, item) { + var alreadySelected; + var selectionChanged = false; + var continueEvent = true; + + // Ignore disabled item clicks completely + if (scope.checkDisabled(item)) { + return continueEvent; + } + + if (scope.config && scope.config.selectItems && item) { + if (scope.config.multiSelect && !scope.config.dblClick) { + + alreadySelected = _.find(scope.config.selectedItems, function (itemObj) { + return itemObj === item; + }); + + if (alreadySelected) { + // already selected so deselect + scope.config.selectedItems = _.without(scope.config.selectedItems, item); + } else { + // add the item to the selected items + scope.config.selectedItems.push(item); + selectionChanged = true; + } + } else { + if (scope.config.selectedItems[0] === item) { + if (!scope.config.dblClick) { + scope.config.selectedItems = []; + selectionChanged = true; + } + continueEvent = false; + } else { + scope.config.selectedItems = [item]; + selectionChanged = true; + } + } + + if (selectionChanged && scope.config.onSelect) { + scope.config.onSelect(item, e); + } + if (selectionChanged && scope.config.onSelectionChange) { + scope.config.onSelectionChange(scope.config.selectedItems, e); + } + } + if (scope.config.onClick) { + scope.config.onClick(item, e); + } + + return continueEvent; + }; + + scope.dblClick = function (e, item) { + if (scope.config.onDblClick) { + scope.config.onDblClick(item, e); + } + }; + + scope.checkBoxChange = function (item) { + if (scope.config.onCheckBoxChange) { + scope.config.onCheckBoxChange(item); + } + }; + + scope.isSelected = function (item) { + var matchProp = scope.config.selectionMatchProp; + if (scope.config.selectedItems.length) { + return _.find(scope.config.selectedItems, function (itemObj) { + return itemObj[matchProp] === item[matchProp]; + }); + } + return false; + }; + + scope.checkDisabled = function (item) { + return scope.config.checkDisabled && scope.config.checkDisabled(item); + }; + } + }; + } +]); diff --git a/src/views/datalist/data-list.html b/src/views/datalist/data-list.html new file mode 100644 index 000000000..d39a1913c --- /dev/null +++ b/src/views/datalist/data-list.html @@ -0,0 +1,17 @@ +
+
+
+
+
+
+ +
+
+
+
diff --git a/src/views/views.module.js b/src/views/views.module.js new file mode 100644 index 000000000..efea27b94 --- /dev/null +++ b/src/views/views.module.js @@ -0,0 +1,8 @@ +/** + * @name patternfly + * + * @description + * Views module for patternfly. + * + */ +angular.module('patternfly.views', ['patternfly.utils']); diff --git a/styles/angular-patternfly.css b/styles/angular-patternfly.css index bd07ad018..79bea122e 100644 --- a/styles/angular-patternfly.css +++ b/styles/angular-patternfly.css @@ -79,3 +79,75 @@ margin-left: 0; } +.data-list-pf { + background: #fff; + overflow-x: hidden; + overflow-y: auto; + padding-bottom: 1px; +} +.data-list-pf .list-row { + margin-right: 0px; + position: relative; + padding-right: 0px; + width: 100%; +} +.data-list-pf .list-content { + left: 15px; + position: relative; +} +.data-list-pf .list-content.with-check-box { + border-left: solid 2px #d2d2d2; + left: 30px; + margin-left: 10px; +} +.data-list-pf .list-content.with-menu { + margin-right: 30px; + right: 15px; +} +.data-list-pf .list-check-box { + bottom: 0px; + left: 20px; + position: absolute; + top: 0px; + width: 20px; +} +.data-list-pf .data-list-loading { + background: rgba(0, 0, 0, 0.05); +} +.data-list-pf .list-group-item:first-of-type { + margin-top: 0; +} +.data-list-pf .list-group-item .list-column { + float: left; + padding: 5px 0px; +} +.data-list-pf .list-group-item .pficon { + -webkit-align-items: center; + align-items: center; + color: #1186C1; + font-size: 26px; + width: 26px; +} + +.data-list-pf .list-group-item.active, +.data-list-pf .list-group-item.active:hover, +.data-list-pf .list-group-item.active:focus { + background-color: #def3ff; + border-color: #def3ff; + color: #000000; +} + +.data-list-pf .list-group-item:hover, +.data-list-pf .list-group-item:focus { + background-color: #ededed; + border-color: #ededed; +} + +.data-list-pf .list-group-item.active .pficon, +.data-list-pf .list-group-item.active:hover .pficon, +.data-list-pf .list-group-item.active:focus .pficon { + color: #ffffff; +} +.data-list-pf .row-column { + padding-right: 5px; +} diff --git a/test/karma.conf.js b/test/karma.conf.js index 21a017154..6e181ea74 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -15,10 +15,12 @@ module.exports = function(config) { 'lib/patternfly/components/c3/c3.js', 'lib/angular/angular.js', 'lib/angular-mocks/angular-mocks.js', + 'lib/lodash/lodash.js', 'misc/test-lib/helpers.js', 'src/**/*.module.js', 'src/**/*.js', 'src/**/*.html', + 'test/utils/*.js', 'test/**/*.spec.js' ], diff --git a/test/utils/specUtils.js b/test/utils/specUtils.js new file mode 100644 index 000000000..66bab77fc --- /dev/null +++ b/test/utils/specUtils.js @@ -0,0 +1,10 @@ + +function eventFire(el, etype){ + if (el.fireEvent) { + (el.fireEvent('on' + etype)); + } else { + var evObj = document.createEvent('Events'); + evObj.initEvent(etype, true, false); + el.dispatchEvent(evObj); + } +} diff --git a/test/views/datalist/data-list.spec.js b/test/views/datalist/data-list.spec.js new file mode 100644 index 000000000..ec0eb8fef --- /dev/null +++ b/test/views/datalist/data-list.spec.js @@ -0,0 +1,194 @@ +describe('Directive: pfDataList', function () { + var $scope; + var $compile; + var $timeout; + var element; + + // load the controller's module + beforeEach(function () { + module('patternfly.views', 'patternfly.utils', 'views/datalist/data-list.html'); + }); + + beforeEach(inject(function (_$compile_, _$rootScope_, _$timeout_) { + $compile = _$compile_; + $scope = _$rootScope_; + $timeout = _$timeout_; + })); + + var compileHTML = function (markup, scope) { + element = angular.element(markup); + $compile(element)(scope); + + scope.$digest(); + scope.$apply(); + }; + + beforeEach(function () { + $scope.systemModel = [ + {uuid: '1', name: 'One', size: 291445030, capacity: 8200000000}, + {uuid: '2', name: 'Two', size: 1986231544, capacity: 8700000000}, + {uuid: '3', name: 'Three', size: 7864632, capacity: 7800000000}, + {uuid: '4', name: 'Four', size: 8162410, capacity: 3200000000}, + {uuid: '5', name: 'Five', size: 6781425410, capacity: 7600000000} + ]; + $scope.listConfig = { + selectedItems: [] + }; + + var htmlTmp = '
'+ + '
{{item.name}}
' + + '
'; + + compileHTML(htmlTmp, $scope); + }); + + it('should have correct number list items', function () { + var rows = element.find('.list-content'); + expect(rows.length).toBe(5); + + }); + + it('should show the select checkbox by default', function (){ + var items; + var checkItems; + + items = element.find('.list-content'); + checkItems = element.find('.list-check-box'); + expect(checkItems.length).toBe(items.length); + + // allow item selection + $scope.listConfig.selectItems = false; + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + }); + + it('should not show the select checkboxes when showSelectBox is false', function (){ + var checkItems; + + checkItems = element.find('.list-check-box'); + expect(checkItems.length).toBe(5); + + // disallow checkbox selection + $scope.listConfig.showSelectBox = false; + $scope.$digest(); + + checkItems = element.find('.list-check-box'); + expect(checkItems.length).toBe(0); + }); + + it('should not allow selection when selectItems is false', function (){ + var items; + var selectedItems; + + items = element.find('.list-content'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + + // allow item selection + $scope.listConfig.selectItems = false; + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + }); + + it('should add selected class to clicked list item', function (){ + var items; + var selectedItems; + + items = element.find('.list-content'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + + // allow item selection + $scope.listConfig.selectItems = true; + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(1); + }); + + it('should manage selected array', function (){ + var items; + var selectedItems; + + items = element.find('.list-content'); + expect($scope.listConfig.selectedItems.length).toBe(0); + + // allow item selection + $scope.listConfig.selectItems = true; + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(1); + expect($scope.listConfig.selectedItems.length).toBe(1); + + }); + + it('should handle double click event', function (){ + var items; + var doubleClickWorking = false; + var onDoubleClick = function (){ + doubleClickWorking = true; + }; + + $scope.listConfig.onDblClick = onDoubleClick; + + items = element.find('.list-content'); + expect(doubleClickWorking).toBe(false); + + eventFire(items[1],'dblclick'); + expect(doubleClickWorking).toBe(true); + + }); + + it('should respect the multiSelect setting', function (){ + var items; + var selectedItems; + + items = element.find('.list-content'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + + // allow item selection + $scope.listConfig.selectItems = true; + $scope.listConfig.multiSelect = false; + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(1); + + eventFire(items[2],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(1); + + $scope.listConfig.multiSelect = true; + + eventFire(items[3],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(2); + }); + + it('should set disabled rows correctly', function (){ + var items; + var selectedItems; + var disabledItems; + var checkDisabled = function (item){ + return item.uuid === '2'; + }; + + $scope.listConfig.checkDisabled = checkDisabled; + + $scope.$digest(); + + items = element.find('.list-content'); + disabledItems = element.find('.disabled'); + expect(disabledItems.length).toBe(1); + + eventFire(items[1],'click'); + selectedItems = element.find('.active'); + expect(selectedItems.length).toBe(0); + }); +});