├── LICENSE ├── README.md └── src └── dialog_trigger.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Shahzad Malik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DialogTriggerJS 2 | =============== 3 | 4 | Some simple Javascript code using jQuery that lets a dialog be triggered based on some user behavior such as a timeout, by scrolling by some amount, or based on exit intent. 5 | 6 | This is useful if you want to pop-up something like a newsletter sign-up form in a more intelligent way instead of just doing it instantly. 7 | 8 | You can even chain events together, such as requiring the user to scroll down by some amount like 25% of the page, then back up by 10%, etc. 9 | 10 | ### Basic Usage: 11 | 12 | var dt = new DialogTrigger(callback, options); 13 | 14 | - "callback" is the Javascript function that should be called when the trigger behavior is met 15 | - "options" consists of a "trigger" and any additional parameters as follows: 16 | * trigger: 'exitIntent' 17 | - Call 'callback' when a user intends to exit (such as moving cursor off page or coming back to the top) 18 | - This won't work on mobile devices since mouse events aren't generated, so you should use different triggers in such instances. 19 | - eg. `{ trigger: 'exitIntent' }` 20 | 21 | * trigger: 'target' 22 | - Call 'callback' when a user reaches a particular target element 23 | - Use 'target' to set the name of the element, such as '#mytarget' (eg. `{ trigger: 'target', target: '#mytarget' }`) 24 | 25 | * trigger: 'scrollDown' 26 | - Call 'callback' when a user scrolls down by a certain percent of the page from when the object is instantiated 27 | - Use 'percentDown' to set the percentage 0-100 (eg. `{ trigger: 'scrollDown', percentDown: 50 }`) 28 | - Default percentDown is 50% 29 | 30 | * trigger: 'scrollUp' 31 | - Call 'callback' when a user scrolls up by a certain percent from when the object is instantiated 32 | - Use 'percentUp' to set the percentage 0-100 (eg. `{ trigger: 'scrollUp', percentUp: 10 }`) 33 | - Default percentUp is 10% 34 | 35 | * trigger: 'timeout' 36 | - Call 'callback' after a certain number of milliseconds have elapsed (set 'timeout' to the desired milliseconds) 37 | - Use 'timeout' to set the desired milliseconds (eg. `{ trigger: 'timeout', timeout: 5000 }`) 38 | - Default timeout is 0 milliseconds (instant trigger) 39 | 40 | ### Examples: 41 | function testPopup() { 42 | alert('Hello there!'); 43 | } 44 | 45 | // A trigger based on a timeout of 5 seconds 46 | var dtTimeout = new DialogTrigger(testPopup, { trigger: 'timeout', timeout: 5000 }); 47 | 48 | // A trigger based on the user scrolling down to a target element on the page named '#mytarget' 49 | var dtElement = new DialogTrigger(testPopup, { trigger: 'target', target: '#mytarget' }); 50 | 51 | // A trigger based on the user scrolling down at least 50% of the page 52 | var dtScrollDown = new DialogTrigger(testPopup, { trigger: 'scrollDown', percentDown: 50 }); 53 | 54 | // A trigger based on "exit intent" when the cursor is detected to go above the top of the browser window (useful in desktop scenarios) 55 | var dtExit = new DialogTrigger(testPopup, { trigger: 'exitIntent' }); 56 | 57 | // Triggers can also be chained for a sequence of behaviors (such as scroll down by 50%, then up by 10%): 58 | var dtPercentDown = new DialogTrigger(function() { 59 | var dtPercentUp = new DialogTrigger(testPopup, { trigger: 'scrollUp', percentUp: 10 }); 60 | }, { trigger: 'scrollDown', percentDown: 50 }); 61 | 62 | ### License 63 | The MIT License (MIT) 64 | -------------------------------------------------------------------------------- /src/dialog_trigger.js: -------------------------------------------------------------------------------- 1 | // DialogTriggerJS 2 | // Copyright (c) 2016-2017 Shahzad Malik 3 | // MIT License 4 | // 5 | // Triggers a callback to pop up a dialog (or do anything else) with the specified trigger options. 6 | // 7 | // "trigger" can be one of the following: 8 | // 'exitIntent': Call 'callback' when a user intends to exit (such as moving cursor off page or coming back to the top) 9 | // 'target': Call 'callback' when a user reaches a particular target element (set 'target' to the name of the element, such as '#mytarget') 10 | // 'scrollDown': Call 'callback' when a user scrolls down by a certain percent from when the object is instantiated (set 'percentDown' to the percentage 0-100) 11 | // 'scrollUp': Call 'callback' when a user scrolls up by a certain percent from when the object is instantiated (set 'percentUp' to the percentage 0-100) 12 | // 'timeout': Call 'callback' after a certain number of milliseconds have elapsed (set 'timeout' to the desired milliseconds) 13 | // 14 | // Examples: 15 | // Setting up individual triggers: 16 | // var dt = new DialogTrigger(triggerNagPopup, { trigger: 'timeout', timeout: 5000 }); 17 | // var dt = new DialogTrigger(triggerNagPopup, { trigger: 'target', target: '#all' }); 18 | // var dt = new DialogTrigger(triggerNagPopup, { trigger: 'scrollDown', percentDown: 50 }); 19 | // var dt = new DialogTrigger(triggerNagPopup, { trigger: 'exitIntent' }); 20 | // 21 | // Triggers can also be chained for a sequence of behaviors (such as scroll down by 50%, then exit): 22 | // var dtPercent = new DialogTrigger(function() { 23 | // var dtExit = new DialogTrigger(triggerNagPopup, { trigger: 'exitIntent' }); 24 | // }, { trigger: 'scrollDown', percentDown: 50 }); 25 | function DialogTrigger(callback, options) { 26 | // Becomes this.options 27 | var defaults = { 28 | trigger : 'timeout', 29 | target : '', 30 | timeout : 0, 31 | percentDown : 50, // Used for 'percent' to define a down scroll threshold of significance (based on page height) 32 | percentUp : 10, // Used for 'percent' to define a threshold of upward scroll after down threshold is reached 33 | scrollInterval: 1000 // Frequency (in ms) to check for scroll changes (to avoid bogging the UI) 34 | } 35 | 36 | this.complete = false; // Let's us know if the popup has been triggered 37 | 38 | this.callback = callback; 39 | this.timer = null; 40 | this.interval = null; 41 | 42 | this.options = jQuery.extend(defaults, options); 43 | 44 | this.init = function() { 45 | if(this.options.trigger == 'exitIntent' || this.options.trigger == 'exit_intent') { 46 | var parentThis = this; 47 | 48 | jQuery(document).on('mouseleave', function(e) { 49 | //console.log(e.clientX + ',' + e.clientY); // IE returns negative values on all sides 50 | 51 | if(!parentThis.complete && e.clientY < 0) { // Check if the cursor went above the top of the browser window 52 | parentThis.callback(); 53 | parentThis.complete = true; 54 | jQuery(document).off('mouseleave'); 55 | } 56 | }); 57 | 58 | } else if(this.options.trigger == 'target') { 59 | if(this.options.target !== '') { 60 | // Make sure the target exists 61 | if(jQuery(this.options.target).length == 0) { 62 | this.complete = true; 63 | } else { 64 | var targetScroll = jQuery(this.options.target).offset().top; 65 | 66 | var parentThis = this; 67 | 68 | // Only check the scroll position every few seconds, to avoid bogging the UI 69 | this.interval = setInterval(function() { 70 | if(jQuery(window).scrollTop() >= targetScroll) { 71 | clearInterval(parentThis.interval); 72 | parentThis.interval = null; 73 | 74 | if(!parentThis.complete) { 75 | parentThis.callback(); 76 | parentThis.complete = true; 77 | } 78 | } 79 | }, this.options.scrollInterval); 80 | } 81 | } 82 | 83 | } else if(this.options.trigger == 'scrollDown') { 84 | // Let the user scroll down by some significant amount 85 | var scrollStart = jQuery(window).scrollTop(); 86 | var pageHeight = jQuery(document).height(); 87 | 88 | var parentThis = this; 89 | 90 | if(pageHeight > 0) { 91 | // Only check the scroll position every few seconds, to avoid bogging the UI 92 | this.interval = setInterval(function() { 93 | var scrollAmount = jQuery(window).scrollTop() - scrollStart; 94 | if(scrollAmount < 0) { 95 | scrollAmount = 0; 96 | scrollStart = jQuery(window).scrollTop(); 97 | } 98 | var downScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight); 99 | 100 | if(downScrollPercent > parseFloat(parentThis.options.percentDown) / 100) { 101 | clearInterval(parentThis.interval); 102 | parentThis.interval = null; 103 | 104 | if(!parentThis.complete) { 105 | parentThis.callback(); 106 | parentThis.complete = true; 107 | } 108 | } 109 | 110 | }, this.options.scrollInterval); 111 | } 112 | 113 | } else if(this.options.trigger == 'scrollUp') { 114 | // Let the user scroll down by some significant amount 115 | var scrollStart = jQuery(window).scrollTop(); 116 | var pageHeight = jQuery(document).height(); 117 | 118 | var parentThis = this; 119 | 120 | if(pageHeight > 0) { 121 | // Only check the scroll position every few seconds, to avoid bogging the UI 122 | this.interval = setInterval(function() { 123 | var scrollAmount = scrollStart - jQuery(window).scrollTop(); 124 | if(scrollAmount < 0) { 125 | scrollAmount = 0; 126 | scrollStart = jQuery(window).scrollTop(); 127 | } 128 | var upScrollPercent = parseFloat(scrollAmount) / parseFloat(pageHeight); 129 | 130 | if(upScrollPercent > parseFloat(parentThis.options.percentUp) / 100) { 131 | clearInterval(parentThis.interval); 132 | parentThis.interval = null; 133 | 134 | if(!parentThis.complete) { 135 | parentThis.callback(); 136 | parentThis.complete = true; 137 | } 138 | } 139 | 140 | }, this.options.scrollInterval); 141 | } 142 | 143 | } else if(this.options.trigger == 'timeout') { 144 | this.timer = setTimeout(this.callback, this.options.timeout); 145 | } 146 | 147 | }; 148 | 149 | this.cancel = function() { 150 | if(this.timer !== null) { 151 | clearTimeout(this.timer); 152 | this.timer = null; 153 | } 154 | 155 | if(this.interval !== null) { 156 | clearInterval(this.interval); 157 | this.interval = null; 158 | } 159 | 160 | this.complete = true; 161 | } 162 | 163 | this.init(); 164 | } 165 | --------------------------------------------------------------------------------