import ngModule from '../../module'; import './style.css'; tooltip.$inject = ['$document', '$compile', '$interpolate', '$sce', '$templateCache', '$http', '$q']; function tooltip($document, $compile, $interpolate, $sce, $templateCache, $http, $q) { var promise; function _getTemplate(tooltipTemplateUrl) { var template = $templateCache.get(tooltipTemplateUrl); if (typeof template === 'undefined') { template = $http.get(tooltipTemplateUrl).then(function onGetTemplateSuccess(response) { if (promise) { promise.resolve(response.data); } promise = undefined; return response.data; }); $templateCache.put(tooltipTemplateUrl, template); } return template; } function getTemplate(tooltipTemplateUrl) { var _promise = $q.defer(); var template = _getTemplate(tooltipTemplateUrl); if (template) { _promise.resolve(template); } else { promise = _promise; } return _promise.promise; } return { restrict: 'A', priority: -1, link: function($scope, element, attrs) { let tipHtml = '
{{::text}}
'; let tip; let tipClassName = 'tooltip'; let tipActiveClassName = 'tooltip-show'; let scope = $scope.$new(); scope.tipClass = [tipClassName]; scope.text = attrs.vnTooltip || ''; if (attrs.tooltipHtml) { scope.isHtmlContent = true; scope.htmlContent = $sce.trustAsHtml(attrs.tooltipHtml); _compileTip(); } else if (attrs.tooltipTemplate) { getTemplate(attrs.tooltipTemplate).then(template => { scope.isHtmlContent = true; scope.htmlContent = $sce.trustAsHtml($interpolate(template)(scope)); _compileTip(); }); } else { scope.isHtmlContent = false; scope.htmlContent = null; _compileTip(); } if (attrs.tooltipPosition) { scope.tipClass.push('tooltip-' + attrs.tooltipPosition); } else { scope.tipClass.push('tooltip-down'); } function _compileTip() { tip = $compile(tipHtml)(scope); $document.find('body').append(tip); _bindEvents(); } function _bindEvents() { element.bind('mouseover', function(e) { _showTooltip(e); }); element.on('mouseout', function() { _hideTooltip(); }); tip.on('mouseover', function(e) { _showTooltip(e); }); tip.on('mouseout', function() { _hideTooltip(); }); element.on('$destroy', function() { tip.remove(); scope.$destroy(); }); } function _calculatePosition(e) { let pos = element[0].getBoundingClientRect(); let tipPos = tip[0].getBoundingClientRect(); let offset = {top: 0, left: 0}; let tipWidth = tipPos.width || tipPos.right - tipPos.left; let tipHeight = tipPos.height || tipPos.bottom - tipPos.top; let elWidth = pos.width || pos.right - pos.left; let elHeight = pos.height || pos.bottom - pos.top; let tipOffset = 10; if (tip.hasClass('tooltip-right')) { offset.top = pos.top - (tipHeight / 2) + (elHeight / 2); offset.left = pos.right + tipOffset; } else if (tip.hasClass('tooltip-left')) { offset.top = pos.top - (tipHeight / 2) + (elHeight / 2); offset.left = pos.left - tipWidth - tipOffset; } else if (tip.hasClass('tooltip-down')) { offset.top = pos.top + elHeight + tipOffset; offset.left = pos.left - (tipWidth / 2) + (elWidth / 2); } else { offset.top = pos.top - tipHeight - tipOffset; offset.left = pos.left - (tipWidth / 2) + (elWidth / 2); } // outsides if (offset.left + tipPos.width > window.innerWidth) { // right outside let diffLeft = (offset.left + tipPos.width) - window.innerWidth; offset.left -= diffLeft + 10; let arrow = tip[0].querySelector('.tooltip-arrow'); if (arrow) { angular.element(arrow).css('margin-left', diffLeft + 'px'); } } else if (offset.left < 10) { // left outside offset.left = 10; let arrow = tip[0].querySelector('.tooltip-arrow'); if (arrow) { angular.element(arrow).css('margin-left', '10px'); } } if (offset.top > window.innerHeight) { // down outside offset.top = pos.top - tipHeight - tipOffset; } else if (offset.top < 10) { // top outside offset.top = pos.top + elHeight + tipOffset; } tip.css('top', offset.top + 'px'); tip.css('left', offset.left + 'px'); } function _showTooltip(e) { tip.addClass(tipActiveClassName); _calculatePosition(e); } function _hideTooltip() { tip.removeClass(tipActiveClassName); } } }; } ngModule.directive('vnTooltip', tooltip);