From 146256f8c71d209c2ead178d3d5c0d902c5e8846 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 24 Jun 2016 12:51:31 -0600 Subject: [PATCH] Modify hz-cell to use hz-field hz-cell doesn't use params, which causes lots of problems when trying to render changes to data...since it evaluates only once, reading what's assumed to be on scope. This patch adds 'table,' 'column,' and 'item' params so they may be better watched by the directive. hz-field does use params and thus is useful in many situations outside of hz-cell. This patch provides hz-field and lets hz-cell use it so all output logic is shared. hz-field also: a) accepts 'values' as a column configuration as we discussed in the last mid-cycle, so codes, etc. may be supplied without use of a filter; and b) accepts 'urlFunction' which translates the given item to a url which is linked on the outputted name (rather than having to write a template for a common link function). Follow-on patches will demonstrate use. Change-Id: I0835a90e61d0e708233da795964595f88616388c Partially-Implements: blueprint angular-registry --- .../widgets/property/hz-field.directive.js | 131 ++++++++++++++++++ .../widgets/property/property.module.js | 28 ++++ .../widgets/table/hz-cell.directive.js | 55 ++++---- .../widgets/table/hz-detail-row.html | 4 +- .../widgets/table/hz-dynamic-table.html | 2 +- .../widgets/table/hz-dynamic-table.spec.js | 48 +++++++ .../framework/widgets/widgets.module.js | 1 + .../static/app/core/images/images.module.js | 7 +- 8 files changed, 244 insertions(+), 32 deletions(-) create mode 100644 horizon/static/framework/widgets/property/hz-field.directive.js create mode 100644 horizon/static/framework/widgets/property/property.module.js diff --git a/horizon/static/framework/widgets/property/hz-field.directive.js b/horizon/static/framework/widgets/property/hz-field.directive.js new file mode 100644 index 0000000000..22d1d47db8 --- /dev/null +++ b/horizon/static/framework/widgets/property/hz-field.directive.js @@ -0,0 +1,131 @@ +/** + * (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +(function() { + 'use strict'; + + angular + .module('horizon.framework.widgets.property') + .directive('hzField', hzField); + + hzField.$inject = ['$filter']; + + /** + * @ngdoc directive + * @name hzField + * @param config {Object} - The field definition object, described below + * @param item {Object} - The object containing the property from config.id + * @description + * The `hzField` directive allows you to output an object's property using + * formatting as provided by a field configuration. + * + * The config object describes a single field, and the config object's 'id' + * property matches the name of a property in the 'item' parameter. For + * example, if config.id is 'name' then there should be an item.name that + * is evaluated for display using the logic described below. + * + * The field configuration may transform the data in the item's property + * using either a set of single-argument filters or functions, specified by + * the 'filters' property, or using the 'values' object in which the item + * property is mapped via the keys to the values in the given object. Note + * that a combination of 'filters' and 'values' may be used; in this case + * the filters are evaluated first. This allows for translations that will + * map to keys first (e.g. upper-casing a string with a filter so it matches + * upper-case keys), and allows the values provided in the 'values' mapping + * to be the final value produced. The 'urlFunction' option allows for a + * a function to be given, where the item is the sole parameter and the result + * should be a URL. + * + * @restrict E + * + * @scope + * @example + * + * var config = {id: 'a', title: 'Header A', priority: 1}; + * + * // Using urlFunction to create a link + * var linked = {id: 'b', title: 'Header B', priority: 2, urlFunction: myUrlFunction}, + * + * // Using defaultSort + * var defaultSort = {id: 'c', title: 'Header C', priority: 1, sortDefault: true}; + * + * // Using filters (can be combined with 'values') + * var filtered = {id: 'd', title: 'Header D', priority: 2, + * filters: [someFilterFunction, 'uppercase']}; + * + * // Using value mappings + * var mapped = {id: 'e', title: 'Header E', priority: 1, + * values: { + * 'a': 'apple', + * 'j': 'jacks' + * } + * }; + * + * function myUrlFunction(item) { + * return '/my/path/' + item.id; + * } + * + * ``` + * + * ``` + * + */ + function hzField($filter) { + + var directive = { + restrict: 'E', + scope: { + config: "=", + item: "=" + }, + link: link + }; + return directive; + + /////////////////// + + function link(scope, element) { + var config = scope.config; + var item = scope.item; + var propValue = item[config.id]; + var output = propValue; + if (config && config.filters) { + for (var i = 0; i < config.filters.length; i++) { + var filter = config.filters[i]; + // call horizon framework filter function if provided + if (angular.isFunction(filter)) { + output = filter(propValue); + // call angular filters + } else { + output = $filter(filter)(propValue); + } + } + } + if (config && config.values) { + // apply mapping values to the data if applicable + output = config.values[output]; + } + var url; + if (config && config.urlFunction) { + url = config.urlFunction(item); + } + if (url) { + element.append(angular.element('').attr('href', url).append(output)); + } else { + element.append(output); + } + } + } +})(); diff --git a/horizon/static/framework/widgets/property/property.module.js b/horizon/static/framework/widgets/property/property.module.js new file mode 100644 index 0000000000..709db36b1b --- /dev/null +++ b/horizon/static/framework/widgets/property/property.module.js @@ -0,0 +1,28 @@ +/* + * (c) Copyright 2016 Hewlett Packard Enterprise Development Company LP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @name horizon.framework.widgets.property + * @description + * This module provides support for displaying properties of registered resource + * types. + */ + angular.module('horizon.framework.widgets.property', []); + +})(); diff --git a/horizon/static/framework/widgets/table/hz-cell.directive.js b/horizon/static/framework/widgets/table/hz-cell.directive.js index 10d854ebee..efd94d2c43 100644 --- a/horizon/static/framework/widgets/table/hz-cell.directive.js +++ b/horizon/static/framework/widgets/table/hz-cell.directive.js @@ -20,26 +20,29 @@ .module('horizon.framework.widgets.table') .directive('hzCell', hzCell); - hzCell.$inject = ['$compile', '$filter']; + hzCell.$inject = ['$compile']; /** * @ngdoc directive * @name horizon.framework.widgets.table.directive:hzCell + * @param table {Object} - The table/controller context + * @param column {Object} - The column definition object, described below + * @param item {Object} - The object containing the property from column.id * @description * The `hzCell` directive allows you to customize your cell content. * When specifying your table configuration object, you may pass in a * template per each column. * + * See the documentation on hz-field for details on how to specify formatting + * based on the column configuration. + * * You should define a template when you want to format data or show more * complex content (e.g conditionally show different icons or a link). * You should reference the cell's 'item' attribute in the template if - * you need access to the cell's data. The attributes 'column' and 'item' - * should be defined outside of this directive. See example below. + * you need access to the cell's data. See example below. * * It should ideally be used within the context of the `hz-dynamic-table` directive. - * The params passed into `hz-dynamic-table` can be used in the custom template, - * including the 'table' scope. 'table' can be referenced if you want to pass in an - * outside scope. + * 'table' can be referenced in a template if you want to pass in an outside scope. * * @restrict E * @@ -55,27 +58,37 @@ * {id: 'c', title: 'Header C', priority: 1, sortDefault: true}, * {id: 'd', title: 'Header D', priority: 2, * template: '{$ item.id $}', - * filters: [someFilterFunction, 'uppercase']} + * filters: [someFilterFunction, 'uppercase']}, + * {id: 'e', title: 'Header E', priority: 1, + * values: { + * 'a': 'apple', + * 'j': 'jacks' + * } + * } * ] * }; * * ``` - * + * * * - * + * * * * * ``` * */ - function hzCell($compile, $filter) { + function hzCell($compile) { var directive = { restrict: 'E', - scope: false, + scope: { + table: '=', + column: '=', + item: '=' + }, link: link }; return directive; @@ -84,26 +97,14 @@ function link(scope, element) { var column = scope.column; - var item = scope.item; var html; - // if template provided, render, and place into cell if (column && column.template) { + // if template provided, render, and place into cell html = $compile(column.template)(scope); } else { - // apply filters to cell data if applicable - html = item[column.id]; - if (column && column.filters) { - for (var i = 0; i < column.filters.length; i++) { - var filter = column.filters[i]; - // call horizon framework filter function if provided - if (angular.isFunction(filter)) { - html = filter(item[column.id]); - // call angular filters - } else { - html = $filter(filter)(item[column.id]); - } - } - } + // NOTE: 'table' is not passed to hz-field as hz-field is intentionally + // not cognizant of a 'table' context as hz-cell is. + html = $compile('')(scope); } element.append(html); } diff --git a/horizon/static/framework/widgets/table/hz-detail-row.html b/horizon/static/framework/widgets/table/hz-detail-row.html index e6343c4ca8..80db5364bd 100644 --- a/horizon/static/framework/widgets/table/hz-detail-row.html +++ b/horizon/static/framework/widgets/table/hz-detail-row.html @@ -12,7 +12,7 @@
{$ column.title $}
-
+
- \ No newline at end of file + diff --git a/horizon/static/framework/widgets/table/hz-dynamic-table.html b/horizon/static/framework/widgets/table/hz-dynamic-table.html index d782fd79d8..78ed53dc8e 100644 --- a/horizon/static/framework/widgets/table/hz-dynamic-table.html +++ b/horizon/static/framework/widgets/table/hz-dynamic-table.html @@ -63,7 +63,7 @@ - +