eliace/ergo-js

View on GitHub
js/includes/popup.js

Summary

Maintainability
C
1 day
Test Coverage

$ergo.rules['popup'] = ['object'];

$ergo.alias('includes:popup', {

    defaults: {
        as: 'popup',
        popup: {
            to: null,
            at: 'left top',
            my: 'left top',
            offset: [0, 0],
            closeOn: 'outerClick',
            exclusive: true,
            boundary: 'auto'
        },
        states: {
            'dropup-auto:auto': 'dropup-auto',
            'dropdown-auto:auto': 'dropdown-auto',
            'no-auto:auto': ''
        },
        events: {
            'jquery:mouseleave': function(e){
                if(this.options.popup.closeOn == 'mouseleave') this.close();
            }
        },
        autoHeight: 'ignore' // игнорировать высоту контекстного меню при автоматическом расчете высоты
    },



//    overrides: {

        open: function(position) {

            var popups = Ergo.context._popups;

            // в эксклюзивном режиме закрываем другие всплывающие виджеты
            if(!popups.isEmpty() && this.options.popup.exclusive) {
                popups.applyAll('close');
                popups.removeAll();
            }



            var self = this;

            var x = 0;
            var y = 0;

            if(arguments.length == 2) {
                x = arguments[0];
                y = arguments[1];
                position = {};//offset: [arguments[0], arguments[1]]};
            }

            var p = $ergo.mergeOptions({}, [this.options.popup, position]);

            // позиционируем виджет

            // определяем координаты относительно точки "at"
            x += p.offset[0];
            y += p.offset[1];


            // получаем целевой элемент, относительно которого отображаем элемент
            var to_el = null;

            // определяем элемент, к которому будет привязан popup
            if(p.to) {
                to_el = $(p.to);
            }
            else if(this.parent) {
                to_el = this.parent.el;
            }



            // определяем смещение из привязки к элементу "to"


            if(to_el) {

                var at = p.at.split(' ');

                if(at[0] == 'right') x += to_el.outerWidth(false);
                else if(at[0] == 'center') x += to_el.outerWidth(false)/2;

                if(at[1] == 'bottom') y += to_el.outerHeight(false);
                else if(at[1] == 'center') y += to_el.outerHeight(false)/2;

                if(p.adjust)
    //                this.el.width(to_el.outerWidth(false));
                    this.el.css('min-width', to_el.outerWidth(false));

            }


            // определяем смещение из привязки точки popup

            // var my = p.my.split(' ');

            // if(my[0] == 'right') x -= this.el.outerWidth(false);
            // else if(my[0] == 'center') x -= this.el.outerWidth(false)/2;

            // if(my[1] == 'bottom') y -= this.el.outerHeight(false);
            // else if(my[1] == 'center') y -= this.el.outerHeight(false)/2;


            // if(to_el) {
                // // смещение целевого элемента
                // var offset = to_el.offset();
    //
                // x += offset.left;
                // y += offset.top;
            // }


            if(p.behaviour == 'contextmenu') {

                var max_w = $(document).scrollLeft() + $(window).width();
                var max_h = $(document).scrollTop() + $(window).height();
                var pop_h = this.el.outerHeight(true);
                var pop_w = this.el.outerWidth(true);

                var dh = (y + pop_h) - max_h;
                if(dh > 0) {
                    y -= pop_h;
                }

                var dw = (x + pop_w) - max_w;
                if(dw > 0) {
                    x -= dw;//pop_w;
                }

                this.el.css({'left': x, 'top': y});
            }
            else if(p.behaviour == 'global') {

                var offset = to_el.offset();
                x += offset.left;
                y += offset.top;

                y += to_el.outerHeight(false);


                this.el.css({'left': x, 'top': y});
            }




            if(p.behaviour != 'none') {

//                this.el.css({'left': x, 'top': y});

            }



            if(p.boundary == 'auto' && to_el) {
                // изменяем положение виджета в зависимости от расстояния до границы
                var offset = to_el.offset();
                var max_x = $(window).width();
                var max_y = $(window).height();
                var scroll_top = 0;

                this.el.parents().each(function(i, elem) {
                    scroll_top += $(elem).scrollTop();
                });

                if(offset.left + this.el.width() > max_x)
                    this.states.set('pull-left-auto');
                else
                    this.states.unset('pull-left-auto');

                if(offset.top + to_el.height() + this.el.outerHeight(true) - scroll_top > max_y)
                    this.states.set('dropup-auto');
                else if(this.states.is('dropup') && (offset.top - this.el.outerHeight(true) - scroll_top < 0))
                    this.states.set('dropdown-auto');
                else
                    this.states.set('no-auto');


            }



            // настраиваем размер виджета


            // определяем параметры закрытия

            // FIXME возможные проблемы при удалении
            $('html').one('click.ergoPopup', function(e) {
                this.events.fire('outerClick');
                if(this.options.popup.closeOn == 'outerClick') this.close();
            }.bind(this));

            Ergo.context.events.once('outerClick', function(e) {
                this.events.fire('outerClick');
                if(this.options.popup.closeOn == 'outerClick') this.close();
            }.bind(this), this);



            // добавляем текущий объект в список всплывших окон
            popups.add(this);


            return this.show().then(function(){
                self.events.fire('opened');
            });
        },


        close: function() {
            var self = this;
            var popups = Ergo.context._popups;

            var k = popups.keyOf(this);
            if( k > -1 ) {//Ergo.context._popup == this) {

                if(this != popups.last()) popups.get(k+1).close();  //TODO возможно, будет лучше, если закрытия будут связаны в цепочку

                popups.remove(this);

                Ergo.context.events.off(this);

                $('html').off('click.ergoPopup');

                return this.hide().then(function(){
                    self.events.fire('closed');
                });
            }

        },


//    },



    _construct: function() {

        if(!Ergo.context._popups)
            Ergo.context._popups = new Ergo.core.Array();

    }



});