123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- 'use strict';
- define(['jquery', '../lib/@waca/core-client/js/core-client/ui/AccessibleView', 'doT', 'underscore', './DialogBlocker'], function ($, BaseClass, dot, _, DialogBlocker) {
- var idCounter = 0;
-
- var Flyout = BaseClass.extend({
-
- bsFullTemplateString: '<div {{? it.marginLeft}}style="margin-left:{{=it.marginLeft}}px" {{?}}class="popover {{=it.popoverClass}}"><div class="arrow"></div><div class="flyout-content-container">{{=it.containerTemplate}}</div></div>',
-
- containerTemplateString: '{{=it.closeBtn}} <div id="{{=it.id}}" class="flyout-content"> <div style="{{? it.ht}}height:{{=it.ht}}px;{{?}}{{? it.wd}}width:{{=it.wd}}px;{{?}} {{? it.ht || it.wd}} overflow:auto;-webkit-overflow-scrolling: touch;{{?}}" class="popover-content"> </div></div>',
-
- closeBtnTemplateString: '<div id="{{=it.bid}}" class="flyout-close-button"> <span class="glyphicon glyphicon-remove-circle"></span> </div>',
- placement: null,
- enableTabLooping: true,
- init: function init(options) {
- Flyout.inherited('init', this, [{ launchPoint: options.launchPoint }]);
- _.defaults(options, { modal: false });
- this.forceRedraw = options.forceRedraw;
- this.logger = options.logger;
- this.selector = options.selector;
- this.notCentered = options.notCentered;
- this.relatedNodes = options.relatedNodes || [];
- this.once = options.once;
- this.modal = options.modal;
-
- this.hideOnMouseLeave = options.hideOnMouseLeave;
- if (!this.placement) {
- this.placement = options.placement;
- }
- this.notCentered = options.notCentered;
- this.alignment = options.alignment;
- this.hideEventsAttached = false;
-
-
- if (options.pageX) {
- var selector = $(this.selector);
- var placement = options.placement || this._calculatePlacement(0, selector);
- if (placement === 'top' || placement === 'bottom') {
- var midpoint = $(this.selector).offset().left + $(this.selector).width() / 2;
- options.marginLeft = options.pageX - midpoint;
- }
- }
- idCounter++;
- this.id = '_pop_' + idCounter;
- var btnId = this.id + '_btn_';
- var template = this._generateContainerTemplate(options, this.id, btnId);
- this.contentRootSelector = '#' + this.id + '>.popover-content';
- var view = options.viewInstance;
- if (!view) {
- view = new options.viewClass({
- popupContainer: this,
- content: options.content,
- viewOptions: options.viewOptions,
- contentRootSelector: this.contentRootSelector,
- maxHt: options.maxHt,
- maxWd: options.maxWd,
- logger: this.logger
- });
- this.isDestroyContentView = true;
- }
- this.view = view;
- var content = view;
- if (view.getRenderedHtml) {
- content = view.getRenderedHtml.bind(view);
- }
- this.content = content;
- var container = options.container;
- if (this.modal) {
- container = DialogBlocker.getJqBlocker();
- container.addClass('show');
- container.addClass('transparent');
- this._blocker = container;
- }
- var viewport = options.viewport;
- var popoverOptions = {
- placement: options.placement || this._calculatePlacement.bind(this),
- trigger: 'manual',
- container: container,
- content: content,
- viewport: viewport,
- html: true,
- template: template,
- sanitize: false
- };
- this.popover = $(this.selector).popover(popoverOptions);
- this._bindEvents(options, btnId);
- },
- _addBlocker: function _addBlocker() {
- DialogBlocker.show(document.body, this._blocker);
- },
-
- _findCurrentOpenedPopoversToClose: function _findCurrentOpenedPopoversToClose() {
- var $flyoutContents = $('.flyout-content-container');
- var flyouts = [];
- _.each($flyoutContents, function (flyoutContent) {
- var $flyoutContent = $(flyoutContent);
- var flyout = $flyoutContent.data('flyout');
- if (flyout) {
- flyouts.push(flyout);
- }
- });
- return flyouts;
- },
- open: function open(nodeToOpen) {
- if (this.forceRedraw || !this.isOpen) {
- return this._open(nodeToOpen);
- }
- this.isOpenReady = Promise.resolve();
- return this.isOpenReady;
- },
-
- _open: function _open(nodeToOpen) {
- var _this = this;
- this.isOpenReady = new Promise(function (resolve) {
- var openedFlyouts = _this._findCurrentOpenedPopoversToClose();
- if (openedFlyouts.length > 0) {
-
- var hideContext = {};
- var flyoutsToBeCloseMap = {};
- _.each(openedFlyouts, function (flyout) {
- flyoutsToBeCloseMap[flyout.id] = flyout;
- hideContext[flyout.id] = {
- flyout: flyout,
- hiddenPopoverCallback: function hiddenPopoverCallback() {
- delete flyoutsToBeCloseMap[flyout.id];
- if (_.keys(flyoutsToBeCloseMap).length === 0) {
- resolve(hideContext);
- }
- }
- };
- flyout.popover.on('hidden.bs.popover', hideContext[flyout.id].hiddenPopoverCallback);
- });
- _.each(hideContext, function (context) {
- context.flyout.close();
- });
- } else {
- resolve();
- }
- }).then(function (hideContext) {
- _.each(hideContext, function (context) {
- context.flyout.popover.off('hidden.bs.popover', context.hiddenPopoverCallback);
- });
-
- if (_this.modal) {
- if (!_this.isOpen && $(_this.popover).has(nodeToOpen)) {
- _this._addBlocker();
- }
- }
- _this._openFlyout(nodeToOpen);
- });
- return this.isOpenReady;
- },
-
- openIsReady: function openIsReady() {
- var _this2 = this;
- var promise = this.isOpenReady || Promise.resolve();
- return promise.then(function () {
- return !!_this2.isOpen;
- });
- },
-
- _openFlyout: function _openFlyout(node) {
- var _this3 = this;
- if (!this.isOpen) {
- if ($(this.popover).has(node)) {
- var $node = $(node);
- $node.popover('show');
- var popover = $node.length && $.data($node[0], 'bs.popover');
- if (popover && popover.$tip) {
- if (this.alignment === 'top') {
- popover.$tip.css('top', popover.$element.position().top);
- } else if (this.alignment === 'left') {
- popover.$tip.css('left', popover.$element.position().left);
- }
- if (this.notCentered && (this.placement === 'right' || this.placement === 'left')) {
- popover.$tip.css('top', popover.$element.offset().top);
- } else if (this.notCentered && (this.placement === 'top' || this.placement === 'bottom')) {
- popover.$tip.css('left', popover.$element.offset().left);
- }
- this.adjustPopoverInViewport(popover);
-
- popover.$tip.on('userCloseFlyout', function () {
- _this3.close();
- });
- } else {
- console.error('Cannot retrieve popover object');
- }
- }
- this.isOpen = true;
- }
- },
-
- adjustPopoverInViewport: function adjustPopoverInViewport(popover) {
- var $tip = popover.$tip;
- var tipWindowCoord = $tip.get(0).getBoundingClientRect();
- var windowWidth = $(window).width();
- var windowHeight = $(window).height();
- var popoverMarginLeftWidth = parseFloat($tip.css('margin-left'));
- var popoverMarginRightWidth = parseFloat($tip.css('margin-right'));
- var popoverMarginTopWidth = parseFloat($tip.css('margin-top'));
- var popoverMarginBottomWidth = parseFloat($tip.css('margin-bottom'));
- var popoverLeftToBorder = tipWindowCoord.left + popoverMarginLeftWidth;
- var popoverRightToBorder = tipWindowCoord.right - popoverMarginRightWidth;
- var popoverTopToBorder = tipWindowCoord.top + popoverMarginTopWidth;
- var popoverBottomToBorder = tipWindowCoord.bottom - popoverMarginBottomWidth;
- if (popoverLeftToBorder < 0) {
- $tip.css('left', -popoverMarginLeftWidth);
- } else if (windowWidth < popoverRightToBorder) {
- var distanceToMove = Math.min(popoverRightToBorder - windowWidth, popoverMarginLeftWidth + tipWindowCoord.left);
- $tip.css('left', tipWindowCoord.left - distanceToMove);
- }
- if (popoverTopToBorder < 0) {
- $tip.css('top', -popoverMarginTopWidth);
- } else if (windowHeight < popoverBottomToBorder) {
- var _distanceToMove = Math.min(popoverBottomToBorder - windowHeight, popoverMarginBottomWidth + tipWindowCoord.top);
- $tip.css('top', tipWindowCoord.top - _distanceToMove);
- }
- },
-
- close: function close(e) {
- this.detachHideEvents();
- $(this.selector).popover('hide');
- this.view.trigger('flyout:hide', e);
- this._removeBlocker();
- this.restoreFocus();
- if (this.modal) {
-
- this.destroy();
- }
- this.isOpen = false;
- delete this.isOpenReady;
- if (this.view.onPopupDone) {
- this.view.onPopupDone();
- }
- },
- restoreFocus: function restoreFocus() {
- $(this.getLaunchPoint()).focus();
- },
-
- destroy: function destroy() {
- var _this4 = this;
- var options = {
- viewId: this.view.viewId
- };
- this.view.trigger('flyout:destroy', options);
- this.once = false;
-
- this.isOpen = false;
- delete this.isOpenReady;
- var promise = new Promise(function (resolve) {
- _this4.popover.on('hidden.bs.popover', function () {
- if (_this4.popover) {
- _this4.popover.off('shown.bs.popover');
- _this4.popover.off('hidden.bs.popover');
- _this4.popover.off('click.flyoutShowEvent tap.flyoutShowEvent');
- }
- var transition = $.support.transition;
- $.support.transition = false;
- $(_this4.selector).popover('destroy');
- $.support.transition = transition;
- _this4.detachHideEvents();
- if (_this4.isDestroyContentView && _this4.view && _this4.view.destroy) {
- _this4.view.destroy();
- _this4.view = null;
- }
- $(window).off('resize.flyoutResizeListener');
- resolve();
- });
- _this4._removeBlocker();
- if ($(_this4.selector).data && $(_this4.selector).data('bs.popover')) {
- $(_this4.selector).popover('hide');
- } else {
- resolve();
- }
- });
- return promise;
- },
- detachHideEvents: function detachHideEvents() {
- if (this.hideEventsAttached) {
- if (this.mouseHideEventHandler) {
- $('body').off('mousedown.flyoutHideEvent touchstart.flyoutHideEvent', this.mouseHideEventHandler);
- }
- if (this.scrollHideEventHandler) {
- $('body').off('wheel.flyoutHideEvent touchstart.flyoutHideEvent', this.scrollHideEventHandler);
- }
- if (this.keyboardHideEventHandler) {
- $('body').off('keydown.flyoutHideEvent', this.keyboardHideEventHandler);
- }
- if (this.onMouseLeaveEventHandler && this.popover) {
- var popover = this.popover.data('bs.popover');
- var $tip = popover && popover.$tip;
- if ($tip) {
- $tip.off('mouseleave', this.onMouseLeaveEventHandler);
- }
- }
- $(window).off('resize.flyoutResizeListener');
- this.hideEventsAttached = false;
- }
- },
- _generateContainerTemplate: function _generateContainerTemplate(options, id, btnId) {
- if (!this.closeBtnDotTempl) {
- this.closeBtnDotTempl = dot.template(this.closeBtnTemplateString || '');
- this.fullDotTempl = dot.template(this.bsFullTemplateString);
- this.containerDotTempl = dot.template(this.containerTemplateString);
- }
- var closeBtnStr;
- if (options.hasCloseBtn) {
- closeBtnStr = this.closeBtnDotTempl({
- bid: btnId
- });
- } else {
- closeBtnStr = '';
- }
- var sContainer = this.containerDotTempl({
- id: id,
- ht: options.maxHt,
- wd: options.maxWd,
- closeBtn: closeBtnStr
- });
- var sFullTempl = this.fullDotTempl({
- containerTemplate: sContainer,
- popoverClass: options.popoverClass ? options.popoverClass : '',
- marginLeft: options.marginLeft ? options.marginLeft : ''
- });
- return sFullTempl;
- },
- _bindEvents: function _bindEvents(options, btnId) {
- var _this5 = this;
- var view = this.view;
- if (options.hasCloseBtn) {
- this.popover.on('shown.bs.popover', function () {
- $('#' + btnId).onClick(_this5.close.bind(_this5));
- });
- }
- this.popover.on('shown.bs.popover', function () {
- var $tip = _this5.popover.data('bs.popover').$tip;
- if ($tip) {
- $tip.addClass('animationDone');
- $tip.on('tap', function (e) {
- e.stopPropagation();
- });
- }
- _this5.setFocus();
- _this5.enableLooping($(_this5.contentRootSelector));
- });
- this.popover.on('shown.bs.popover', this._setupFlyoutHideAction.bind(this));
- if (options.onVisible) {
- this.popover.one('shown.bs.popover', function () {
- var $tip = _this5.popover.data('bs.popover').$tip;
- options.onVisible($tip);
- });
- }
- if (view.onPopupShown) {
- this.popover.on('shown.bs.popover', view.onPopupShown.bind(view));
- }
- if (view.onPopupClosed) {
- this.popover.on('hidden.bs.popover', function () {
- view.onPopupClosed();
-
- if (_this5.once) {
- _this5.destroy();
- }
- });
- }
- },
- setFocus: function setFocus() {
- if (this.view && this.view.setFocus) {
- this.view.setFocus();
- }
- },
- _removeBlocker: function _removeBlocker() {
- if (this._blocker) {
- this._blocker.remove();
- this._blocker = null;
- }
- },
- _setupFlyoutHideAction: function _setupFlyoutHideAction() {
- var _this6 = this;
- if (!this.hideEventsAttached) {
- this.hideEventsAttached = true;
- var $tip = this.popover.data('bs.popover').$tip;
- var $flyoutContentNode = $('#' + this.id);
- var $ancestor = $flyoutContentNode.closest('.flyout-content-container');
- $ancestor.data('flyout', this);
- this.mouseHideEventHandler = function (e) {
- var flyout = this;
- $(this.selector).each(function () {
- var $this = $(this);
- var $relatedNodes = $(flyout.relatedNodes);
- var ignoreClick = flyout.relatedNodes && ($relatedNodes.has(e.target).length !== 0 || $relatedNodes.is(e.target));
- if (!ignoreClick && !$this.is(e.target) && $this.has(e.target).length === 0 && $tip && $tip.has(e.target).length === 0) {
- flyout.close(e);
- }
- });
- }.bind(this);
- $('body').on('mousedown.flyoutHideEvent touchstart.flyoutHideEvent', this.mouseHideEventHandler);
- this.scrollHideEventHandler = function (e) {
- var flyout = this;
- var $this = $(this);
- if (!$this.is(e.target) && $this.has(e.target).length === 0 && $tip && $tip.has(e.target).length === 0) {
- flyout.close(e);
- }
- }.bind(this);
- $('body').on('wheel.flyoutHideEvent touchstart.flyoutHideEvent', this.scrollHideEventHandler);
-
- this.keyboardHideEventHandler = function (e) {
-
- if (e.keyCode === 27 || e.keyCode === 219 && e.ctrlKey) {
- this.close(e);
- }
- return;
- }.bind(this);
- $('body').on('keydown.flyoutHideEvent', this.keyboardHideEventHandler);
-
- if (this.hideOnMouseLeave === true) {
- if ($tip) {
-
- this.onMouseLeaveEventHandler = function (e) {
- if (!_this6._oTimerOut) {
- _this6._oTimerOut = window.setTimeout(function () {
- _this6.close(e);
- _this6._oTimerOut = null;
- }, 500);
- }
- };
- $tip.on('mouseleave', this.onMouseLeaveEventHandler);
- }
- }
-
- $(window).on('resize.flyoutResizeListener', function (e) {
- _this6.close(e);
- });
- }
- },
-
- _calculatePlacement: function _calculatePlacement(tip, element) {
- var content = $(this.content);
- var $element = $(element);
- var placement = 'auto';
- var boundary = $(window);
- var padding = this.viewport ? this.viewport.padding : 0;
- var contentOuterHeight = content.outerHeight(true) || 0;
- var contentOuterWidth = content.outerWidth(true) || 0;
-
- if (Math.round($element.offset().top) >= Math.round(contentOuterHeight + padding)) {
- placement = 'top';
- } else if (Math.round(boundary.height() - ($element.offset().top + $element.outerHeight(true))) >= Math.round(contentOuterHeight + padding)) {
- placement = 'bottom';
- } else if (Math.round(boundary.width() - ($element.offset().left + $element.outerWidth(true))) >= Math.round(contentOuterWidth + padding)) {
- placement = 'right';
- } else if (Math.round($element.offset().left) >= Math.round(contentOuterWidth + padding)) {
- placement = 'left';
- }
- this.placement = placement;
- return placement;
- }
- });
- return Flyout;
- });
|