Question

I have table of e.g. regexes which contains name, regex, time etc. All columns except regexes have fix width, table has set width to 100% and table is in div in page layout.

I need display each regex by following rules:

  1. if regex is shorter than column width - display full regex
  2. if regex is longer than column width
    a. display icon for display full regex, part of regex which fits in column and ellipsis (...)

    b. display icon for display shorted regex and full regex

All rules must be dynamically evaluated if window is resized or if column width is changed.

Example:

--------------------------------------------------------------------------------
| Name    | Regex                                          | Time       | Rule |
--------------------------------------------------------------------------------
| Full    | (^) \b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b | 2012-10-01 | 2b   |
| Short   | [0-9a-f]{64}                                   | 2012-11-23 | 1    |
| To long | (>) ^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.(?:[A-Z]{2}...| 2012-11-27 | 2a   |
--------------------------------------------------------------------------------

What I have (updated)

solution without ellipsis

Directive

angular.module('ui.directives').directive('collapsibleText', function ($window, $compile, $timeout) {
    return {
        restrict: 'A',
        require: '^collapsibleText',
        scope: { collapsibleText: '@' },
        template: '<div style="display: inline-block;height: 20px;white-space: nowrap;">'
                    + '<i style="cursor:pointer" ng-hide="textSize < parentSize && !collapsed" ng-class="collapsed && \'icon-collapse\' || \'icon-expand\'" ng-click="changeCollapsed()"></i>'
                    + '<div ng-class="collapsed && \'no-collapsible\' || \'collapsible-text\'">{{collapsibleText}}</div>'
                + '</div>',
        controller: ['$scope', function ($scope) {
            $scope.collapsed = false;

            $scope.getTextSize = function () {
                var paddingLeft = $scope.element.css('paddingLeft'),
                    paddingRight = $scope.element.css('paddingRight');

                var $shadow = angular.element('<span></span>').css({
                    position: 'absolute',
                    paddingLeft: paddingLeft,
                    paddingRight: paddingRight,
                    fontSize: $scope.element.css('fontSize'),
                    fontFamily: $scope.element.css('fontFamily'),
                    lineHeight: $scope.element.css('lineHeight'),
                    resize: 'none',
                    visibility: 'hidden'
                });
                angular.element(document.body).append($shadow);
                $shadow.html($scope.collapsibleText);

                $scope.textSize = $shadow[0].offsetWidth + 20;
                return $scope.textSize;
            };

            $scope.getParentSize = function() {
                $scope.parentSize = $scope.parent[0].offsetWidth;
                return $scope.parentSize;
            };

            $scope.changeCollapsed = function () {
                $scope.collapsed = !$scope.collapsed;
            };
        }],
        link: function (scope, element, attrs, ctrl) {
            scope.element = $(element);
            scope.parent = scope.element.parent();

            scope.getTextSize();

            var w = angular.element($window);
            scope.getWindowDimensions = function () {
                return { 'h': w.height(), 'w': w.width() };
            };
            scope.$watch(scope.getWindowDimensions, function (newValue, oldValue) {
                scope.getParentSize();
            }, true);

            w.bind('resize', function () {
                scope.$apply();
            });

            $timeout(function () { scope.getParentSize(); }, 0);
        }
    };
});

html

...
<td><span collapsible-text="regex"></span></td>
...

Where is problem

  • if I expand one regex, other long regexes ended with ellipses although is shorter then column width
  • on start, all regexes have collapsed icon until somebody click to the icon

Is here some better solution?

Was it helpful?

Solution

My final solution

angular.module('ui.directives').directive('collapsibleText', function ($window, $timeout) {
    return {
        restrict: 'A',
        require: '^collapsibleText',
        scope: { collapsibleText: '@' },
        template: '<div style="display: inline-block;height: 20px;white-space: nowrap;position: relative;padding-right: 30px;">'
                    + '<i style="cursor:pointer" ng-hide="textSize < parentSize && !collapsed" ng-class="collapsed && \'icon-collapse\' || \'icon-expand\'" ng-click="changeCollapsed()"></i>'
                    + '<div ng-class="collapsed && \'no-collapsible\' || \'collapsible-text\'">{{collapsibleText}}</div>'
                    + '<span ng-hide="textSize < parentSize">...</span>'
                + '</div>',
        controller: ['$scope', function ($scope) {
            $scope.collapsed = false;

            $scope.getTextSize = function () {
                var paddingLeft = $scope.element.css('paddingLeft'),
                    paddingRight = $scope.element.css('paddingRight');

                var $shadow = angular.element('<span></span>').css({
                    position: 'absolute',
                    paddingLeft: paddingLeft,
                    paddingRight: paddingRight,
                    fontSize: $scope.element.css('fontSize'),
                    fontFamily: $scope.element.css('fontFamily'),
                    lineHeight: $scope.element.css('lineHeight'),
                    resize: 'none',
                    visibility: 'hidden'
                });
                angular.element(document.body).append($shadow);
                $shadow.html($scope.collapsibleText);

                $scope.textSize = $shadow[0].offsetWidth + 40;
                return $scope.textSize;
            };

            $scope.getParentSize = function() {
                $scope.parentSize = $scope.parent[0].offsetWidth;
                return $scope.parentSize;
            };

            $scope.changeCollapsed = function () {
                $scope.collapsed = !$scope.collapsed;
                $timeout(function() {
                     angular.element($window).triggerHandler('collapseChanged');
                }, 100);
            };
        }],
        link: function (scope, element) {
            scope.element = $(element);
            scope.parent = scope.element.parent();

            scope.getTextSize();

            var w = angular.element($window);
            w.bind('resize shown collapseChanged', function () {
                scope.getParentSize();
                scope.$apply();
            });
        }
    };
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top