2 /* ***************************************************************************
3 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 * ***************************************************************************
24 * Author: Sanghee Lee <sang-hee.lee@samsung.com>
28 * Splitview is a widget which can show different HTML contents at the same time on each divided pane.
29 * A user can place Splitview controls on JQuery Mobile's Content area and arrange two panes on the widget.
30 * And HTML fragments or another Splitview also can be placed on the pane.
31 * The number of panes inside of Splitview is restricted as two.
32 * If a user define only one pane in Splitview, a empty pane will be added automatically,
33 * on the other hand, if 3 or more panes are defined in Splitview, the panes after two will be ignored and removed from the DOM tree.
34 * The HTML fragments of a pane should be composed of elements describing a part of Web page (e.g. <div>...</div>).
35 * Also widgets can be included in the HTML fragments.
39 * data-fixed : The resizing mode of panes - fixed and flexible mode.
40 * If the value is true, the panes' sizes will be fixed, or if not, it will be flexible. (Default : false)
41 * data-divider-vertical : The direction of dividers.
42 * If the value is true, the panes will be placed in horizontal direction,
43 * or if not, it will be placed in vertical direction. (Default : "true")
44 * data-ratio : The ratio of two panes' widths or heights. (Default : [ 1/2, 1/2 ]
48 * pane ( id [ , element ] )
49 * : This method replaces child contents of a pane indicated by id attribute with contents of inputted element.
50 * If second argument is not specified, it will act as a getter method.
51 * The string of id has to be started with "#" which means "id" of CSS selectors.
53 * : This method maximizes a pane's size indicated by id.
54 * The string of id has to be started with "#" which means "id" of CSS selectors.
56 * : This method restores all panes' sizes to the ratio prior to maximization.
60 * <div data-role="splitview" data-fixed="false" data-divider-vertical="true" data-ratio="0.5, 0.5">
61 * <div class="ui-pane">pane0</div>
62 * <div class="ui-pane">pane1</div>
70 Splitview widget enables a user to place and arrange several panes. Each divided pane can show repective HTML contents.
72 To add a Splitview widget to the application, use the following code:
74 <div data-role="splitview" data-fixed="false" data-divider-vertical="true" data-ratio="0.5, 0.5">
75 <div class="ui-pane">pane0</div>
76 <div class="ui-pane">pane1</div>
81 @property {Boolean} data-fixed
82 The resizing mode of panes - fixed and flexible mode.
86 @property {Boolean} data-divider-vertical
87 The direction of dividers - horizontal or vertical.
91 @property {Array} data-ratio
92 The ratio of two panes' widths or heights.
97 This method replaces child contents of a pane indicated by id attribute with contents of inputted element.
98 If second argument is not specified, it will act as a getter method.
100 <div data-role="splitview">
101 <div class="ui-pane" id="pane0">pane0</div>
102 <div class="ui-pane" id="pane1">pane1</div>
104 $(".selector").splitview("pane", id, element);
109 This method maximizes a pane's size indicated by id.
111 <div data-role="splitview">
112 <div class="ui-pane" id="pane0">pane0</div>
113 <div class="ui-pane" id="pane1">pane1</div>
115 $(".selector").splitview("maximize", id);
120 This method restores all panes' sizes to the ratio prior to maximization.
122 <div data-role="splitview">
123 <div class="ui-pane" id="pane0">pane0</div>
124 <div class="ui-pane" id="pane1">pane1</div>
126 $(".selector").splitview("restore");
129 ( function ( $, window, document, undefined ) {
130 $.widget( "tizen.splitview", $.mobile.widget, {
133 dividerVertical : true,
135 initSelector : ":jqmData(role='splitview')"
138 _create : function () {
142 $panes = $el.children( ".ui-pane" ),
143 panesLength = $panes.length,
146 ratioAttr = this.element.attr( "data-ratio" ),
147 containerSize = [ 0, 0 ],
151 if ( panesLength !== 2 ) {
152 if ( panesLength < 2 ) {
153 for ( i = panesLength ; i < 2 ; ++i ) {
154 self._addEmptyPanes();
157 $panes.slice( 2 ).remove();
160 $panes = $el.children( ".ui-pane" );
161 panesLength = $panes.length;
164 spliters[ 0 ] = $( "<a href='#' class='ui-spliter' aria-label='Drag scroll, double tap and move to adjust split area'></a>" ).insertAfter( $panes[ 0 ] );
165 spliterBars[ 0 ] = $( "<div class='ui-spliter-bar'></div>" ).appendTo( spliters[ 0 ] );
166 $( "<div class='ui-spliter-handle'></div>" ).appendTo( spliterBars[ 0 ] );
172 spliterBars : spliterBars,
174 containerSize : containerSize,
180 self._bindTouchEvents();
181 self._convertRatio( ratioAttr, $panes.length );
183 $el.addClass( "ui-splitview ui-direction-" + self._direction( opt.dividerVertical ) );
187 $( window ).unbind( ".splitview" )
188 .bind( "pagechange.splitview resize.splitview", function ( event ) {
189 $( ".ui-page-active .ui-splitview" ).each( function () {
190 $( this ).data( "splitview" )._refresh();
195 _addEmptyPanes : function () {
199 $panes = $el.children( ".ui-pane" ),
200 scrollAttribute = ( $.support.scrollview ) ? "data-scroll='y'" : "",
201 pane = $( "<div class='ui-pane' " + scrollAttribute + "></div>" );
203 if ( scrollAttribute.length ) {
204 pane.scrollview( { direction: "y" } );
207 if ( !$panes.length ) {
210 $panes.last().after( pane );
214 _direction : function ( isHorizontal ) {
215 return isHorizontal ? "horizontal" : "vertical";
218 _isStyleSpecified : function ( cssString ) {
219 return ( typeof cssString !== "undefined" && cssString.length );
222 _getContainerSize : function ( widthString, heightString ) {
225 widthSpecified = self._isStyleSpecified( widthString ),
226 heightSpecified = self._isStyleSpecified( heightString );
228 self.containerSize[ 0 ] = ( widthSpecified ) ? $el.outerWidth( true ) : self._parentWidth();
229 self.containerSize[ 1 ] = ( heightSpecified ) ? $el.outerHeight( true ) : self._parentHeight();
231 if ( !self.containerSize[ 0 ] || !self.containerSize[ 1 ] ) {
238 _parentWidth : function () {
239 var $parent = this.element.parent();
241 if ( !$parent && typeof $parent === "undefined" && !$parent.length ) {
242 return $( window ).width();
245 return $parent.width();
248 _parentHeight : function () {
249 var $parent = this.element.parent(),
251 heightSpecified = false,
254 while ( $parent && typeof $parent !== "undefined" && $parent.length ) {
255 if ( typeof $parent[ 0 ].style !== "undefined" ) {
256 heightString = $parent[ 0 ].style.height;
257 heightSpecified = ( typeof heightString !== "undefined" && heightString.length );
258 if ( heightSpecified ) {
259 parentHeight = $parent.height();
264 $parent = $parent.parent();
267 if ( !heightSpecified ) {
268 parentHeight = $(window).height();
274 _convertRatio : function ( ratioParam, panesLength ) {
278 type = typeof ratioParam,
282 for ( i = 0; i < panesLength; ++i ) {
289 ratio[ 0 ] = ratioParam;
294 ratioArray = ratioParam.split( "," );
295 loop = Math.min( ratioArray.length, panesLength );
296 for ( i = 0; i < loop; ++i ) {
297 ratio[ i ] = parseFloat( ratioArray[ i ] );
302 if ( !$.isArray( ratioParam ) ) {
306 loop = Math.min( ratioParam.length, panesLength );
307 for ( i = 0; i < loop; ++i ) {
308 type = typeof ratioParam[ i ];
309 ratio[ i ] = ( type === "string" ) ? parseFloat( ratioParam[ i ] ) :
310 ( type === "number" ) ? ratioParam[ i ] : 0;
315 self.options.ratio = ratio;
316 self._adjustRatio( panesLength );
319 _adjustRatio : function ( panesLength ) {
321 ratio = self.options.ratio,
329 if ( !panesLength ) {
330 self.options.ratio = [];
340 value = remain / panesLength;
345 remain = Math.max( 0, remain - value );
348 subValue = Math.max( subRemain, ratio[ i ] * -1 );
349 ratio[ i ] = Math.max( 0, ratio[ i ] + subValue );
350 remain = Math.min( 0, remain - subValue );
351 subRemain -= subValue;
357 ratio[ ratio.length - 1 ] += remain;
359 for ( i = ratio.length - 1; i >= 0; --i ) {
360 subValue = Math.max( remain, ratio[ i ] * -1 );
361 ratio[ i ] = Math.max( 0, ratio[ i ] + subValue );
362 remain = Math.min( 0, remain - subValue );
370 self.options.ratio = ratio;
374 _setOption : function ( key, value ) {
376 orgValue = self.options[ key ];
378 if ( orgValue === value ) {
382 $.Widget.prototype._setOption.apply( this, arguments );
386 self._fixed( value );
389 case "dividerVertical":
390 self._dividerVertical( value );
394 self._ratio( value );
399 _subtractDiffWidth : function ( width, diff ) {
402 if ( width <= self.minPaneWidth ) {
410 if ( width >= self.minPaneWidth ) {
418 width: self.minPaneWidth,
419 diff: width - self.minPaneWidth
423 _initRatio : function ( fromFirstPane, panes, isHorizontal, availableWidth ) {
428 panesLength = panes.length,
432 panes.each( function ( i ) {
433 var pane = $( this );
434 widths.push( isHorizontal ? pane.width() : pane.height() );
438 diff = availableWidth - sum;
444 widths[ fromFirstPane ? 0 : panesLength - 1 ] += diff;
446 if ( fromFirstPane ) {
447 for ( i = 0; i < panesLength; ++i ) {
448 ret = self._subtractDiffWidth( widths[ i ], diff );
449 widths[ i ] = ret.width;
456 for ( i = panesLength - 1; i >= 0; --i ) {
457 diff = self._subtractDiffWidth( widths[ i ], diff );
458 widths[ i ] = ret.width;
468 for ( i in widths ) {
472 for ( i in self.options.ratio ) {
473 self.options.ratio[ i ] = widths[ i ] / sum;
479 _horizontalBoundary : function () {
483 return $el.outerWidth( true ) - $el.width();
486 _verticalBoundary : function () {
490 return $el.outerHeight( true ) - $el.height();
493 _boundary : function ( type ) {
496 computedStyle = window.getComputedStyle( $el[ 0 ], null ),
497 margin = parseFloat( computedStyle[ "margin" + type ] ),
498 border = parseFloat( computedStyle[ "border" + type + "Width" ] ),
499 padding = parseFloat( computedStyle[ "padding" + type ] );
508 _layout : function ( initRatio, fromFirstPane ) {
512 isHorizontal = opt.dividerVertical,
514 spliters = self.spliters,
515 spliterBars = self.spliterBars,
516 spliterBar = self.spliterBars.length ? $( spliterBars[ 0 ] ) : null,
517 spliterWidth = !spliterBar ? 0 :
518 isHorizontal ? spliterBar.outerWidth() :
519 spliterBar.outerHeight(),
520 spliterBarMargin = !spliterBar ? 0 :
522 spliterBar.outerWidth( true ) - spliterBar.outerWidth() :
523 spliterBar.outerHeight( true ) - spliterBar.outerHeight(),
524 panesLength = $panes.length,
525 currentAvailable = 0,
526 spliterSize = spliterWidth * ( panesLength - 1 ),
527 parentWidth = self.containerSize[ 0 ],
528 parentHeight = self.containerSize[ 1 ],
529 width = parentWidth - self._horizontalBoundary(),
530 height = parentHeight - self._verticalBoundary(),
531 innerSize = isHorizontal ? height : width,
532 availableWidth = isHorizontal ? width - spliterSize :
533 height - spliterSize,
534 initializedWidth = [],
536 childSplitview = null;
538 initRatio = !!initRatio;
539 fromFirstPane = !!fromFirstPane;
543 "min-height" : height
547 initializedWidth = self._initRatio( fromFirstPane, $panes, isHorizontal, availableWidth );
550 currentAvailable = availableWidth;
551 $panes.each( function ( i ) {
552 var $pane = $( this ),
553 paneWidth = initRatio ? initializedWidth[ i ] :
554 Math.floor( availableWidth * self.options.ratio[i] ),
555 prevPane = ( ( i ) ? $panes.eq( i - 1 ) : null ),
561 currentAvailable -= paneWidth;
562 if ( i === ( panesLength - 1 ) ) {
563 paneWidth = Math.max( Math.min( paneWidth, self.minPaneWidth ), paneWidth + currentAvailable );
566 widthSum += paneWidth;
569 boundary = self._boundary( isHorizontal ? "Left" : "Top" );
570 posValue = boundary.padding;
572 posValue = parseInt( prevPane.css( isHorizontal ? "left" : "top" ), 10 );
573 posValue += isHorizontal ? prevPane.width() : prevPane.height();
574 posValue += spliterWidth;
577 widthValue = isHorizontal ? paneWidth : innerSize;
578 heightValue = isHorizontal ? innerSize : paneWidth;
581 "width" : widthValue ,
582 "height" : heightValue
585 $pane.css( ( isHorizontal ? "left" : "top" ), posValue );
588 $panes.each( function ( i ) {
589 var $pane = $( this ),
590 paneWidth = isHorizontal ? $pane.width() : $pane.height();
592 self.options.ratio[ i ] = paneWidth / widthSum;
595 $.each( spliters, function ( i ) {
596 var spliter = $( this ),
597 prevPane = $panes.eq( i ),
598 bar = spliter.children( ".ui-spliter-bar" ),
599 handle = bar.children( ".ui-spliter-handle" ),
602 if ( isHorizontal ) {
603 posValue = parseInt( prevPane.css( "left" ), 10 ) + prevPane.width() - spliterBarMargin;
604 spliter.outerHeight( innerSize ).css( "left", posValue );
606 posValue = parseInt( prevPane.css( "top" ), 10 ) + prevPane.height() - spliterBarMargin;
607 spliter.outerWidth( innerSize ).css( "top", posValue );
611 bar[ isHorizontal ? "outerHeight" : "outerWidth" ]( innerSize );
613 if ( handle.length ) {
614 handle.css( isHorizontal ? "top" : "left", ( innerSize - spliterWidth ) / 2 );
618 childSplitview = $el.find( ".ui-splitview:first" );
619 if ( !childSplitview.length ) {
623 childSplitview = childSplitview.data( "splitview" );
624 if ( childSplitview ) {
625 childSplitview._refresh();
629 _bindTouchEvents : function () {
633 spliters = self.spliters;
635 $.each( spliters, function ( i ) {
636 var spliter = $( this );
637 self._bindSpliterTouchEvents.call( self, spliter );
641 _bindSpliterTouchEvents : function ( spliter ) {
645 touchStartEvt = ( $.support.touch ? "touchstart" : "mousedown" ),
646 touchMoveEvt = ( $.support.touch ? "touchmove" : "mousemove" ) + ".splitview",
647 touchEndEvt = ( $.support.touch ? "touchend" : "mouseup" ) + ".splitview";
649 spliter.bind( touchStartEvt, { e : spliter }, function ( event ) {
650 if ( self.options.fixed ) {
654 var realEvent = $.support.touch ? event.originalEvent.changedTouches[0] : event,
655 targetSpliter = event.data.e,
656 prevPane = targetSpliter.prev(),
657 nextPane = targetSpliter.next(),
658 splitviewInPrev = prevPane.find( ".ui-splitview:first" ),
659 splitviewInNext = nextPane.find( ".ui-splitview:first" ),
660 isHorizontal = opt.dividerVertical,
661 spliterWidth = isHorizontal ?
662 $( self.spliterBars[0] ).outerWidth() :
663 $( self.spliterBars[0] ).outerHeight();
665 self.moveTarget = targetSpliter;
667 spliterWidth : spliterWidth || 0,
670 splitviewInPrev : splitviewInPrev,
671 splitviewInNext : splitviewInNext,
672 prevPanePos : parseInt( prevPane.css( isHorizontal ? "left" : "top" ), 10 ) || 0,
673 prevPaneWidth : parseInt( prevPane.css( isHorizontal ? "width" : "height" ), 10 ) || 0,
674 nextPanePos : parseInt( nextPane.css( isHorizontal ? "left" : "top" ), 10 ) || 0,
675 nextPaneWidth : parseInt( nextPane.css( isHorizontal ? "width" : "height" ), 10 ) || 0,
676 targetPos : parseInt( targetSpliter.css( isHorizontal ? "left" : "top" ), 10 ) || 0,
677 pagePos : isHorizontal ? realEvent.pageX : realEvent.pageY
680 targetSpliter.addClass( "ui-spliter-active" );
682 $el.bind( touchMoveEvt, function ( event ) {
683 if ( !self.touchStatus ) {
686 event.stopPropagation();
687 self._drag( $.support.touch ? event.originalEvent.changedTouches[0] : event );
688 }).bind( touchEndEvt, function ( event ) {
689 event.stopPropagation();
690 self._stop( $.support.touch ? event.originalEvent.changedTouches[0] : event );
691 self.touchStatus = false;
692 $el.unbind( ".splitview" );
693 $( document ).unbind( ".splitview" );
696 $( document ).bind( touchMoveEvt + " " + touchEndEvt, function() {
697 $el.trigger( touchEndEvt );
700 event.preventDefault();
701 self.touchStatus = true;
705 _drag : function ( e ) {
706 if ( !this.moveData || typeof this.moveData === "undefined" ) {
713 isHorizontal = opt.dividerVertical,
714 moveData = self.moveData,
715 moveTarget = self.moveTarget,
716 prevPane = moveData.prevPane,
717 nextPane = moveData.nextPane,
718 splitviewInPrev = moveData.splitviewInPrev,
719 splitviewInNext = moveData.splitviewInNext,
720 spliterWidth = moveData.spliterWidth,
724 prevPaneWidth = null,
725 nextPaneWidth = null,
726 pagePos = isHorizontal ? e.pageX : e.pageY,
729 movement = pagePos - moveData.pagePos;
730 if ( movement > 0 ) {
731 movement = Math.min( Math.max( moveData.nextPaneWidth - self.minPaneWidth, 0 ), movement );
733 movement = Math.max( Math.max( moveData.prevPaneWidth - self.minPaneWidth, 0 ) * -1, movement );
736 nextPanePos = moveData.nextPanePos + movement;
737 prevPaneWidth = Math.max( moveData.prevPaneWidth + movement, 0 );
738 nextPaneWidth = Math.max( moveData.nextPaneWidth - movement, 0 );
739 targetPos = moveData.targetPos + movement;
741 moveTarget.css( isHorizontal ? { left : targetPos } : { top : targetPos } );
742 prevPane.css( isHorizontal ? { width : prevPaneWidth } : { height : prevPaneWidth } );
743 nextPane.css( isHorizontal ? { width : nextPaneWidth, left : nextPanePos } :
744 { height : nextPaneWidth, top : nextPanePos } );
746 if ( splitviewInPrev.length ) {
747 splitview = splitviewInPrev.data( "splitview" );
748 splitview._refresh( true, false );
751 if ( splitviewInNext.length ) {
752 splitview = splitviewInNext.data( "splitview" );
753 splitview._refresh( true, true );
757 _stop : function ( e ) {
758 if ( !this.moveData || !this.moveTarget ) {
766 panesLength = $panes.length,
767 isHorizontal = opt.dividerVertical,
768 moveData = self.moveData,
769 moveTarget = self.moveTarget,
770 prevPane = moveData.prevPane,
771 nextPane = moveData.nextPane,
772 splitviewInPrev = moveData.splitviewInPrev,
773 splitviewInNext = moveData.splitviewInNext,
774 spliterWidth = moveData.spliterWidth,
775 spliterSize = spliterWidth * ( panesLength - 1 ),
779 prevPaneWidth = null,
780 nextPaneWidth = null,
781 displayStyle = $el.css( "display" ),
782 parentWidth = self.containerSize[ 0 ],
783 parentHeight = self.containerSize[ 1 ],
784 width = parentWidth - self._horizontalBoundary(),
785 height = parentHeight - self._verticalBoundary(),
786 availableWidth = isHorizontal ?
787 ( width - spliterSize ) :
788 ( height - spliterSize ),
791 moveTarget.removeClass( "ui-spliter-active" );
794 $panes.each( function ( i ) {
795 var $pane = $( this ),
796 paneWidth = isHorizontal ? $pane.width() : $pane.height();
801 $panes.each( function ( i ) {
802 var $pane = $( this ),
803 paneWidth = isHorizontal ? $pane.width() : $pane.height();
805 self.options.ratio[ i ] = paneWidth / sum;
808 self.moveData = null;
811 _fixed : function ( isFix ) {
813 spliters = self.spliters;
815 $.each( spliters, function ( i ) {
816 var $spliter = $( this );
819 $spliter.addClass( "ui-fixed" );
821 $spliter.removeClass( "ui-fixed" );
828 _dividerVertical : function ( isDividerVertical ) {
831 isHorizontal = isDividerVertical,
837 $panes = $el.children( ".ui-pane" );
838 $spliters = $el.children( ".ui-spliter" );
839 $bar = $spliters.children( ".ui-spliter-bar" );
840 $handle = $bar.children( ".ui-spliter-handle" );
842 $el.removeClass( "ui-direction-vertical" );
843 $el.removeClass( "ui-direction-horizontal" );
844 $el.addClass( "ui-splitview ui-direction-" + self._direction( isHorizontal ) );
870 if ( self._getContainerSize( $el[ 0 ].style.width, $el[ 0 ].style.height ) ) {
875 _ratio : function ( ratioParam ) {
878 $panes = $el.children( ".ui-pane" ),
879 panesLength = $panes.length;
881 self._convertRatio( ratioParam, panesLength );
885 _refresh : function ( initRatio, fromFirstPane ) {
889 initRatio = !!initRatio;
890 fromFirstPane = !!fromFirstPane;
892 if ( self._getContainerSize( $el[ 0 ].style.width, $el[ 0 ].style.height ) ) {
893 self._layout( initRatio, fromFirstPane );
897 pane : function ( id, element ) {
898 if ( typeof id !== "string" ) {
904 $targetPane = $el.children( id ),
906 elementParent = null;
908 if ( !$targetPane.hasClass( "ui-pane" ) ) {
914 return $targetPane.contents();
918 if ( $targetPane.hasClass( "ui-scrollview-clip" ) ) {
919 $targetPane.scrollview( "scrollTo", 0, 0, 0 );
921 $targetView = $targetPane.children( ".ui-scrollview-view" );
922 if ( !$targetView.length ) {
926 $targetView = $targetPane;
929 elementParent = element.parent();
930 if ( elementParent.length && elementParent[ 0 ] === $targetView[ 0 ] ) {
934 $targetView.empty().append( element ).trigger( "create" );
935 $targetView.fadeIn( 'fast' );
938 maximize : function ( id ) {
939 if ( typeof id !== "string" ) {
946 $targetPane = $el.children( id );
948 if ( !$targetPane.hasClass( "ui-pane" ) ) {
952 self.savedRatio = self.options.ratio.slice();
954 self.options.ratio = [];
955 $panes.each( function ( i ) {
956 self.options.ratio.push( ( this === $targetPane[ 0 ] ) ? 1 : 0 );
962 restore : function () {
965 if ( !self.savedRatio.length ) {
969 self.options.ratio = self.savedRatio.slice();
970 self._adjustRatio( self.panes.length );
976 $( document ).bind( "pagecreate create", function ( e ) {
977 $.tizen.splitview.prototype.enhanceWithin( e.target );
979 } ( jQuery, window, document ) );