From 6dac8df8bc1705d216451061562f8347fc68ef28 Mon Sep 17 00:00:00 2001 From: Nikos M Date: Thu, 17 Mar 2022 12:07:35 +0200 Subject: [PATCH] v.1.0.1 contd * position popup to maximize visible area * popup.hide() method * other changes --- README.md | 12 +++++--- src/InfoPopup.js | 72 ++++++++++++++++++++++++++++++++++++-------- src/InfoPopup.min.js | 2 +- test/demo.html | 2 +- 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ed1c4dd..ec57070 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A simple JavaScript class to show info popups easily for various combinations of items and events (Desktop and Mobile) -**version 1.0.1** (5 kB minified) +**version 1.0.1** (6 kB minified) [Live Example](https://foo123.github.io/examples/infopopup/) @@ -16,7 +16,7 @@ A simple JavaScript class to show info popups easily for various combinations of ``` ```javascript -InfoPopup({ +let infoPopup = InfoPopup({ // custom class for custom styling of popup infoClass: 'title-info', // custom class for custom styling of focused element @@ -33,9 +33,13 @@ InfoPopup({ // position popup differently on Y axis depending on item // options: 'bottom', 'center', 'top' (default) atItemY: (item) => item.href === '#bar' ? 'bottom' : 'top', - // close popup after 1 sec - closeDelay: 1000 + // hide popup after 1 sec + hideDelay: 1000 }); + +// programmatically show/hide popup +infoPopup.show(document.querySelector('[href="#foo"]')); +infoPopup.hide(); ``` [![interactive map with InfoPopup](/screenshot.png)](https://foo123.github.io/examples/infopopup/) diff --git a/src/InfoPopup.js b/src/InfoPopup.js index 5f93975..32c28a6 100644 --- a/src/InfoPopup.js +++ b/src/InfoPopup.js @@ -129,7 +129,7 @@ function InfoPopup(options) }; removeInfoPopup = function() { clearTimer(); - timer = setTimeout(removePopup, +(self.options.closeDelay || 0)); + timer = setTimeout(removePopup, +(self.options.hideDelay || 0)); }; handler2 = function handler2(evt) { if ('mouseleave' === evt.type) @@ -149,7 +149,7 @@ function InfoPopup(options) }; handler = function(evt) { var item = evt.target && closest(evt.target, self.options.item || '.info-item'); - if (item && ('function' === typeof self.options.content)) + if (item && is_function(self.options.content)) { self.show(item, evt); if ('click' !== self.options.trigger) @@ -181,10 +181,46 @@ function InfoPopup(options) case 'left': x = itemRect.left; addClass(infoPopup, 'left'); + if (0 > x) + { + if (itemRect.right - infoRect.width > x) + { + x = itemRect.right - infoRect.width; + removeClass(infoPopup, 'left'); + addClass(infoPopup, 'right'); + } + } + else if (x + infoRect.width > vw) + { + if (itemRect.right < x + infoRect.width) + { + x = itemRect.right - infoRect.width; + removeClass(infoPopup, 'left'); + addClass(infoPopup, 'right'); + } + } break; case 'right': x = itemRect.right - infoRect.width; addClass(infoPopup, 'right'); + if (0 > x) + { + if (itemRect.left > x) + { + x = itemRect.left; + removeClass(infoPopup, 'right'); + addClass(infoPopup, 'left'); + } + } + else if (itemRect.right > vw) + { + if (itemRect.left + infoRect.width < itemRect.right) + { + x = itemRect.left; + removeClass(infoPopup, 'right'); + addClass(infoPopup, 'left'); + } + } break; case 'center': default: @@ -231,13 +267,14 @@ function InfoPopup(options) break; case 'bottom': y = itemRect.bottom; + addClass(infoPopup, 'below'); if (y + infoRect.height > vh) { - y = itemRect.top - infoRect.height; - } - else - { - addClass(infoPopup, 'below'); + if (infoRect.height - itemRect.top < y + infoRect.height - vh) + { + y = itemRect.top - infoRect.height; + removeClass(infoPopup, 'below'); + } } break; case 'top': @@ -251,7 +288,7 @@ function InfoPopup(options) sy = document.body.scrollTop; y = 0; } - else + else if (vh - itemRect.bottom - infoRect.height > y) { y = itemRect.bottom; addClass(infoPopup, 'below'); @@ -279,10 +316,15 @@ function InfoPopup(options) removeEvent(document.body, 'touchstart', handler, {capture:true, passive:false}); } }; + self.hide = function() { + clearTimer(); + removePopup(); + }; self.show = function(item, evt) { + if (!item || !is_function(self.options.content)) return; var infoContent, imgs, loaded = 0; - infoContent = self.options.content(item); + infoContent = self.options.content(item, self); if (null == infoContent || false === infoContent) { return; @@ -303,8 +345,8 @@ function InfoPopup(options) clearCurrent(); - addClass(item, self.options.focusedClass || 'focused'); current = item; + addClass(current, self.options.focusedClass || 'focused'); document.body.appendChild(infoPopup); @@ -318,7 +360,12 @@ function InfoPopup(options) removeEvent(img, 'error', load); removeEvent(img, 'load', load); ++loaded; - if ((imgs.length === loaded) && infoPopup.parentNode && (infoPopup === ancestor(img, infoPopup))) + if ( + (imgs.length === loaded) + && (item === current) + && infoPopup.parentNode + && (infoPopup === ancestor(img, infoPopup)) + ) { // re-position popup positionAt(item, self.options.atItemX, self.options.atItemY); @@ -384,7 +431,8 @@ InfoPopup.prototype = { constructor: InfoPopup, options: null, dispose: null, - show: null + show: null, + hide: null }; InfoPopup.VERSION = VERSION; return InfoPopup; diff --git a/src/InfoPopup.min.js b/src/InfoPopup.min.js index e51bce7..a0d0d52 100644 --- a/src/InfoPopup.min.js +++ b/src/InfoPopup.min.js @@ -6,4 +6,4 @@ * https://github.com/foo123/InfoPopup * **/ -!function(t,e){"use strict";"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(function(t){return e()}):t.InfoPopup=e()}("undefined"!=typeof self?self:this,function(t){"use strict";var e=/^\s+|\s+$/g,h=String.prototype.trim?function(t){return t.trim()}:function(t){return t.replace(e,"")},i=null;function s(){var e=!1,t={};try{Object.defineProperty(t,"passive",{get:function(){return!(e=!0)}}),window.addEventListener("test",null,t),window.removeEventListener("test",null,t)}catch(t){e=!1}return e}function v(t,e){var o,n;t.classList?t.classList.add(e):(n=e,((o=t).classList?o.classList.contains(n):-1!==(" "+o.className+" ").indexOf(" "+n+" "))||(t.className=""===t.className?e:t.className+" "+e))}function g(t,e){t.classList?t.classList.remove(e):t.className=h((" "+t.className+" ").replace(" "+e+" "," "))}function y(t,e,o,n){null==i&&(i=s()),t.attachEvent?t.attachEvent("on"+e,o):t.addEventListener(e,o,i?n:"object"==typeof n?!!n.capture:!!n)}function b(t,e,o,n){null==i&&(i=s()),t.detachEvent?t.detachEvent("on"+e,o):t.removeEventListener(e,o,i?n:"object"==typeof n?!!n.capture:!!n)}function w(t){return t.getBoundingClientRect()}function C(t,e){if(t.closest)return t.closest(e);for(;t;){if(t.matches(e))return t;t=t.parentNode}}function E(t){return"function"==typeof t}function L(t){var p,s,e,o,c,r,n,i,u,a,l,d,f,m=this;if(!(m instanceof L))return new L(t);a=function(){o&&clearTimeout(o)},u=function(){c&&(g(c,m.options.focusedClass||"focused"),"function"==typeof m.options.onBlur&&m.options.onBlur(c),c=null)},n=function(t){t&&t.preventDefault&&t.preventDefault(),u(),p&&p.parentNode&&p.parentNode.removeChild(p)},i=function(){a(),o=setTimeout(n,+(m.options.closeDelay||0))},d=function t(e){"mouseleave"===e.type&&(e.target&&C(e.target,m.options.item||".info-item"))!==c||(b(document.body,e.type,t,{capture:!0,passive:!0}),i())},l=function(t){var e=t.target&&C(t.target,m.options.item||".info-item");e&&"function"==typeof m.options.content&&(m.show(e,t),"click"!==m.options.trigger&&y(document.body,"touchstart"===t.type?"touchend":"mouseleave",d,{capture:!0,passive:!0}))},r=function(t,e,o){var n,i,s,c,r,u,a,l;switch(E(e)&&(e=e(t,m)),E(o)&&(o=o(t,m)),p.style.position="absolute",g(p,"below"),g(p,"left"),g(p,"right"),n=w(document.body),i=w(t),s=w(p),u=window.innerWidth||document.documentElement.clientWidth,a=window.innerHeight||document.documentElement.clientHeight,l=document.body.scrollLeft||0,t=document.body.scrollTop||0,(e||"center").toLowerCase()){case"left":c=i.left,v(p,"left");break;case"right":c=i.right-s.width,v(p,"right");break;case"center":default:(c=i.left+i.width/2-s.width/2)<0?-c<=l?(document.body.scrollLeft+=c,l=document.body.scrollLeft,c=0):(c=i.left,v(p,"left")):c+s.width>u&&(c=i.right-s.width,v(p,"right"))}switch((o||"top").toLowerCase()){case"center":(r=i.top+i.height/2-s.height)<0&&(-r<=t?(document.body.scrollTop+=r,t=document.body.scrollTop,r=0):(r=i.top+i.height/2,v(p,"below")));break;case"bottom":(r=i.bottom)+s.height>a?r=i.top-s.height:v(p,"below");break;case"top":default:(r=i.top-s.height)<0&&(-r<=t?(document.body.scrollTop+=r,t=document.body.scrollTop,r=0):(r=i.bottom,v(p,"below")))}p.style.left=String(c+l-n.left)+"px",p.style.top=String(r+t-n.top)+"px"},m.options=t||{},m.dispose=function(){a(),n(),"click"===m.options.trigger?(e&&b(e,"click",n,{capture:!0,passive:!1}),b(document.body,"click",l,{capture:!0,passive:!1})):(p&&b(p,"mouseenter",f,{capture:!0,passive:!0}),p&&b(p,"touchstart",a,{capture:!0,passive:!0}),b(document.body,"mouseenter",l,{capture:!0,passive:!1}),b(document.body,"touchstart",l,{capture:!0,passive:!1}))},m.show=function(o,t){var n,i=0,e=m.options.content(o);null!=e&&!1!==e&&(e instanceof window.Node?(s.textContent="",s.appendChild(e)):s.innerHTML=h(String(e)),t&&t.preventDefault&&t.preventDefault(),a(),u(),v(o,m.options.focusedClass||"focused"),c=o,document.body.appendChild(p),(n=p.getElementsByTagName("img"))&&n.length&&[].forEach.call(n,function(e){var t;!e.complete&&(e.src&&e.src.length||e.currentSrc&&e.currentSrc.length)?(y(e,"error",t=function t(){b(e,"error",t),b(e,"load",t),++i,n.length===i&&p.parentNode&&p===function(t,e){for(;t;){if(t===e)return e;t=t.parentNode}}(e,p)&&r(o,m.options.atItemX,m.options.atItemY)}),y(e,"load",t)):++i}),r(o,m.options.atItemX,m.options.atItemY))},p||(v(p=document.createElement("div"),"info-popup"),m.options.infoClass&&v(p,m.options.infoClass),"click"===m.options.trigger?(p.appendChild(document.createElement("div")),v(p.firstChild,"header"),p.firstChild.appendChild(e=document.createElement("button")),v(e,"close"),e.setAttribute("title",m.options.closeMsg||"Close Popup"),y(e,"click",n,{capture:!0,passive:!1})):e=null,p.appendChild(s=document.createElement("div")),v(s,"content"),"click"===m.options.trigger?y(document.body,"click",l,{capture:!0,passive:!1}):(y(p,"mouseenter",f=function(t){a(),y(p,"mouseleave",function t(e){b(p,"mouseleave",t,{capture:!0,passive:!0}),i()},{capture:!0,passive:!0})},{capture:!0,passive:!0}),y(p,"touchstart",a,{capture:!0,passive:!0}),y(document.body,"mouseenter",l,{capture:!0,passive:!1}),y(document.body,"touchstart",l,{capture:!0,passive:!1})))}return L.prototype={constructor:L,options:null,dispose:null,show:null},L.VERSION="1.0.1",L}); \ No newline at end of file +!function(t,e){"use strict";"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(function(t){return e()}):t.InfoPopup=e()}("undefined"!=typeof self?self:this,function(t){"use strict";var e=/^\s+|\s+$/g,m=String.prototype.trim?function(t){return t.trim()}:function(t){return t.replace(e,"")},i=null;function s(){var e=!1,t={};try{Object.defineProperty(t,"passive",{get:function(){return!(e=!0)}}),window.addEventListener("test",null,t),window.removeEventListener("test",null,t)}catch(t){e=!1}return e}function g(t,e){var o,n;t.classList?t.classList.add(e):(n=e,((o=t).classList?o.classList.contains(n):-1!==(" "+o.className+" ").indexOf(" "+n+" "))||(t.className=""===t.className?e:t.className+" "+e))}function v(t,e){t.classList?t.classList.remove(e):t.className=m((" "+t.className+" ").replace(" "+e+" "," "))}function b(t,e,o,n){null==i&&(i=s()),t.attachEvent?t.attachEvent("on"+e,o):t.addEventListener(e,o,i?n:"object"==typeof n?!!n.capture:!!n)}function y(t,e,o,n){null==i&&(i=s()),t.detachEvent?t.detachEvent("on"+e,o):t.removeEventListener(e,o,i?n:"object"==typeof n?!!n.capture:!!n)}function w(t){return t.getBoundingClientRect()}function C(t,e){if(t.closest)return t.closest(e);for(;t;){if(t.matches(e))return t;t=t.parentNode}}function E(t){return"function"==typeof t}function L(t){var p,s,e,o,c,r,n,i,u,l,a,d,f,h=this;if(!(h instanceof L))return new L(t);l=function(){o&&clearTimeout(o)},u=function(){c&&(v(c,h.options.focusedClass||"focused"),"function"==typeof h.options.onBlur&&h.options.onBlur(c),c=null)},n=function(t){t&&t.preventDefault&&t.preventDefault(),u(),p&&p.parentNode&&p.parentNode.removeChild(p)},i=function(){l(),o=setTimeout(n,+(h.options.hideDelay||0))},d=function t(e){"mouseleave"===e.type&&(e.target&&C(e.target,h.options.item||".info-item"))!==c||(y(document.body,e.type,t,{capture:!0,passive:!0}),i())},a=function(t){var e=t.target&&C(t.target,h.options.item||".info-item");e&&E(h.options.content)&&(h.show(e,t),"click"!==h.options.trigger&&b(document.body,"touchstart"===t.type?"touchend":"mouseleave",d,{capture:!0,passive:!0}))},r=function(t,e,o){var n,i,s,c,r,u,l,a;switch(E(e)&&(e=e(t,h)),E(o)&&(o=o(t,h)),p.style.position="absolute",v(p,"below"),v(p,"left"),v(p,"right"),n=w(document.body),i=w(t),s=w(p),u=window.innerWidth||document.documentElement.clientWidth,l=window.innerHeight||document.documentElement.clientHeight,a=document.body.scrollLeft||0,t=document.body.scrollTop||0,(e||"center").toLowerCase()){case"left":c=i.left,g(p,"left"),c<0?i.right-s.width>c&&(c=i.right-s.width,v(p,"left"),g(p,"right")):c+s.width>u&&i.rightc&&(c=i.left,v(p,"right"),g(p,"left")):i.right>u&&i.left+s.widthu&&(c=i.right-s.width,g(p,"right"))}switch((o||"top").toLowerCase()){case"center":(r=i.top+i.height/2-s.height)<0&&(-r<=t?(document.body.scrollTop+=r,t=document.body.scrollTop,r=0):(r=i.top+i.height/2,g(p,"below")));break;case"bottom":r=i.bottom,g(p,"below"),r+s.height>l&&s.height-i.topr&&(r=i.bottom,g(p,"below")))}p.style.left=String(c+a-n.left)+"px",p.style.top=String(r+t-n.top)+"px"},h.options=t||{},h.dispose=function(){l(),n(),"click"===h.options.trigger?(e&&y(e,"click",n,{capture:!0,passive:!1}),y(document.body,"click",a,{capture:!0,passive:!1})):(p&&y(p,"mouseenter",f,{capture:!0,passive:!0}),p&&y(p,"touchstart",l,{capture:!0,passive:!0}),y(document.body,"mouseenter",a,{capture:!0,passive:!1}),y(document.body,"touchstart",a,{capture:!0,passive:!1}))},h.hide=function(){l(),n()},h.show=function(o,t){var n,i,e;o&&E(h.options.content)&&(i=0,null!=(e=h.options.content(o,h))&&!1!==e&&(e instanceof window.Node?(s.textContent="",s.appendChild(e)):s.innerHTML=m(String(e)),t&&t.preventDefault&&t.preventDefault(),l(),u(),g(c=o,h.options.focusedClass||"focused"),document.body.appendChild(p),(n=p.getElementsByTagName("img"))&&n.length&&[].forEach.call(n,function(e){var t;!e.complete&&(e.src&&e.src.length||e.currentSrc&&e.currentSrc.length)?(b(e,"error",t=function t(){y(e,"error",t),y(e,"load",t),++i,n.length===i&&o===c&&p.parentNode&&p===function(t,e){for(;t;){if(t===e)return e;t=t.parentNode}}(e,p)&&r(o,h.options.atItemX,h.options.atItemY)}),b(e,"load",t)):++i}),r(o,h.options.atItemX,h.options.atItemY)))},p||(g(p=document.createElement("div"),"info-popup"),h.options.infoClass&&g(p,h.options.infoClass),"click"===h.options.trigger?(p.appendChild(document.createElement("div")),g(p.firstChild,"header"),p.firstChild.appendChild(e=document.createElement("button")),g(e,"close"),e.setAttribute("title",h.options.closeMsg||"Close Popup"),b(e,"click",n,{capture:!0,passive:!1})):e=null,p.appendChild(s=document.createElement("div")),g(s,"content"),"click"===h.options.trigger?b(document.body,"click",a,{capture:!0,passive:!1}):(b(p,"mouseenter",f=function(t){l(),b(p,"mouseleave",function t(e){y(p,"mouseleave",t,{capture:!0,passive:!0}),i()},{capture:!0,passive:!0})},{capture:!0,passive:!0}),b(p,"touchstart",l,{capture:!0,passive:!0}),b(document.body,"mouseenter",a,{capture:!0,passive:!1}),b(document.body,"touchstart",a,{capture:!0,passive:!1})))}return L.prototype={constructor:L,options:null,dispose:null,show:null,hide:null},L.VERSION="1.0.1",L}); \ No newline at end of file diff --git a/test/demo.html b/test/demo.html index c0a3bd4..ac3e238 100644 --- a/test/demo.html +++ b/test/demo.html @@ -438,7 +438,7 @@

Interactive Map of Areas of Greece w/ InfoPopup v.