1+ /**
2+ * jQuery iframe click tracking plugin
3+ *
4+ * @author Vincent Paré (www.finalclap.com)
5+ * @copyright © 2013-2015 Vincent Paré
6+ * @license http://opensource.org/licenses/Apache-2.0
7+ * @version 1.1.0
8+ */
9+ ( function ( $ ) {
10+ // Tracking handler manager
11+ $ . fn . iframeTracker = function ( handler ) {
12+ var target = this . get ( ) ;
13+ if ( handler === null || handler === false ) {
14+ $ . iframeTracker . untrack ( target ) ;
15+ } else if ( typeof handler == "object" ) {
16+ $ . iframeTracker . track ( target , handler ) ;
17+ } else {
18+ throw new Error ( "Wrong handler type (must be an object, or null|false to untrack)" ) ;
19+ }
20+ } ;
21+
22+ // Iframe tracker common object
23+ $ . iframeTracker = {
24+ // State
25+ focusRetriever : null , // Element used for restoring focus on window (element)
26+ focusRetrieved : false , // Says if the focus was retrived on the current page (bool)
27+ handlersList : [ ] , // Store a list of every trakers (created by calling $(selector).iframeTracker...)
28+ isIE8AndOlder : false , // true for Internet Explorer 8 and older
29+
30+ // Init (called once on document ready)
31+ init : function ( ) {
32+ // Determine browser version (IE8-) ($.browser.msie is deprecated since jQuery 1.9)
33+ try {
34+ if ( $ . browser . msie == true && $ . browser . version < 9 ) {
35+ this . isIE8AndOlder = true ;
36+ }
37+ } catch ( ex ) {
38+ try {
39+ var matches = navigator . userAgent . match ( / ( m s i e ) ( [ \w . ] + ) / i) ;
40+ if ( matches [ 2 ] < 9 ) {
41+ this . isIE8AndOlder = true ;
42+ }
43+ } catch ( ex2 ) { }
44+ }
45+
46+ // Listening window blur
47+ $ ( window ) . focus ( ) ;
48+ $ ( window ) . blur ( function ( e ) {
49+ $ . iframeTracker . windowLoseFocus ( e ) ;
50+ } ) ;
51+
52+ // Focus retriever (get the focus back to the page, on mouse move)
53+ $ ( 'body' ) . append ( '<div style="position:fixed; top:0; left:0; overflow:hidden;"><input style="position:absolute; left:-300px;" type="text" value="" id="focus_retriever" readonly="true" /></div>' ) ;
54+ this . focusRetriever = $ ( '#focus_retriever' ) ;
55+ this . focusRetrieved = false ;
56+ $ ( document ) . mousemove ( function ( e ) {
57+ if ( document . activeElement && document . activeElement . tagName == 'IFRAME' ) {
58+ $ . iframeTracker . focusRetriever . focus ( ) ;
59+ $ . iframeTracker . focusRetrieved = true ;
60+ }
61+ } ) ;
62+
63+ // Special processing to make it work with my old friend IE8 (and older) ;)
64+ if ( this . isIE8AndOlder ) {
65+ // Blur doesn't works correctly on IE8-, so we need to trigger it manually
66+ this . focusRetriever . blur ( function ( e ) {
67+ e . stopPropagation ( ) ;
68+ e . preventDefault ( ) ;
69+ $ . iframeTracker . windowLoseFocus ( e ) ;
70+ } ) ;
71+
72+ // Keep focus on window (fix bug IE8-, focusable elements)
73+ $ ( 'body' ) . click ( function ( e ) { $ ( window ) . focus ( ) ; } ) ;
74+ $ ( 'form' ) . click ( function ( e ) { e . stopPropagation ( ) ; } ) ;
75+
76+ // Same thing for "post-DOMready" created forms (issue #6)
77+ try {
78+ $ ( 'body' ) . on ( 'click' , 'form' , function ( e ) { e . stopPropagation ( ) ; } ) ;
79+ } catch ( ex ) {
80+ console . log ( "[iframeTracker] Please update jQuery to 1.7 or newer. (exception: " + ex . message + ")" ) ;
81+ }
82+ }
83+ } ,
84+
85+
86+ // Add tracker to target using handler (bind boundary listener + register handler)
87+ // target: Array of target elements (native DOM elements)
88+ // handler: User handler object
89+ track : function ( target , handler ) {
90+ // Adding target elements references into handler
91+ handler . target = target ;
92+
93+ // Storing the new handler into handler list
94+ $ . iframeTracker . handlersList . push ( handler ) ;
95+
96+ // Binding boundary listener
97+ $ ( target )
98+ . bind ( 'mouseover' , { handler : handler } , $ . iframeTracker . mouseoverListener )
99+ . bind ( 'mouseout' , { handler : handler } , $ . iframeTracker . mouseoutListener ) ;
100+ } ,
101+
102+ // Remove tracking on target elements
103+ // target: Array of target elements (native DOM elements)
104+ untrack : function ( target ) {
105+ if ( typeof Array . prototype . filter != "function" ) {
106+ console . log ( "Your browser doesn't support Array filter, untrack disabled" ) ;
107+ return ;
108+ }
109+
110+ // Unbinding boundary listener
111+ $ ( target ) . each ( function ( index ) {
112+ $ ( this )
113+ . unbind ( 'mouseover' , $ . iframeTracker . mouseoverListener )
114+ . unbind ( 'mouseout' , $ . iframeTracker . mouseoutListener ) ;
115+ } ) ;
116+
117+ // Handler garbage collector
118+ var nullFilter = function ( value ) {
119+ return value === null ? false : true ;
120+ } ;
121+ for ( var i in this . handlersList ) {
122+ // Prune target
123+ for ( var j in this . handlersList [ i ] . target ) {
124+ if ( $ . inArray ( this . handlersList [ i ] . target [ j ] , target ) !== - 1 ) {
125+ this . handlersList [ i ] . target [ j ] = null ;
126+ }
127+ }
128+ this . handlersList [ i ] . target = this . handlersList [ i ] . target . filter ( nullFilter ) ;
129+
130+ // Delete handler if unused
131+ if ( this . handlersList [ i ] . target . length == 0 ) {
132+ this . handlersList [ i ] = null ;
133+ }
134+ }
135+ this . handlersList = this . handlersList . filter ( nullFilter ) ;
136+ } ,
137+
138+ // Target mouseover event listener
139+ mouseoverListener : function ( e ) {
140+ e . data . handler . over = true ;
141+ try { e . data . handler . overCallback ( this ) ; } catch ( ex ) { }
142+ } ,
143+
144+ // Target mouseout event listener
145+ mouseoutListener : function ( e ) {
146+ e . data . handler . over = false ;
147+ $ . iframeTracker . focusRetriever . focus ( ) ;
148+ try { e . data . handler . outCallback ( this ) ; } catch ( ex ) { }
149+ } ,
150+
151+ // Calls blurCallback for every handler with over=true on window blur
152+ windowLoseFocus : function ( event ) {
153+ for ( var i in this . handlersList ) {
154+ if ( this . handlersList [ i ] . over == true ) {
155+ try { this . handlersList [ i ] . blurCallback ( ) ; } catch ( ex ) { }
156+ }
157+ }
158+ }
159+ } ;
160+
161+ // Init the iframeTracker on document ready
162+ $ ( document ) . ready ( function ( ) {
163+ $ . iframeTracker . init ( ) ;
164+ } ) ;
165+ } ) ( jQuery ) ;
0 commit comments