angular-ui / ui-layout

This directive allows you to split !
http://angular-ui.github.io/ui-layout/
MIT License
406 stars 198 forks source link

Event ui.layout.sizesLoaded wanted #160

Open joshlongerbeam opened 8 years ago

joshlongerbeam commented 8 years ago

I'm attaching my own directive to the ui-layout element that writes the current position of the ui-splitbar elements to local storage (specifically their style="left:..." property). But I'm having problems getting this directive to overwrite the splitbars' css values at the proper time when loading the page (it always starts-with/is-overwritten-by whatever I've specified in ui-layout-container size="...").

If I'm clearly using something not as intended (e.g., I should be pointing the directive at the sizes attr instead of css values or jquery should be working but I'm new to it), tell me and close the issue.

If this is a feature that would be useful for this or other reasons, tag it as enhancement.

SomeKittens commented 8 years ago

It sounds like you want to save the current grid and be able to load that later? I think @j--w is working on that.

joshlongerbeam commented 8 years ago

Yup! That's exactly what I'm doing. I almost have it working too: I decided to modify the size attributes instead of css widths, and apparently scope.$watch('ui.layout.resize' and scope.$on('ui.layout.resize' trigger at different times.

j--w commented 8 years ago

@SomeKittens , I wasn't working on persisting the sizes, just caching them during the session as per #100 which @petrsimon ended up resolving with his PR I believe. I think a localstorage layer could be built on top of his work if we wanted to persist the cached sizes.

joshlongerbeam commented 8 years ago

Here's the directive I've made. (can't link to file, in a private repo). Notes: It's only meant to handle widths between vertical splitters, and the localStorageService basically just interacts with local storage.

At the very least, I hope this helps show how much work-around is needed to manually employ such an enhancement.

angular.module('core').directive('saveSplit', ['localStorageService', '$timeout',

function(localStorageService, $timeout) {
    return {
        link: function(scope, element, attrs) {
            var widths = [];        // widths from localStorage (possibly in percent from old splitters)
            var minWidths = [];         // minimum widths (in px) of each panel
            var containers = [];            // jquery references to panes between splitters
            var inited = false;

            function updateWidths() {
                if(inited) {
                    widths = [];
                    containers.forEach(function(container) {
                        widths.push(parseInt(container.css('width'), 10));
                    });
                    localStorageService.set(attrs.saveSplit, widths);
                }
                setWidths();    //apply changes to html size attributes
            }

            function setWidths() {
                if (!containers.length)
                    findPanes();
                if(!minWidths.length) {
                    var temp;
                    element.children('div[ui-layout-container]').each(function(){
                        temp = $(this).attr('min-size');
                        temp = temp ? temp : 0; //incase no min-size given, .attr() returns undefined
                        minWidths.push(parseInt(temp, 10));
                    });
                }
                if(!widths.length)
                    widths = localStorageService.get(attrs.saveSplit);
                widths.forEach(function(width, index){
                    if(width && width >= minWidths[index])
                        containers[index].attr('size', width+'px');
                });
                inited = true;
            }

            function findPanes() {
                element.children('div[ui-layout-container]').each(function(){
                    containers.push($(this));
                });
            }

            scope.$watch('ui.layout.resize', function(){
                setWidths();
            });

            scope.$on('ui.layout.resize', function(){
                updateWidths();
            });
        }
    };
}

]);

Corresponding HTML: <div ui-layout="{flow : 'column', disableToggle:true}" save-split="driveSplitter"> <div ui-layout-container[s]></div> </div>

SomeKittens commented 8 years ago

@j--w ah, understood. Wouldn't be too hard to add in a persistent dealio.

@joshterainsights We'd love a PR! Would you mind adding to core? If not, that's ok, it'll just be up to the maintainer's schedules.

petrsimon commented 8 years ago

Can I ask why do you want to store splitbar positions and not container size instead? Conceptually, I think, the container is what we care about, splitbar position is secondary.

In my view, what we need is to serialize container sizes and their collapsed state.

The collapsed state is easy, see the updated README in master branch.

Serializing container sizes should be relatively easy to add. Each layout stores it's child containers in the container property. And each container stores uncollapsedSize property (which should be undefined for auto sized containers). So mapping over all layouts and containers will give you all their sizes, which you can store and later reuse. The size of auto-sized containers should not be stored.

There's also the size property of containers, which is the actual size and all containers should have it defined and it should be 0 for collapsed containers. When split bar is dragged, the uncollapsedSize is set (i.e. container is no longer an auto-sized container, except for "central" containers, see README).

The ui.layout.loaded event should fire after all sizes have been calculated and containers collapsed. So if you are seeing left:0px you either have collapsed container to the left of the splitbar or you are using flow: 'row' or there is something wrong.

joshlongerbeam commented 8 years ago

@petrsimon It's not so much that I care about splitbar positions, it's that that was the solution I saw that solved it. But you're right: the container-widths are the more important aspect. Currently, I actually set them to percentage widths.

Current project doesn't care about collapsed state since it's always disabled.

The directive I copy-pasted roughly uses the properties you described, and it's just to get the particular job done.

I have no idea what was happening with left:0px, as collapse is never enabled anywhere in the project.


@SomeKittens I'm currently bogged down with graduating from college and impending laser eye surgery, but I'd love to do a pull request in a month or so! I'll try to make it generic enough to handle heights/widths and collapsed states.