/************************************************************************************

DevPortal Navigation Popover

This is a custom popover for the desktop version of the devportal menu.
It is unique in two ways.

1. It allows you to specify a screen size below which the popover will
not appear.  This allows us to do something different for mobile.

2. It allows you to hover over the modal and click on a link in the
body of the popover.

**************************************************************************************/ P.when(“jQuery”).register(“jquery-placeholder”, function ($) {

'use strict';

// NAV POPOVER PUBLIC CLASS DEFINITION
// ===============================

var DPNavbarPopover = function (element, options) {
    this.options    = null;
    this.timeout    = null;
    this.hoverState = null;
    this.$element   = null;

    this.init(element, options);
}

DPNavbarPopover.TRANSITION_DURATION = 150;

DPNavbarPopover.DEFAULTS = {
    animation: true,
    minWindowWidth: 1000,
    template:
        '<div class="dp-navbar-popover">' +
            '<div class="dp-navbar-popover-arrow"></div>' +
            '<div class="dp-navbar-popover-content"></div>' +
        '</div>',
    trigger: 'hover focus',
    delay: 0,
    html: false,
    content: ''
}

DPNavbarPopover.prototype.init = function (element, options) {
    this.$element  = $(element);
    this.options   = this.getOptions(options);

    var triggers = this.options.trigger.split(' ');

    for (var i = triggers.length; i--;) {
        var trigger = triggers[i];

        if (trigger === 'click') {
            this.$element.click($.proxy(this.toggle, this));
        } else if (trigger !== 'manual') {
            if (trigger === 'hover') {
              this.$element.mouseenter($.proxy(this.enter, this));
              this.$element.mouseleave($.proxy(this.leave, this));
            }
            else {
              this.$element.focusin($.proxy(this.enter, this));
              this.$element.focusout($.proxy(this.leave, this));
            }
        }
    }
}

DPNavbarPopover.prototype.getDefaults = function () {
    return DPNavbarPopover.DEFAULTS;
}

DPNavbarPopover.prototype.getOptions = function (options) {
    options = $.extend({}, this.getDefaults(), this.$element.data(), options);

    if (options.delay && typeof options.delay === 'number') {
        var delay = options.delay;
        options.delay = {
            show: delay,
            hide: delay
        };
    }

    return options;
}

DPNavbarPopover.prototype.enter = function () {
    var self = this;
    if (window.innerWidth > self.options.minWindowWidth) {

        if (self.$popover && self.$popover.is(':visible')) {
            self.hoverState = 'in';
            return;
        }

        clearTimeout(self.timeout);

        self.hoverState = 'in';

        if (!self.options.delay || !self.options.delay.show) {
            return self.show();
        }

        self.timeout = setTimeout(function () {
            if (self.hoverState === 'in') {
                self.show();
            }
        }, self.options.delay.show);
    }
}

DPNavbarPopover.prototype.leave = function (event) {
    var self = this;
    var container;

    clearTimeout(self.timeout);

    self.hoverState = 'out';

    if (!self.options.delay || !self.options.delay.hide) {
        return self.hide();
    }

    self.timeout = setTimeout(function () {
        if (self.hoverState === 'out') {
            self.hide();
        }
    }, self.options.delay.hide);

    if (event.currentTarget) {
        container = $(event.currentTarget).siblings('.dp-navbar-popover');
        container.one('mouseenter', function() {
            clearTimeout(self.timeout);
            container.one('mouseleave', function(event) {
                // This recursive call caused an unresponsive script
                // warning dialog. Changing to hide() fixed that and doesn't
                // appear to have any negative effects.
                //self.leave(event);
                self.hide();
            });
        });
    }
}

DPNavbarPopover.prototype.show = function () {
    // What does this do?
    var e = $.Event('show.dp.nav.popover');
    this.$element.trigger(e)

    if (this.hasContent()) {
        var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
        if (e.isDefaultPrevented() || !inDom) {
            return;
        }
        var that = this;

        var $popover = this.popover();

        var tipId = this.getUID();

        this.setContent();
        $popover.attr('id', tipId);
        this.$element.attr('aria-describedby', tipId);

        if (this.options.animation) {
            $popover.addClass('fade');
        }

        $popover
            .detach()
            .css({ top: 0, left: 0, display: 'block' })
            .data('dp.navbar.popover', this);

        $popover.insertAfter(this.$element)

        var pos = this.getPosition();
        var offset = { top: pos.top + pos.height, left: pos.left };

        this.applyPlacement(offset);

        var complete = function () {
            var prevHoverState = that.hoverState;
            that.$element.trigger('shown.bs.' + that.type);
            that.hoverState = null;

            if (prevHoverState === 'out') {
                that.leave(that);
            }
        }

        if ($.support.transition && this.$popover.hasClass('fade')) {
            $popover
                .one('bsTransitionEnd', complete)
                .emulateTransitionEnd(DPNavbarPopover.TRANSITION_DURATION);
        } else {
            complete();
        }
    }
}

DPNavbarPopover.prototype.applyPlacement = function (offset, placement) {
    var $popover = this.popover();
    var elWidth = this.$element[0].offsetWidth;
    var arrowOffset = (elWidth / 2) - 11;

    offset.top  = offset.top + 10;
    offset.left = offset.left;

    $popover.addClass('in');
    $popover.offset(offset);

    this.arrow().css('margin-left', arrowOffset + 'px')
}

DPNavbarPopover.prototype.hasContent = function () {
    return this.getContent();
}

DPNavbarPopover.prototype.getContent = function () {
    if (this.$element.attr('data-content')) {
        return this.$element.attr('data-content');
    } else {
        if (typeof this.options.content === 'function') {
            return this.options.content.call(this.$element[0]);
        } else {
            return this.options.content;
        }
    }
}

DPNavbarPopover.prototype.setContent = function () {
    var $popover = this.popover();
    var content = this.getContent();

    $popover.find('.dp-navbar-popover-content').children().detach().end()[
        // we use append for html objects to maintain js events
        this.options.html ? (typeof content === 'string' ? 'html' : 'append') : 'text'
    ](content)

    $popover.removeClass('fade top bottom left right in')
}

DPNavbarPopover.prototype.hide = function (callback) {
    var that = this;
    var $popover = this.popover();
    var e = $.Event('hide.dp.nav.popover');

    function complete() {
        $popover.fadeOut();
        if (that.hoverState !== 'in') {
            $popover.detach()
        }

        that.$element
            .removeAttr('aria-describedby')
            .trigger('hidden.dp.nav.popover')

        if (callback) {
            callback();
        }
    }

    this.$element.trigger(e);

    if (e.isDefaultPrevented()) {
        return;
    }

    $popover.removeClass('in');

// Removed the transition logic as it resulted in menus that never disappeared. // // if ($.support.transition && this.$popover.hasClass('fade')) { // $popover // .one('bsTransitionEnd', complete) // .emulateTransitionEnd(DPNavbarPopover.TRANSITION_DURATION) // } else {

complete();

// }

    this.hoverState = null;

    return this;
}

DPNavbarPopover.prototype.hasContent = function () {
    return this.getContent();
}

DPNavbarPopover.prototype.getPosition = function ($element) {
    $element = $element || this.$element;

    var el = $element[0];

    var elRect    = el.getBoundingClientRect()
    if (elRect.width === null) {
        // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
        elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
    }
    var elOffset  = $element.offset()
    return $.extend({}, elRect, elOffset);
}

DPNavbarPopover.prototype.getUID = function () {
    var UID = Math.round(Math.random() * 1000000);
    return 'dp-navbar-popover-' + UID;
}

DPNavbarPopover.prototype.popover = function () {
    if (!this.$popover) {
        this.$popover = $(this.options.template);
    }
    return this.$popover
}

DPNavbarPopover.prototype.arrow = function () {
    if (!this.$arrow) {
        this.$arrow = this.popover().find('.dp-navbar-popover-arrow');
    }
    return this.$arrow;
}

DPNavbarPopover.prototype.toggle = function (e) {
    var self = this
    if (e) {
        self = $(e.currentTarget).data('dp.navbar.popover')
    }

    self.popover().hasClass('in') ? self.leave(self) : self.enter(self)
}

// Added for debugging
DPNavbarPopover.prototype.getMenuName = function () {
    return this.$element.find("a.dp-navbar-button").text().trim();
}

// TOOLTIP PLUGIN DEFINITION
// =========================

function Plugin(option) {
    return this.each(function () {
        var $this   = $(this);
        var data    = $this.data('dp.navbar.popover');
        var options = typeof option === 'object' && option;

        if (!data && option === 'destroy') {
            return;
        }
        if (!data) {
            $this.data('dp.navbar.popover', (data = new DPNavbarPopover(this, options)));
        }
        if (typeof option === 'string') {
            data[option]();
        }
    })
}

var old = $.fn.dpNavbarPopover

$.fn.dpNavbarPopover             = Plugin
$.fn.dpNavbarPopover.Constructor = DPNavbarPopover

// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================

function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
        WebkitTransition : 'webkitTransitionEnd',
        MozTransition    : 'transitionend',
        OTransition      : 'oTransitionEnd otransitionend',
        transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
        if (el.style[name] !== undefined) {
            return { end: transEndEventNames[name] }
        }
    }

    return false; // explicit for ie8 (._.)
}

// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
    var called = false
    var $el = this
    $(this).one('bsTransitionEnd', function () {
        called = true;
    })
    var callback = function () {
        if (!called) {
            $($el).trigger($.support.transition.end);
        }
    }
    setTimeout(callback, duration);
    return this;
}

$(function () {
    $.support.transition = transitionEnd();

    if (!$.support.transition) {
        return;
    }

    $.event.special.bsTransitionEnd = {
        bindType: $.support.transition.end,
        delegateType: $.support.transition.end,
        handle: function (e) {
            if ($(e.target).is(this)) {
                return e.handleObj.handler.apply(this, arguments);
            }
        }
    }
})

});