├── .gitignore ├── LICENCE.MIT ├── README.md ├── examples ├── example-ltr.html ├── example-popup.html ├── example-rtl.html ├── libs │ ├── bootstrap.min.css │ ├── fancybox_loading.gif │ ├── fancybox_loading@2x.gif │ ├── fancybox_overlay.png │ ├── fancybox_sprite.png │ ├── fancybox_sprite@2x.png │ ├── jquery-3.2.0.min.js │ ├── jquery.fancybox.css │ └── jquery.fancybox.js └── sample-table.txt ├── jquery.stickytable.css ├── jquery.stickytable.js ├── jquery.stickytable.min.css ├── jquery.stickytable.min.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /LICENCE.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ahmed Rafik 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 | # Sticky Table Plugin for JQuery 2 | jquery.stickytable is a lightweight plugin to help developers have fixed rows or columns in a `
` or ` | ` element you want to get sticky relatively to the left. 26 | - Add `sticky-cell-opposite` class to the ` | ` or ` | ` element you want to get sticky relatively to the right. 27 | - If your table is `RTL`: 28 | - Add `sticky-rtl-cells` class to the *wrapper*. 29 | - Add `sticky-cell` class to the ` | ` or ` | ` element you want to get sticky relatively to the right. 30 | - Add `sticky-cell-opposite` class to the ` | ` or ` | ` element you want to get sticky relatively to the left.
31 |
32 | ### AJAX loaded content
33 | If there is a table loaded using AJAX after the document is initially loaded
34 | and it's needed to be sticky, trigger the `stickyTable` event on `$( document )` like:
35 | ```
36 | $( document ).trigger( "stickyTable" );
37 | ```
38 |
39 | You can view examples for more clarification.
40 | ## Known Issues
41 | We are aware of the following issues and we would be grateful if anyone can help us with them:
42 | - On RTL tables, sticky rows and cells flickers or doesn't appear at all in Microsoft Edge
43 | ## Credits
44 | Big thanks to [othree](https://github.com/othree) for his [jQuery RTL Scroll Type Detector](https://github.com/othree/jquery.rtl-scroll-type) which helped us alot supporting RTL tables for different browsers
45 | ## License
46 | [](https://opensource.org/licenses/MIT)
47 |
--------------------------------------------------------------------------------
/examples/example-ltr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | LTR Sticky Table16 |
17 |
1080 |
1081 |
1082 |
1083 |
--------------------------------------------------------------------------------
/examples/example-popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Sticky Table in a Popup19 | View Table 20 | 21 | 22 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /examples/example-rtl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |RTL Sticky Table16 |
17 |
1080 |
1081 |
1082 |
1083 |
--------------------------------------------------------------------------------
/examples/libs/fancybox_loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/armaaar/JQuery-Sticky-Table/b5bd2f9b85d46fb8fe19ec9e42d99e3b9d636da5/examples/libs/fancybox_loading.gif
--------------------------------------------------------------------------------
/examples/libs/fancybox_loading@2x.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/armaaar/JQuery-Sticky-Table/b5bd2f9b85d46fb8fe19ec9e42d99e3b9d636da5/examples/libs/fancybox_loading@2x.gif
--------------------------------------------------------------------------------
/examples/libs/fancybox_overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/armaaar/JQuery-Sticky-Table/b5bd2f9b85d46fb8fe19ec9e42d99e3b9d636da5/examples/libs/fancybox_overlay.png
--------------------------------------------------------------------------------
/examples/libs/fancybox_sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/armaaar/JQuery-Sticky-Table/b5bd2f9b85d46fb8fe19ec9e42d99e3b9d636da5/examples/libs/fancybox_sprite.png
--------------------------------------------------------------------------------
/examples/libs/fancybox_sprite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/armaaar/JQuery-Sticky-Table/b5bd2f9b85d46fb8fe19ec9e42d99e3b9d636da5/examples/libs/fancybox_sprite@2x.png
--------------------------------------------------------------------------------
/examples/libs/jquery.fancybox.css:
--------------------------------------------------------------------------------
1 | /*! fancyBox v2.1.5 fancyapps.com | fancyapps.com/fancybox/#license */
2 | .fancybox-wrap,
3 | .fancybox-skin,
4 | .fancybox-outer,
5 | .fancybox-inner,
6 | .fancybox-image,
7 | .fancybox-wrap iframe,
8 | .fancybox-wrap object,
9 | .fancybox-nav,
10 | .fancybox-nav span,
11 | .fancybox-tmp
12 | {
13 | padding: 0;
14 | margin: 0;
15 | border: 0;
16 | outline: none;
17 | vertical-align: top;
18 | }
19 |
20 | .fancybox-wrap {
21 | position: absolute;
22 | top: 0;
23 | left: 0;
24 | z-index: 8020;
25 | }
26 |
27 | .fancybox-skin {
28 | position: relative;
29 | background: #f9f9f9;
30 | color: #444;
31 | text-shadow: none;
32 | -webkit-border-radius: 4px;
33 | -moz-border-radius: 4px;
34 | border-radius: 4px;
35 | }
36 |
37 | .fancybox-opened {
38 | z-index: 8030;
39 | }
40 |
41 | .fancybox-opened .fancybox-skin {
42 | -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
43 | -moz-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
44 | box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
45 | }
46 |
47 | .fancybox-outer, .fancybox-inner {
48 | position: relative;
49 | }
50 |
51 | .fancybox-inner {
52 | overflow: hidden;
53 | }
54 |
55 | .fancybox-type-iframe .fancybox-inner {
56 | -webkit-overflow-scrolling: touch;
57 | }
58 |
59 | .fancybox-error {
60 | color: #444;
61 | font: 14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;
62 | margin: 0;
63 | padding: 15px;
64 | white-space: nowrap;
65 | }
66 |
67 | .fancybox-image, .fancybox-iframe {
68 | display: block;
69 | width: 100%;
70 | height: 100%;
71 | }
72 |
73 | .fancybox-image {
74 | max-width: 100%;
75 | max-height: 100%;
76 | }
77 |
78 | #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span {
79 | background-image: url('fancybox_sprite.png');
80 | }
81 |
82 | #fancybox-loading {
83 | position: fixed;
84 | top: 50%;
85 | left: 50%;
86 | margin-top: -22px;
87 | margin-left: -22px;
88 | background-position: 0 -108px;
89 | opacity: 0.8;
90 | cursor: pointer;
91 | z-index: 8060;
92 | }
93 |
94 | #fancybox-loading div {
95 | width: 44px;
96 | height: 44px;
97 | background: url('fancybox_loading.gif') center center no-repeat;
98 | }
99 |
100 | .fancybox-close {
101 | position: absolute;
102 | top: -18px;
103 | right: -18px;
104 | width: 36px;
105 | height: 36px;
106 | cursor: pointer;
107 | z-index: 8040;
108 | }
109 |
110 | .fancybox-nav {
111 | position: absolute;
112 | top: 0;
113 | width: 40%;
114 | height: 100%;
115 | cursor: pointer;
116 | text-decoration: none;
117 | background: transparent url('blank.gif'); /* helps IE */
118 | -webkit-tap-highlight-color: rgba(0,0,0,0);
119 | z-index: 8040;
120 | }
121 |
122 | .fancybox-prev {
123 | left: 0;
124 | }
125 |
126 | .fancybox-next {
127 | right: 0;
128 | }
129 |
130 | .fancybox-nav span {
131 | position: absolute;
132 | top: 50%;
133 | width: 36px;
134 | height: 34px;
135 | margin-top: -18px;
136 | cursor: pointer;
137 | z-index: 8040;
138 | visibility: hidden;
139 | }
140 |
141 | .fancybox-prev span {
142 | left: 10px;
143 | background-position: 0 -36px;
144 | }
145 |
146 | .fancybox-next span {
147 | right: 10px;
148 | background-position: 0 -72px;
149 | }
150 |
151 | .fancybox-nav:hover span {
152 | visibility: visible;
153 | }
154 |
155 | .fancybox-tmp {
156 | position: absolute;
157 | top: -99999px;
158 | left: -99999px;
159 | visibility: hidden;
160 | max-width: 99999px;
161 | max-height: 99999px;
162 | overflow: visible !important;
163 | }
164 |
165 | /* Overlay helper */
166 |
167 | .fancybox-lock {
168 | overflow: hidden !important;
169 | width: auto;
170 | }
171 |
172 | .fancybox-lock body {
173 | overflow: hidden !important;
174 | }
175 |
176 | .fancybox-lock-test {
177 | overflow-y: hidden !important;
178 | }
179 |
180 | .fancybox-overlay {
181 | position: absolute;
182 | top: 0;
183 | left: 0;
184 | overflow: hidden;
185 | display: none;
186 | z-index: 8010;
187 | background: url('fancybox_overlay.png');
188 | }
189 |
190 | .fancybox-overlay-fixed {
191 | position: fixed;
192 | bottom: 0;
193 | right: 0;
194 | }
195 |
196 | .fancybox-lock .fancybox-overlay {
197 | overflow: auto;
198 | overflow-y: scroll;
199 | }
200 |
201 | /* Title helper */
202 |
203 | .fancybox-title {
204 | visibility: hidden;
205 | font: normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;
206 | position: relative;
207 | text-shadow: none;
208 | z-index: 8050;
209 | }
210 |
211 | .fancybox-opened .fancybox-title {
212 | visibility: visible;
213 | }
214 |
215 | .fancybox-title-float-wrap {
216 | position: absolute;
217 | bottom: 0;
218 | right: 50%;
219 | margin-bottom: -35px;
220 | z-index: 8050;
221 | text-align: center;
222 | }
223 |
224 | .fancybox-title-float-wrap .child {
225 | display: inline-block;
226 | margin-right: -100%;
227 | padding: 2px 20px;
228 | background: transparent; /* Fallback for web browsers that doesn't support RGBa */
229 | background: rgba(0, 0, 0, 0.8);
230 | -webkit-border-radius: 15px;
231 | -moz-border-radius: 15px;
232 | border-radius: 15px;
233 | text-shadow: 0 1px 2px #222;
234 | color: #FFF;
235 | font-weight: bold;
236 | line-height: 24px;
237 | white-space: nowrap;
238 | }
239 |
240 | .fancybox-title-outside-wrap {
241 | position: relative;
242 | margin-top: 10px;
243 | color: #fff;
244 | }
245 |
246 | .fancybox-title-inside-wrap {
247 | padding-top: 10px;
248 | }
249 |
250 | .fancybox-title-over-wrap {
251 | position: absolute;
252 | bottom: 0;
253 | left: 0;
254 | color: #fff;
255 | padding: 10px;
256 | background: #000;
257 | background: rgba(0, 0, 0, .8);
258 | }
259 |
260 | /*Retina graphics!*/
261 | @media only screen and (-webkit-min-device-pixel-ratio: 1.5),
262 | only screen and (min--moz-device-pixel-ratio: 1.5),
263 | only screen and (min-device-pixel-ratio: 1.5){
264 |
265 | #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span {
266 | background-image: url('fancybox_sprite@2x.png');
267 | background-size: 44px 152px; /*The size of the normal image, half the size of the hi-res image*/
268 | }
269 |
270 | #fancybox-loading div {
271 | background-image: url('fancybox_loading@2x.gif');
272 | background-size: 24px 24px; /*The size of the normal image, half the size of the hi-res image*/
273 | }
274 | }
--------------------------------------------------------------------------------
/examples/libs/jquery.fancybox.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * fancyBox - jQuery Plugin
3 | * version: 2.1.5 (Fri, 14 Jun 2013)
4 | * @requires jQuery v1.6 or later
5 | *
6 | * Examples at http://fancyapps.com/fancybox/
7 | * License: www.fancyapps.com/fancybox/#license
8 | *
9 | * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
10 | *
11 | */
12 |
13 | (function (window, document, $, undefined) {
14 | "use strict";
15 |
16 | var H = $("html"),
17 | W = $(window),
18 | D = $(document),
19 | F = $.fancybox = function () {
20 | F.open.apply( this, arguments );
21 | },
22 | IE = navigator.userAgent.match(/msie/i),
23 | didUpdate = null,
24 | isTouch = document.createTouch !== undefined,
25 |
26 | isQuery = function(obj) {
27 | return obj && obj.hasOwnProperty && obj instanceof $;
28 | },
29 | isString = function(str) {
30 | return str && $.type(str) === "string";
31 | },
32 | isPercentage = function(str) {
33 | return isString(str) && str.indexOf('%') > 0;
34 | },
35 | isScrollable = function(el) {
36 | return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)));
37 | },
38 | getScalar = function(orig, dim) {
39 | var value = parseInt(orig, 10) || 0;
40 |
41 | if (dim && isPercentage(orig)) {
42 | value = F.getViewport()[ dim ] / 100 * value;
43 | }
44 |
45 | return Math.ceil(value);
46 | },
47 | getValue = function(value, dim) {
48 | return getScalar(value, dim) + 'px';
49 | };
50 |
51 | $.extend(F, {
52 | // The current version of fancyBox
53 | version: '2.1.5',
54 |
55 | defaults: {
56 | padding : 15,
57 | margin : 20,
58 |
59 | width : 800,
60 | height : 600,
61 | minWidth : 100,
62 | minHeight : 100,
63 | maxWidth : 9999,
64 | maxHeight : 9999,
65 | pixelRatio: 1, // Set to 2 for retina display support
66 |
67 | autoSize : true,
68 | autoHeight : false,
69 | autoWidth : false,
70 |
71 | autoResize : true,
72 | autoCenter : !isTouch,
73 | fitToView : true,
74 | aspectRatio : false,
75 | topRatio : 0.5,
76 | leftRatio : 0.5,
77 |
78 | scrolling : 'auto', // 'auto', 'yes' or 'no'
79 | wrapCSS : '',
80 |
81 | arrows : true,
82 | closeBtn : true,
83 | closeClick : false,
84 | nextClick : false,
85 | mouseWheel : true,
86 | autoPlay : false,
87 | playSpeed : 3000,
88 | preload : 3,
89 | modal : false,
90 | loop : true,
91 |
92 | ajax : {
93 | dataType : 'html',
94 | headers : { 'X-fancyBox': true }
95 | },
96 | iframe : {
97 | scrolling : 'auto',
98 | preload : true
99 | },
100 | swf : {
101 | wmode: 'transparent',
102 | allowfullscreen : 'true',
103 | allowscriptaccess : 'always'
104 | },
105 |
106 | keys : {
107 | next : {
108 | 13 : 'left', // enter
109 | 34 : 'up', // page down
110 | 39 : 'left', // right arrow
111 | 40 : 'up' // down arrow
112 | },
113 | prev : {
114 | 8 : 'right', // backspace
115 | 33 : 'down', // page up
116 | 37 : 'right', // left arrow
117 | 38 : 'down' // up arrow
118 | },
119 | close : [27], // escape key
120 | play : [32], // space - start/stop slideshow
121 | toggle : [70] // letter "f" - toggle fullscreen
122 | },
123 |
124 | direction : {
125 | next : 'left',
126 | prev : 'right'
127 | },
128 |
129 | scrollOutside : true,
130 |
131 | // Override some properties
132 | index : 0,
133 | type : null,
134 | href : null,
135 | content : null,
136 | title : null,
137 |
138 | // HTML templates
139 | tpl: {
140 | wrap : '
The requested content cannot be loaded. ').click(F.cancel).appendTo('body');
614 |
615 | // If user will press the escape-button, the request will be canceled
616 | D.bind('keydown.loading', function(e) {
617 | if ((e.which || e.keyCode) === 27) {
618 | e.preventDefault();
619 |
620 | F.cancel();
621 | }
622 | });
623 |
624 | if (!F.defaults.fixed) {
625 | viewport = F.getViewport();
626 |
627 | el.css({
628 | position : 'absolute',
629 | top : (viewport.h * 0.5) + viewport.y,
630 | left : (viewport.w * 0.5) + viewport.x
631 | });
632 | }
633 | },
634 |
635 | getViewport: function () {
636 | var locked = (F.current && F.current.locked) || false,
637 | rez = {
638 | x: W.scrollLeft(),
639 | y: W.scrollTop()
640 | };
641 |
642 | if (locked) {
643 | rez.w = locked[0].clientWidth;
644 | rez.h = locked[0].clientHeight;
645 |
646 | } else {
647 | // See http://bugs.jquery.com/ticket/6724
648 | rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width();
649 | rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height();
650 | }
651 |
652 | return rez;
653 | },
654 |
655 | // Unbind the keyboard / clicking actions
656 | unbindEvents: function () {
657 | if (F.wrap && isQuery(F.wrap)) {
658 | F.wrap.unbind('.fb');
659 | }
660 |
661 | D.unbind('.fb');
662 | W.unbind('.fb');
663 | },
664 |
665 | bindEvents: function () {
666 | var current = F.current,
667 | keys;
668 |
669 | if (!current) {
670 | return;
671 | }
672 |
673 | // Changing document height on iOS devices triggers a 'resize' event,
674 | // that can change document height... repeating infinitely
675 | W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);
676 |
677 | keys = current.keys;
678 |
679 | if (keys) {
680 | D.bind('keydown.fb', function (e) {
681 | var code = e.which || e.keyCode,
682 | target = e.target || e.srcElement;
683 |
684 | // Skip esc key if loading, because showLoading will cancel preloading
685 | if (code === 27 && F.coming) {
686 | return false;
687 | }
688 |
689 | // Ignore key combinations and key events within form elements
690 | if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
691 | $.each(keys, function(i, val) {
692 | if (current.group.length > 1 && val[ code ] !== undefined) {
693 | F[ i ]( val[ code ] );
694 |
695 | e.preventDefault();
696 | return false;
697 | }
698 |
699 | if ($.inArray(code, val) > -1) {
700 | F[ i ] ();
701 |
702 | e.preventDefault();
703 | return false;
704 | }
705 | });
706 | }
707 | });
708 | }
709 |
710 | if ($.fn.mousewheel && current.mouseWheel) {
711 | F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) {
712 | var target = e.target || null,
713 | parent = $(target),
714 | canScroll = false;
715 |
716 | while (parent.length) {
717 | if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) {
718 | break;
719 | }
720 |
721 | canScroll = isScrollable( parent[0] );
722 | parent = $(parent).parent();
723 | }
724 |
725 | if (delta !== 0 && !canScroll) {
726 | if (F.group.length > 1 && !current.canShrink) {
727 | if (deltaY > 0 || deltaX > 0) {
728 | F.prev( deltaY > 0 ? 'down' : 'left' );
729 |
730 | } else if (deltaY < 0 || deltaX < 0) {
731 | F.next( deltaY < 0 ? 'up' : 'right' );
732 | }
733 |
734 | e.preventDefault();
735 | }
736 | }
737 | });
738 | }
739 | },
740 |
741 | trigger: function (event, o) {
742 | var ret, obj = o || F.coming || F.current;
743 |
744 | if (!obj) {
745 | return;
746 | }
747 |
748 | if ($.isFunction( obj[event] )) {
749 | ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
750 | }
751 |
752 | if (ret === false) {
753 | return false;
754 | }
755 |
756 | if (obj.helpers) {
757 | $.each(obj.helpers, function (helper, opts) {
758 | if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) {
759 | F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj);
760 | }
761 | });
762 | }
763 |
764 | D.trigger(event);
765 | },
766 |
767 | isImage: function (str) {
768 | return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
769 | },
770 |
771 | isSWF: function (str) {
772 | return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
773 | },
774 |
775 | _start: function (index) {
776 | var coming = {},
777 | obj,
778 | href,
779 | type,
780 | margin,
781 | padding;
782 |
783 | index = getScalar( index );
784 | obj = F.group[ index ] || null;
785 |
786 | if (!obj) {
787 | return false;
788 | }
789 |
790 | coming = $.extend(true, {}, F.opts, obj);
791 |
792 | // Convert margin and padding properties to array - top, right, bottom, left
793 | margin = coming.margin;
794 | padding = coming.padding;
795 |
796 | if ($.type(margin) === 'number') {
797 | coming.margin = [margin, margin, margin, margin];
798 | }
799 |
800 | if ($.type(padding) === 'number') {
801 | coming.padding = [padding, padding, padding, padding];
802 | }
803 |
804 | // 'modal' propery is just a shortcut
805 | if (coming.modal) {
806 | $.extend(true, coming, {
807 | closeBtn : false,
808 | closeClick : false,
809 | nextClick : false,
810 | arrows : false,
811 | mouseWheel : false,
812 | keys : null,
813 | helpers: {
814 | overlay : {
815 | closeClick : false
816 | }
817 | }
818 | });
819 | }
820 |
821 | // 'autoSize' property is a shortcut, too
822 | if (coming.autoSize) {
823 | coming.autoWidth = coming.autoHeight = true;
824 | }
825 |
826 | if (coming.width === 'auto') {
827 | coming.autoWidth = true;
828 | }
829 |
830 | if (coming.height === 'auto') {
831 | coming.autoHeight = true;
832 | }
833 |
834 | /*
835 | * Add reference to the group, so it`s possible to access from callbacks, example:
836 | * afterLoad : function() {
837 | * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
838 | * }
839 | */
840 |
841 | coming.group = F.group;
842 | coming.index = index;
843 |
844 | // Give a chance for callback or helpers to update coming item (type, title, etc)
845 | F.coming = coming;
846 |
847 | if (false === F.trigger('beforeLoad')) {
848 | F.coming = null;
849 |
850 | return;
851 | }
852 |
853 | type = coming.type;
854 | href = coming.href;
855 |
856 | if (!type) {
857 | F.coming = null;
858 |
859 | //If we can not determine content type then drop silently or display next/prev item if looping through gallery
860 | if (F.current && F.router && F.router !== 'jumpto') {
861 | F.current.index = index;
862 |
863 | return F[ F.router ]( F.direction );
864 | }
865 |
866 | return false;
867 | }
868 |
869 | F.isActive = true;
870 |
871 | if (type === 'image' || type === 'swf') {
872 | coming.autoHeight = coming.autoWidth = false;
873 | coming.scrolling = 'visible';
874 | }
875 |
876 | if (type === 'image') {
877 | coming.aspectRatio = true;
878 | }
879 |
880 | if (type === 'iframe' && isTouch) {
881 | coming.scrolling = 'scroll';
882 | }
883 |
884 | // Build the neccessary markup
885 | coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' );
886 |
887 | $.extend(coming, {
888 | skin : $('.fancybox-skin', coming.wrap),
889 | outer : $('.fancybox-outer', coming.wrap),
890 | inner : $('.fancybox-inner', coming.wrap)
891 | });
892 |
893 | $.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
894 | coming.skin.css('padding' + v, getValue(coming.padding[ i ]));
895 | });
896 |
897 | F.trigger('onReady');
898 |
899 | // Check before try to load; 'inline' and 'html' types need content, others - href
900 | if (type === 'inline' || type === 'html') {
901 | if (!coming.content || !coming.content.length) {
902 | return F._error( 'content' );
903 | }
904 |
905 | } else if (!href) {
906 | return F._error( 'href' );
907 | }
908 |
909 | if (type === 'image') {
910 | F._loadImage();
911 |
912 | } else if (type === 'ajax') {
913 | F._loadAjax();
914 |
915 | } else if (type === 'iframe') {
916 | F._loadIframe();
917 |
918 | } else {
919 | F._afterLoad();
920 | }
921 | },
922 |
923 | _error: function ( type ) {
924 | $.extend(F.coming, {
925 | type : 'html',
926 | autoWidth : true,
927 | autoHeight : true,
928 | minWidth : 0,
929 | minHeight : 0,
930 | scrolling : 'no',
931 | hasError : type,
932 | content : F.coming.tpl.error
933 | });
934 |
935 | F._afterLoad();
936 | },
937 |
938 | _loadImage: function () {
939 | // Reset preload image so it is later possible to check "complete" property
940 | var img = F.imgPreload = new Image();
941 |
942 | img.onload = function () {
943 | this.onload = this.onerror = null;
944 |
945 | F.coming.width = this.width / F.opts.pixelRatio;
946 | F.coming.height = this.height / F.opts.pixelRatio;
947 |
948 | F._afterLoad();
949 | };
950 |
951 | img.onerror = function () {
952 | this.onload = this.onerror = null;
953 |
954 | F._error( 'image' );
955 | };
956 |
957 | img.src = F.coming.href;
958 |
959 | if (img.complete !== true) {
960 | F.showLoading();
961 | }
962 | },
963 |
964 | _loadAjax: function () {
965 | var coming = F.coming;
966 |
967 | F.showLoading();
968 |
969 | F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
970 | url: coming.href,
971 | error: function (jqXHR, textStatus) {
972 | if (F.coming && textStatus !== 'abort') {
973 | F._error( 'ajax', jqXHR );
974 |
975 | } else {
976 | F.hideLoading();
977 | }
978 | },
979 | success: function (data, textStatus) {
980 | if (textStatus === 'success') {
981 | coming.content = data;
982 |
983 | F._afterLoad();
984 | }
985 | }
986 | }));
987 | },
988 |
989 | _loadIframe: function() {
990 | var coming = F.coming,
991 | iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
992 | .attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling)
993 | .attr('src', coming.href);
994 |
995 | // This helps IE
996 | $(coming.wrap).bind('onReset', function () {
997 | try {
998 | $(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
999 | } catch (e) {}
1000 | });
1001 |
1002 | if (coming.iframe.preload) {
1003 | F.showLoading();
1004 |
1005 | iframe.one('load', function() {
1006 | $(this).data('ready', 1);
1007 |
1008 | // iOS will lose scrolling if we resize
1009 | if (!isTouch) {
1010 | $(this).bind('load.fb', F.update);
1011 | }
1012 |
1013 | // Without this trick:
1014 | // - iframe won't scroll on iOS devices
1015 | // - IE7 sometimes displays empty iframe
1016 | $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show();
1017 |
1018 | F._afterLoad();
1019 | });
1020 | }
1021 |
1022 | coming.content = iframe.appendTo( coming.inner );
1023 |
1024 | if (!coming.iframe.preload) {
1025 | F._afterLoad();
1026 | }
1027 | },
1028 |
1029 | _preloadImages: function() {
1030 | var group = F.group,
1031 | current = F.current,
1032 | len = group.length,
1033 | cnt = current.preload ? Math.min(current.preload, len - 1) : 0,
1034 | item,
1035 | i;
1036 |
1037 | for (i = 1; i <= cnt; i += 1) {
1038 | item = group[ (current.index + i ) % len ];
1039 |
1040 | if (item.type === 'image' && item.href) {
1041 | new Image().src = item.href;
1042 | }
1043 | }
1044 | },
1045 |
1046 | _afterLoad: function () {
1047 | var coming = F.coming,
1048 | previous = F.current,
1049 | placeholder = 'fancybox-placeholder',
1050 | current,
1051 | content,
1052 | type,
1053 | scrolling,
1054 | href,
1055 | embed;
1056 |
1057 | F.hideLoading();
1058 |
1059 | if (!coming || F.isActive === false) {
1060 | return;
1061 | }
1062 |
1063 | if (false === F.trigger('afterLoad', coming, previous)) {
1064 | coming.wrap.stop(true).trigger('onReset').remove();
1065 |
1066 | F.coming = null;
1067 |
1068 | return;
1069 | }
1070 |
1071 | if (previous) {
1072 | F.trigger('beforeChange', previous);
1073 |
1074 | previous.wrap.stop(true).removeClass('fancybox-opened')
1075 | .find('.fancybox-item, .fancybox-nav')
1076 | .remove();
1077 | }
1078 |
1079 | F.unbindEvents();
1080 |
1081 | current = coming;
1082 | content = coming.content;
1083 | type = coming.type;
1084 | scrolling = coming.scrolling;
1085 |
1086 | $.extend(F, {
1087 | wrap : current.wrap,
1088 | skin : current.skin,
1089 | outer : current.outer,
1090 | inner : current.inner,
1091 | current : current,
1092 | previous : previous
1093 | });
1094 |
1095 | href = current.href;
1096 |
1097 | switch (type) {
1098 | case 'inline':
1099 | case 'ajax':
1100 | case 'html':
1101 | if (current.selector) {
1102 | content = $(' ').html(content).find(current.selector);
1103 |
1104 | } else if (isQuery(content)) {
1105 | if (!content.data(placeholder)) {
1106 | content.data(placeholder, $('').insertAfter( content ).hide() );
1107 | }
1108 |
1109 | content = content.show().detach();
1110 |
1111 | current.wrap.bind('onReset', function () {
1112 | if ($(this).find(content).length) {
1113 | content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false);
1114 | }
1115 | });
1116 | }
1117 | break;
1118 |
1119 | case 'image':
1120 | content = current.tpl.image.replace('{href}', href);
1121 | break;
1122 |
1123 | case 'swf':
1124 | content = '';
1133 | break;
1134 | }
1135 |
1136 | if (!(isQuery(content) && content.parent().is(current.inner))) {
1137 | current.inner.append( content );
1138 | }
1139 |
1140 | // Give a chance for helpers or callbacks to update elements
1141 | F.trigger('beforeShow');
1142 |
1143 | // Set scrolling before calculating dimensions
1144 | current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
1145 |
1146 | // Set initial dimensions and start position
1147 | F._setDimension();
1148 |
1149 | F.reposition();
1150 |
1151 | F.isOpen = false;
1152 | F.coming = null;
1153 |
1154 | F.bindEvents();
1155 |
1156 | if (!F.isOpened) {
1157 | $('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove();
1158 |
1159 | } else if (previous.prevMethod) {
1160 | F.transitions[ previous.prevMethod ]();
1161 | }
1162 |
1163 | F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ]();
1164 |
1165 | F._preloadImages();
1166 | },
1167 |
1168 | _setDimension: function () {
1169 | var viewport = F.getViewport(),
1170 | steps = 0,
1171 | canShrink = false,
1172 | canExpand = false,
1173 | wrap = F.wrap,
1174 | skin = F.skin,
1175 | inner = F.inner,
1176 | current = F.current,
1177 | width = current.width,
1178 | height = current.height,
1179 | minWidth = current.minWidth,
1180 | minHeight = current.minHeight,
1181 | maxWidth = current.maxWidth,
1182 | maxHeight = current.maxHeight,
1183 | scrolling = current.scrolling,
1184 | scrollOut = current.scrollOutside ? current.scrollbarWidth : 0,
1185 | margin = current.margin,
1186 | wMargin = getScalar(margin[1] + margin[3]),
1187 | hMargin = getScalar(margin[0] + margin[2]),
1188 | wPadding,
1189 | hPadding,
1190 | wSpace,
1191 | hSpace,
1192 | origWidth,
1193 | origHeight,
1194 | origMaxWidth,
1195 | origMaxHeight,
1196 | ratio,
1197 | width_,
1198 | height_,
1199 | maxWidth_,
1200 | maxHeight_,
1201 | iframe,
1202 | body;
1203 |
1204 | // Reset dimensions so we could re-check actual size
1205 | wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp');
1206 |
1207 | wPadding = getScalar(skin.outerWidth(true) - skin.width());
1208 | hPadding = getScalar(skin.outerHeight(true) - skin.height());
1209 |
1210 | // Any space between content and viewport (margin, padding, border, title)
1211 | wSpace = wMargin + wPadding;
1212 | hSpace = hMargin + hPadding;
1213 |
1214 | origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width;
1215 | origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height;
1216 |
1217 | if (current.type === 'iframe') {
1218 | iframe = current.content;
1219 |
1220 | if (current.autoHeight && iframe.data('ready') === 1) {
1221 | try {
1222 | if (iframe[0].contentWindow.document.location) {
1223 | inner.width( origWidth ).height(9999);
1224 |
1225 | body = iframe.contents().find('body');
1226 |
1227 | if (scrollOut) {
1228 | body.css('overflow-x', 'hidden');
1229 | }
1230 |
1231 | origHeight = body.outerHeight(true);
1232 | }
1233 |
1234 | } catch (e) {}
1235 | }
1236 |
1237 | } else if (current.autoWidth || current.autoHeight) {
1238 | inner.addClass( 'fancybox-tmp' );
1239 |
1240 | // Set width or height in case we need to calculate only one dimension
1241 | if (!current.autoWidth) {
1242 | inner.width( origWidth );
1243 | }
1244 |
1245 | if (!current.autoHeight) {
1246 | inner.height( origHeight );
1247 | }
1248 |
1249 | if (current.autoWidth) {
1250 | origWidth = inner.width();
1251 | }
1252 |
1253 | if (current.autoHeight) {
1254 | origHeight = inner.height();
1255 | }
1256 |
1257 | inner.removeClass( 'fancybox-tmp' );
1258 | }
1259 |
1260 | width = getScalar( origWidth );
1261 | height = getScalar( origHeight );
1262 |
1263 | ratio = origWidth / origHeight;
1264 |
1265 | // Calculations for the content
1266 | minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth);
1267 | maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth);
1268 |
1269 | minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight);
1270 | maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight);
1271 |
1272 | // These will be used to determine if wrap can fit in the viewport
1273 | origMaxWidth = maxWidth;
1274 | origMaxHeight = maxHeight;
1275 |
1276 | if (current.fitToView) {
1277 | maxWidth = Math.min(viewport.w - wSpace, maxWidth);
1278 | maxHeight = Math.min(viewport.h - hSpace, maxHeight);
1279 | }
1280 |
1281 | maxWidth_ = viewport.w - wMargin;
1282 | maxHeight_ = viewport.h - hMargin;
1283 |
1284 | if (current.aspectRatio) {
1285 | if (width > maxWidth) {
1286 | width = maxWidth;
1287 | height = getScalar(width / ratio);
1288 | }
1289 |
1290 | if (height > maxHeight) {
1291 | height = maxHeight;
1292 | width = getScalar(height * ratio);
1293 | }
1294 |
1295 | if (width < minWidth) {
1296 | width = minWidth;
1297 | height = getScalar(width / ratio);
1298 | }
1299 |
1300 | if (height < minHeight) {
1301 | height = minHeight;
1302 | width = getScalar(height * ratio);
1303 | }
1304 |
1305 | } else {
1306 | width = Math.max(minWidth, Math.min(width, maxWidth));
1307 |
1308 | if (current.autoHeight && current.type !== 'iframe') {
1309 | inner.width( width );
1310 |
1311 | height = inner.height();
1312 | }
1313 |
1314 | height = Math.max(minHeight, Math.min(height, maxHeight));
1315 | }
1316 |
1317 | // Try to fit inside viewport (including the title)
1318 | if (current.fitToView) {
1319 | inner.width( width ).height( height );
1320 |
1321 | wrap.width( width + wPadding );
1322 |
1323 | // Real wrap dimensions
1324 | width_ = wrap.width();
1325 | height_ = wrap.height();
1326 |
1327 | if (current.aspectRatio) {
1328 | while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
1329 | if (steps++ > 19) {
1330 | break;
1331 | }
1332 |
1333 | height = Math.max(minHeight, Math.min(maxHeight, height - 10));
1334 | width = getScalar(height * ratio);
1335 |
1336 | if (width < minWidth) {
1337 | width = minWidth;
1338 | height = getScalar(width / ratio);
1339 | }
1340 |
1341 | if (width > maxWidth) {
1342 | width = maxWidth;
1343 | height = getScalar(width / ratio);
1344 | }
1345 |
1346 | inner.width( width ).height( height );
1347 |
1348 | wrap.width( width + wPadding );
1349 |
1350 | width_ = wrap.width();
1351 | height_ = wrap.height();
1352 | }
1353 |
1354 | } else {
1355 | width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_)));
1356 | height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_)));
1357 | }
1358 | }
1359 |
1360 | if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) {
1361 | width += scrollOut;
1362 | }
1363 |
1364 | inner.width( width ).height( height );
1365 |
1366 | wrap.width( width + wPadding );
1367 |
1368 | width_ = wrap.width();
1369 | height_ = wrap.height();
1370 |
1371 | canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
1372 | canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight));
1373 |
1374 | $.extend(current, {
1375 | dim : {
1376 | width : getValue( width_ ),
1377 | height : getValue( height_ )
1378 | },
1379 | origWidth : origWidth,
1380 | origHeight : origHeight,
1381 | canShrink : canShrink,
1382 | canExpand : canExpand,
1383 | wPadding : wPadding,
1384 | hPadding : hPadding,
1385 | wrapSpace : height_ - skin.outerHeight(true),
1386 | skinSpace : skin.height() - height
1387 | });
1388 |
1389 | if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
1390 | inner.height('auto');
1391 | }
1392 | },
1393 |
1394 | _getPosition: function (onlyAbsolute) {
1395 | var current = F.current,
1396 | viewport = F.getViewport(),
1397 | margin = current.margin,
1398 | width = F.wrap.width() + margin[1] + margin[3],
1399 | height = F.wrap.height() + margin[0] + margin[2],
1400 | rez = {
1401 | position: 'absolute',
1402 | top : margin[0],
1403 | left : margin[3]
1404 | };
1405 |
1406 | if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
1407 | rez.position = 'fixed';
1408 |
1409 | } else if (!current.locked) {
1410 | rez.top += viewport.y;
1411 | rez.left += viewport.x;
1412 | }
1413 |
1414 | rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio)));
1415 | rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * current.leftRatio)));
1416 |
1417 | return rez;
1418 | },
1419 |
1420 | _afterZoomIn: function () {
1421 | var current = F.current;
1422 |
1423 | if (!current) {
1424 | return;
1425 | }
1426 |
1427 | F.isOpen = F.isOpened = true;
1428 |
1429 | F.wrap.css('overflow', 'visible').addClass('fancybox-opened');
1430 |
1431 | F.update();
1432 |
1433 | // Assign a click event
1434 | if ( current.closeClick || (current.nextClick && F.group.length > 1) ) {
1435 | F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
1436 | if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
1437 | e.preventDefault();
1438 |
1439 | F[ current.closeClick ? 'close' : 'next' ]();
1440 | }
1441 | });
1442 | }
1443 |
1444 | // Create a close button
1445 | if (current.closeBtn) {
1446 | $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
1447 | e.preventDefault();
1448 |
1449 | F.close();
1450 | });
1451 | }
1452 |
1453 | // Create navigation arrows
1454 | if (current.arrows && F.group.length > 1) {
1455 | if (current.loop || current.index > 0) {
1456 | $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
1457 | }
1458 |
1459 | if (current.loop || current.index < F.group.length - 1) {
1460 | $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
1461 | }
1462 | }
1463 |
1464 | F.trigger('afterShow');
1465 |
1466 | // Stop the slideshow if this is the last item
1467 | if (!current.loop && current.index === current.group.length - 1) {
1468 | F.play( false );
1469 |
1470 | } else if (F.opts.autoPlay && !F.player.isActive) {
1471 | F.opts.autoPlay = false;
1472 |
1473 | F.play();
1474 | }
1475 | },
1476 |
1477 | _afterZoomOut: function ( obj ) {
1478 | obj = obj || F.current;
1479 |
1480 | $('.fancybox-wrap').trigger('onReset').remove();
1481 |
1482 | $.extend(F, {
1483 | group : {},
1484 | opts : {},
1485 | router : false,
1486 | current : null,
1487 | isActive : false,
1488 | isOpened : false,
1489 | isOpen : false,
1490 | isClosing : false,
1491 | wrap : null,
1492 | skin : null,
1493 | outer : null,
1494 | inner : null
1495 | });
1496 |
1497 | F.trigger('afterClose', obj);
1498 | }
1499 | });
1500 |
1501 | /*
1502 | * Default transitions
1503 | */
1504 |
1505 | F.transitions = {
1506 | getOrigPosition: function () {
1507 | var current = F.current,
1508 | element = current.element,
1509 | orig = current.orig,
1510 | pos = {},
1511 | width = 50,
1512 | height = 50,
1513 | hPadding = current.hPadding,
1514 | wPadding = current.wPadding,
1515 | viewport = F.getViewport();
1516 |
1517 | if (!orig && current.isDom && element.is(':visible')) {
1518 | orig = element.find('img:first');
1519 |
1520 | if (!orig.length) {
1521 | orig = element;
1522 | }
1523 | }
1524 |
1525 | if (isQuery(orig)) {
1526 | pos = orig.offset();
1527 |
1528 | if (orig.is('img')) {
1529 | width = orig.outerWidth();
1530 | height = orig.outerHeight();
1531 | }
1532 |
1533 | } else {
1534 | pos.top = viewport.y + (viewport.h - height) * current.topRatio;
1535 | pos.left = viewport.x + (viewport.w - width) * current.leftRatio;
1536 | }
1537 |
1538 | if (F.wrap.css('position') === 'fixed' || current.locked) {
1539 | pos.top -= viewport.y;
1540 | pos.left -= viewport.x;
1541 | }
1542 |
1543 | pos = {
1544 | top : getValue(pos.top - hPadding * current.topRatio),
1545 | left : getValue(pos.left - wPadding * current.leftRatio),
1546 | width : getValue(width + wPadding),
1547 | height : getValue(height + hPadding)
1548 | };
1549 |
1550 | return pos;
1551 | },
1552 |
1553 | step: function (now, fx) {
1554 | var ratio,
1555 | padding,
1556 | value,
1557 | prop = fx.prop,
1558 | current = F.current,
1559 | wrapSpace = current.wrapSpace,
1560 | skinSpace = current.skinSpace;
1561 |
1562 | if (prop === 'width' || prop === 'height') {
1563 | ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start);
1564 |
1565 | if (F.isClosing) {
1566 | ratio = 1 - ratio;
1567 | }
1568 |
1569 | padding = prop === 'width' ? current.wPadding : current.hPadding;
1570 | value = now - padding;
1571 |
1572 | F.skin[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) ) );
1573 | F.inner[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) );
1574 | }
1575 | },
1576 |
1577 | zoomIn: function () {
1578 | var current = F.current,
1579 | startPos = current.pos,
1580 | effect = current.openEffect,
1581 | elastic = effect === 'elastic',
1582 | endPos = $.extend({opacity : 1}, startPos);
1583 |
1584 | // Remove "position" property that breaks older IE
1585 | delete endPos.position;
1586 |
1587 | if (elastic) {
1588 | startPos = this.getOrigPosition();
1589 |
1590 | if (current.openOpacity) {
1591 | startPos.opacity = 0.1;
1592 | }
1593 |
1594 | } else if (effect === 'fade') {
1595 | startPos.opacity = 0.1;
1596 | }
1597 |
1598 | F.wrap.css(startPos).animate(endPos, {
1599 | duration : effect === 'none' ? 0 : current.openSpeed,
1600 | easing : current.openEasing,
1601 | step : elastic ? this.step : null,
1602 | complete : F._afterZoomIn
1603 | });
1604 | },
1605 |
1606 | zoomOut: function () {
1607 | var current = F.current,
1608 | effect = current.closeEffect,
1609 | elastic = effect === 'elastic',
1610 | endPos = {opacity : 0.1};
1611 |
1612 | if (elastic) {
1613 | endPos = this.getOrigPosition();
1614 |
1615 | if (current.closeOpacity) {
1616 | endPos.opacity = 0.1;
1617 | }
1618 | }
1619 |
1620 | F.wrap.animate(endPos, {
1621 | duration : effect === 'none' ? 0 : current.closeSpeed,
1622 | easing : current.closeEasing,
1623 | step : elastic ? this.step : null,
1624 | complete : F._afterZoomOut
1625 | });
1626 | },
1627 |
1628 | changeIn: function () {
1629 | var current = F.current,
1630 | effect = current.nextEffect,
1631 | startPos = current.pos,
1632 | endPos = { opacity : 1 },
1633 | direction = F.direction,
1634 | distance = 200,
1635 | field;
1636 |
1637 | startPos.opacity = 0.1;
1638 |
1639 | if (effect === 'elastic') {
1640 | field = direction === 'down' || direction === 'up' ? 'top' : 'left';
1641 |
1642 | if (direction === 'down' || direction === 'right') {
1643 | startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
1644 | endPos[ field ] = '+=' + distance + 'px';
1645 |
1646 | } else {
1647 | startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
1648 | endPos[ field ] = '-=' + distance + 'px';
1649 | }
1650 | }
1651 |
1652 | // Workaround for http://bugs.jquery.com/ticket/12273
1653 | if (effect === 'none') {
1654 | F._afterZoomIn();
1655 |
1656 | } else {
1657 | F.wrap.css(startPos).animate(endPos, {
1658 | duration : current.nextSpeed,
1659 | easing : current.nextEasing,
1660 | complete : F._afterZoomIn
1661 | });
1662 | }
1663 | },
1664 |
1665 | changeOut: function () {
1666 | var previous = F.previous,
1667 | effect = previous.prevEffect,
1668 | endPos = { opacity : 0.1 },
1669 | direction = F.direction,
1670 | distance = 200;
1671 |
1672 | if (effect === 'elastic') {
1673 | endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
1674 | }
1675 |
1676 | previous.wrap.animate(endPos, {
1677 | duration : effect === 'none' ? 0 : previous.prevSpeed,
1678 | easing : previous.prevEasing,
1679 | complete : function () {
1680 | $(this).trigger('onReset').remove();
1681 | }
1682 | });
1683 | }
1684 | };
1685 |
1686 | /*
1687 | * Overlay helper
1688 | */
1689 |
1690 | F.helpers.overlay = {
1691 | defaults : {
1692 | closeClick : true, // if true, fancyBox will be closed when user clicks on the overlay
1693 | speedOut : 200, // duration of fadeOut animation
1694 | showEarly : true, // indicates if should be opened immediately or wait until the content is ready
1695 | css : {}, // custom CSS properties
1696 | locked : !isTouch, // if true, the content will be locked into overlay
1697 | fixed : true // if false, the overlay CSS position property will not be set to "fixed"
1698 | },
1699 |
1700 | overlay : null, // current handle
1701 | fixed : false, // indicates if the overlay has position "fixed"
1702 | el : $('html'), // element that contains "the lock"
1703 |
1704 | // Public methods
1705 | create : function(opts) {
1706 | opts = $.extend({}, this.defaults, opts);
1707 |
1708 | if (this.overlay) {
1709 | this.close();
1710 | }
1711 |
1712 | this.overlay = $('').appendTo( F.coming ? F.coming.parent : opts.parent );
1713 | this.fixed = false;
1714 |
1715 | if (opts.fixed && F.defaults.fixed) {
1716 | this.overlay.addClass('fancybox-overlay-fixed');
1717 |
1718 | this.fixed = true;
1719 | }
1720 | },
1721 |
1722 | open : function(opts) {
1723 | var that = this;
1724 |
1725 | opts = $.extend({}, this.defaults, opts);
1726 |
1727 | if (this.overlay) {
1728 | this.overlay.unbind('.overlay').width('auto').height('auto');
1729 |
1730 | } else {
1731 | this.create(opts);
1732 | }
1733 |
1734 | if (!this.fixed) {
1735 | W.bind('resize.overlay', $.proxy( this.update, this) );
1736 |
1737 | this.update();
1738 | }
1739 |
1740 | if (opts.closeClick) {
1741 | this.overlay.bind('click.overlay', function(e) {
1742 | if ($(e.target).hasClass('fancybox-overlay')) {
1743 | if (F.isActive) {
1744 | F.close();
1745 | } else {
1746 | that.close();
1747 | }
1748 |
1749 | return false;
1750 | }
1751 | });
1752 | }
1753 |
1754 | this.overlay.css( opts.css ).show();
1755 | },
1756 |
1757 | close : function() {
1758 | var scrollV, scrollH;
1759 |
1760 | W.unbind('resize.overlay');
1761 |
1762 | if (this.el.hasClass('fancybox-lock')) {
1763 | $('.fancybox-margin').removeClass('fancybox-margin');
1764 |
1765 | scrollV = W.scrollTop();
1766 | scrollH = W.scrollLeft();
1767 |
1768 | this.el.removeClass('fancybox-lock');
1769 |
1770 | W.scrollTop( scrollV ).scrollLeft( scrollH );
1771 | }
1772 |
1773 | $('.fancybox-overlay').remove().hide();
1774 |
1775 | $.extend(this, {
1776 | overlay : null,
1777 | fixed : false
1778 | });
1779 | },
1780 |
1781 | // Private, callbacks
1782 |
1783 | update : function () {
1784 | var width = '100%', offsetWidth;
1785 |
1786 | // Reset width/height so it will not mess
1787 | this.overlay.width(width).height('100%');
1788 |
1789 | // jQuery does not return reliable result for IE
1790 | if (IE) {
1791 | offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
1792 |
1793 | if (D.width() > offsetWidth) {
1794 | width = D.width();
1795 | }
1796 |
1797 | } else if (D.width() > W.width()) {
1798 | width = D.width();
1799 | }
1800 |
1801 | this.overlay.width(width).height(D.height());
1802 | },
1803 |
1804 | // This is where we can manipulate DOM, because later it would cause iframes to reload
1805 | onReady : function (opts, obj) {
1806 | var overlay = this.overlay;
1807 |
1808 | $('.fancybox-overlay').stop(true, true);
1809 |
1810 | if (!overlay) {
1811 | this.create(opts);
1812 | }
1813 |
1814 | if (opts.locked && this.fixed && obj.fixed) {
1815 | if (!overlay) {
1816 | this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false;
1817 | }
1818 |
1819 | obj.locked = this.overlay.append( obj.wrap );
1820 | obj.fixed = false;
1821 | }
1822 |
1823 | if (opts.showEarly === true) {
1824 | this.beforeShow.apply(this, arguments);
1825 | }
1826 | },
1827 |
1828 | beforeShow : function(opts, obj) {
1829 | var scrollV, scrollH;
1830 |
1831 | if (obj.locked) {
1832 | if (this.margin !== false) {
1833 | $('*').filter(function(){
1834 | return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") );
1835 | }).addClass('fancybox-margin');
1836 |
1837 | //this.el.addClass('fancybox-margin');
1838 | }
1839 |
1840 | scrollV = W.scrollTop();
1841 | scrollH = W.scrollLeft();
1842 |
1843 | //this.el.addClass('fancybox-lock');
1844 |
1845 | W.scrollTop( scrollV ).scrollLeft( scrollH );
1846 | }
1847 |
1848 | this.open(opts);
1849 | },
1850 |
1851 | onUpdate : function() {
1852 | if (!this.fixed) {
1853 | this.update();
1854 | }
1855 | },
1856 |
1857 | afterClose: function (opts) {
1858 | // Remove overlay if exists and fancyBox is not opening
1859 | // (e.g., it is not being open using afterClose callback)
1860 | //if (this.overlay && !F.isActive) {
1861 | if (this.overlay && !F.coming) {
1862 | this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this ));
1863 | }
1864 | }
1865 | };
1866 |
1867 | /*
1868 | * Title helper
1869 | */
1870 |
1871 | F.helpers.title = {
1872 | defaults : {
1873 | type : 'float', // 'float', 'inside', 'outside' or 'over',
1874 | position : 'bottom' // 'top' or 'bottom'
1875 | },
1876 |
1877 | beforeShow: function (opts) {
1878 | var current = F.current,
1879 | text = current.title,
1880 | type = opts.type,
1881 | title,
1882 | target;
1883 |
1884 | if ($.isFunction(text)) {
1885 | text = text.call(current.element, current);
1886 | }
1887 |
1888 | if (!isString(text) || $.trim(text) === '') {
1889 | return;
1890 | }
1891 |
1892 | title = $(' ' + text + ' ');
1893 |
1894 | switch (type) {
1895 | case 'inside':
1896 | target = F.skin;
1897 | break;
1898 |
1899 | case 'outside':
1900 | target = F.wrap;
1901 | break;
1902 |
1903 | case 'over':
1904 | target = F.inner;
1905 | break;
1906 |
1907 | default: // 'float'
1908 | target = F.skin;
1909 |
1910 | title.appendTo('body');
1911 |
1912 | if (IE) {
1913 | title.width( title.width() );
1914 | }
1915 |
1916 | title.wrapInner('');
1917 |
1918 | //Increase bottom margin so this title will also fit into viewport
1919 | F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) );
1920 | break;
1921 | }
1922 |
1923 | title[ (opts.position === 'top' ? 'prependTo' : 'appendTo') ](target);
1924 | }
1925 | };
1926 |
1927 | // jQuery plugin initialization
1928 | $.fn.fancybox = function (options) {
1929 | var index,
1930 | that = $(this),
1931 | selector = this.selector || '',
1932 | run = function(e) {
1933 | var what = $(this).blur(), idx = index, relType, relVal;
1934 |
1935 | if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) {
1936 | relType = options.groupAttr || 'data-fancybox-group';
1937 | relVal = what.attr(relType);
1938 |
1939 | if (!relVal) {
1940 | relType = 'rel';
1941 | relVal = what.get(0)[ relType ];
1942 | }
1943 |
1944 | if (relVal && relVal !== '' && relVal !== 'nofollow') {
1945 | what = selector.length ? $(selector) : that;
1946 | what = what.filter('[' + relType + '="' + relVal + '"]');
1947 | idx = what.index(this);
1948 | }
1949 |
1950 | options.index = idx;
1951 |
1952 | // Stop an event from bubbling if everything is fine
1953 | if (F.open(what, options) !== false) {
1954 | e.preventDefault();
1955 | }
1956 | }
1957 | };
1958 |
1959 | options = options || {};
1960 | index = options.index || 0;
1961 |
1962 | if (!selector || options.live === false) {
1963 | that.unbind('click.fb-start').bind('click.fb-start', run);
1964 |
1965 | } else {
1966 | D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run);
1967 | }
1968 |
1969 | this.filter('[data-fancybox-start=1]').trigger('click');
1970 |
1971 | return this;
1972 | };
1973 |
1974 | // Tests that need a body at doc ready
1975 | D.ready(function() {
1976 | var w1, w2;
1977 |
1978 | if ( $.scrollbarWidth === undefined ) {
1979 | // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth
1980 | $.scrollbarWidth = function() {
1981 | var parent = $('').appendTo('body'),
1982 | child = parent.children(),
1983 | width = child.innerWidth() - child.height( 99 ).innerWidth();
1984 |
1985 | parent.remove();
1986 |
1987 | return width;
1988 | };
1989 | }
1990 |
1991 | if ( $.support.fixedPosition === undefined ) {
1992 | $.support.fixedPosition = (function() {
1993 | var elem = $('').appendTo('body'),
1994 | fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 );
1995 |
1996 | elem.remove();
1997 |
1998 | return fixed;
1999 | }());
2000 | }
2001 |
2002 | $.extend(F.defaults, {
2003 | scrollbarWidth : $.scrollbarWidth(),
2004 | fixed : $.support.fixedPosition,
2005 | parent : $('body')
2006 | });
2007 |
2008 | //Get real width of page scroll-bar
2009 | w1 = $(window).width();
2010 |
2011 | H.addClass('fancybox-lock-test');
2012 |
2013 | w2 = $(window).width();
2014 |
2015 | H.removeClass('fancybox-lock-test');
2016 |
2017 | $("").appendTo("head");
2018 | });
2019 |
2020 | }(window, document, jQuery));
--------------------------------------------------------------------------------
/examples/sample-table.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/jquery.stickytable.css:
--------------------------------------------------------------------------------
1 | .sticky-table {
2 | max-width: 100%;
3 | max-height: 80vh;
4 | overflow: auto;
5 | border-top: 1px solid #ddd;
6 | border-bottom: 1px solid #ddd;
7 | padding: 0 !important;
8 | transition: width 2s;
9 | }
10 |
11 | .sticky-table, .sticky-table * {
12 | -webkit-transition: all 0s;
13 | -moz-transition: all 0s;
14 | -o-transition: all 0s;
15 | transition: all 0s;
16 | }
17 |
18 | .sticky-table table {
19 | margin-bottom: 0;
20 | width: 100%;
21 | max-width: 100%;
22 | border-spacing: 0;
23 | padding: 0 !important;
24 | border-collapse: collapse;
25 | }
26 |
27 | .sticky-table table tr.sticky-header th, .sticky-table table tr.sticky-header td,
28 | .sticky-table table tr.sticky-footer th, .sticky-table table tr.sticky-footer td {
29 | background-color: #fff;
30 | border-top: 0;
31 | position: relative;
32 | position: -webkit-sticky;
33 | position: -ms-sticky;
34 | position: sticky;
35 | outline: 1px solid #ddd;
36 | z-index: 5;
37 | }
38 | .sticky-table table tr.sticky-header th, .sticky-table table tr.sticky-header td {
39 | top: 0;
40 | }
41 | .sticky-table table tr.sticky-footer th, .sticky-table table tr.sticky-footer td {
42 | bottom: 0;
43 | }
44 |
45 | .sticky-table table td.sticky-cell, .sticky-table table th.sticky-cell,
46 | .sticky-table table td.sticky-cell-opposite, .sticky-table table th.sticky-cell-opposite {
47 | background-color: #fff;
48 | outline: 1px solid #ddd;
49 | position: relative;
50 | position: -webkit-sticky;
51 | position: -ms-sticky;
52 | position: sticky;
53 | z-index: 10;
54 | }
55 | .sticky-table.sticky-ltr-cells table td.sticky-cell, .sticky-table.sticky-ltr-cells table th.sticky-cell,
56 | .sticky-table.sticky-rtl-cells table td.sticky-cell-opposite, .sticky-table.sticky-rtl-cells table th.sticky-cell-opposite {
57 | left: 0
58 | }
59 | .sticky-table.sticky-rtl-cells table td.sticky-cell, .sticky-table.sticky-rtl-cells table th.sticky-cell,
60 | .sticky-table.sticky-ltr-cells table td.sticky-cell-opposite, .sticky-table.sticky-ltr-cells table th.sticky-cell-opposite {
61 | right: 0
62 | }
63 |
64 | .sticky-table table tr.sticky-header td.sticky-cell, .sticky-table table tr.sticky-header th.sticky-cell,
65 | .sticky-table table tr.sticky-header td.sticky-cell-opposite, .sticky-table table tr.sticky-header th.sticky-cell-opposite,
66 | .sticky-table table tr.sticky-footer td.sticky-cell, .sticky-table table tr.sticky-footer th.sticky-cell,
67 | .sticky-table table tr.sticky-footer td.sticky-cell-opposite, .sticky-table table tr.sticky-footer th.sticky-cell-opposite {
68 | z-index: 15;
69 | }
70 |
--------------------------------------------------------------------------------
/jquery.stickytable.js:
--------------------------------------------------------------------------------
1 | jQuery(document).on('stickyTable', function() {
2 | var positionStickySupport = (function() {
3 | var el = document.createElement('a'),
4 | mStyle = el.style;
5 | mStyle.cssText = "position:sticky;position:-webkit-sticky;position:-ms-sticky;";
6 | return mStyle.position.indexOf('sticky')!==-1;
7 | })();
8 |
9 | var scrollTypeRTL = (function() {
10 | var definer = $('
ABCD ').appendTo('body')[0],
11 | scrollTypeRTL = 'reverse';
12 |
13 | if (definer.scrollLeft > 0) {
14 | scrollTypeRTL = 'default';
15 | } else {
16 | definer.scrollLeft = 1;
17 | if (definer.scrollLeft === 0) {
18 | scrollTypeRTL = 'negative';
19 | }
20 | }
21 | $(definer).remove();
22 | return scrollTypeRTL;
23 | })();
24 |
25 | if(positionStickySupport) {
26 | var offset = 0;
27 | $(".sticky-table").each( function () {
28 | offset = 0;
29 | $(this).find("table tr.sticky-header").each( function () {
30 | $(this).find("th").css('top', offset);
31 | $(this).find("td").css('top', offset);
32 | offset += $(this).outerHeight();
33 | })
34 |
35 | offset = 0;
36 | $($(this).find("table tr.sticky-footer").get().reverse()).each( function () {
37 | $(this).find("th").css('bottom', offset);
38 | $(this).find("td").css('bottom', offset);
39 | offset += $(this).outerHeight();
40 | })
41 | })
42 |
43 | $(".sticky-ltr-cells table tr").each( function () {
44 | offset = 0;
45 | $(this).find(".sticky-cell").each( function () {
46 | $(this).css('left', offset);
47 | offset += $(this).outerWidth();
48 | })
49 |
50 | offset = 0;
51 | $($(this).find(".sticky-cell-opposite").get().reverse()).each( function () {
52 | $(this).css('right', offset);
53 | offset += $(this).outerWidth();
54 | })
55 | })
56 | } else {
57 | if(navigator.userAgent.match(/Trident\/7\./)) {
58 | $('.sticky-table').on("mousewheel", function (event) {
59 | event.preventDefault();
60 | var wd = event.originalEvent.wheelDelta;
61 | var csp = $(this).scrollTop();
62 | $(this).scrollTop(csp - wd);
63 | });
64 | }
65 |
66 | $(".sticky-table").scroll(function() {
67 | $(this).find("table tr.sticky-header th").css('top', $(this).scrollTop());
68 | $(this).find("table tr.sticky-header td").css('top', $(this).scrollTop());
69 | var maxScroll = $(this).find("table").prop("clientHeight") - $(this).prop("clientHeight");
70 | $(this).find("table tr.sticky-footer th").css('bottom', maxScroll - $(this).scrollTop());
71 | $(this).find("table tr.sticky-footer td").css('bottom', maxScroll - $(this).scrollTop());
72 | }).scroll();
73 |
74 | $(".sticky-ltr-cells").scroll(function() {
75 | $(this).find("table th.sticky-cell").css('left', $(this).scrollLeft());
76 | $(this).find("table td.sticky-cell").css('left', $(this).scrollLeft());
77 | var maxScroll = $(this).find("table").prop("clientWidth") - $(this).prop("clientWidth");
78 | $(this).find("table th.sticky-cell-opposite").css('right', maxScroll - $(this).scrollLeft());
79 | $(this).find("table td.sticky-cell-opposite").css('right', maxScroll - $(this).scrollLeft());
80 | }).scroll();
81 | }
82 | if($(".sticky-rtl-cells").length && !(positionStickySupport && scrollTypeRTL == 'negative')) {
83 | if(positionStickySupport) {
84 | $(".sticky-rtl-cells table th.sticky-cell").css('position', "relative");
85 | $(".sticky-rtl-cells table td.sticky-cell").css('position', "relative");
86 | $(".sticky-rtl-cells table th.sticky-cell-opposite").css('position', "relative");
87 | $(".sticky-rtl-cells table td.sticky-cell-opposite").css('position', "relative");
88 |
89 | $(".sticky-table").scroll(function() {
90 | $(this).find("table tr.sticky-header .sticky-cell").css('top', $(this).scrollTop());
91 | $(this).find("table tr.sticky-header .sticky-cell-opposite").css('top', $(this).scrollTop());
92 | var maxScroll = $(this).find("table").prop("clientHeight") - $(this).prop("clientHeight");
93 | $(this).find("table tr.sticky-footer .sticky-cell").css('bottom', maxScroll - $(this).scrollTop());
94 | $(this).find("table tr.sticky-footer .sticky-cell-opposite").css('bottom', maxScroll - $(this).scrollTop());
95 | }).scroll();
96 | }
97 | $(".sticky-rtl-cells").scroll(function() {
98 | var maxScroll = $(this).find("table").prop("clientWidth") - $(this).prop("clientWidth");
99 | switch(scrollTypeRTL) {
100 | case "default": // webKit Browsers
101 | $(this).find("table th.sticky-cell").css('right', maxScroll - $(this).scrollLeft());
102 | $(this).find("table td.sticky-cell").css('right', maxScroll - $(this).scrollLeft());
103 | $(this).find("table th.sticky-cell-opposite").css('left', $(this).scrollLeft());
104 | $(this).find("table td.sticky-cell-opposite").css('left', $(this).scrollLeft());
105 | break;
106 | case "negative": // Firefox, Opera
107 | $(this).find("table th.sticky-cell").css('right', $(this).scrollLeft() * -1);
108 | $(this).find("table td.sticky-cell").css('right', $(this).scrollLeft() * -1);
109 | $(this).find("table th.sticky-cell-opposite").css('left', maxScroll + $(this).scrollLeft());
110 | $(this).find("table td.sticky-cell-opposite").css('left', maxScroll + $(this).scrollLeft());
111 | break;
112 | case "reverse": // IE, Edge
113 | $(this).find("table th.sticky-cell").css('right', $(this).scrollLeft());
114 | $(this).find("table td.sticky-cell").css('right', $(this).scrollLeft());
115 | $(this).find("table th.sticky-cell-opposite").css('left', maxScroll - $(this).scrollLeft());
116 | $(this).find("table td.sticky-cell-opposite").css('left', maxScroll - $(this).scrollLeft());
117 | }
118 | }).scroll();
119 | }
120 |
121 | $( window ).resize(function() {
122 | $(".sticky-table").scroll();
123 | });
124 |
125 | });
126 | $( document ).ready(function(){
127 | $( document ).trigger( "stickyTable" );
128 | });
129 |
130 |
--------------------------------------------------------------------------------
/jquery.stickytable.min.css:
--------------------------------------------------------------------------------
1 | .sticky-table,.sticky-table table{max-width:100%;padding:0!important}.sticky-table{max-height:80vh;overflow:auto;border-top:1px solid #ddd;border-bottom:1px solid #ddd}.sticky-table,.sticky-table *{-webkit-transition:all 0s;-moz-transition:all 0s;-o-transition:all 0s;transition:all 0s}.sticky-table table{margin-bottom:0;width:100%;border-spacing:0;border-collapse:collapse}.sticky-table table tr.sticky-footer td,.sticky-table table tr.sticky-footer th,.sticky-table table tr.sticky-header td,.sticky-table table tr.sticky-header th{background-color:#fff;border-top:0;position:relative;position:-webkit-sticky;position:-ms-sticky;position:sticky;outline:#ddd solid 1px;z-index:5}.sticky-table table tr.sticky-header td,.sticky-table table tr.sticky-header th{top:0}.sticky-table table tr.sticky-footer td,.sticky-table table tr.sticky-footer th{bottom:0}.sticky-table table td.sticky-cell,.sticky-table table td.sticky-cell-opposite,.sticky-table table th.sticky-cell,.sticky-table table th.sticky-cell-opposite{background-color:#fff;outline:#ddd solid 1px;position:relative;position:-webkit-sticky;position:-ms-sticky;position:sticky;z-index:10}.sticky-table.sticky-ltr-cells table td.sticky-cell,.sticky-table.sticky-ltr-cells table th.sticky-cell,.sticky-table.sticky-rtl-cells table td.sticky-cell-opposite,.sticky-table.sticky-rtl-cells table th.sticky-cell-opposite{left:0}.sticky-table.sticky-ltr-cells table td.sticky-cell-opposite,.sticky-table.sticky-ltr-cells table th.sticky-cell-opposite,.sticky-table.sticky-rtl-cells table td.sticky-cell,.sticky-table.sticky-rtl-cells table th.sticky-cell{right:0}.sticky-table table tr.sticky-footer td.sticky-cell,.sticky-table table tr.sticky-footer td.sticky-cell-opposite,.sticky-table table tr.sticky-footer th.sticky-cell,.sticky-table table tr.sticky-footer th.sticky-cell-opposite,.sticky-table table tr.sticky-header td.sticky-cell,.sticky-table table tr.sticky-header td.sticky-cell-opposite,.sticky-table table tr.sticky-header th.sticky-cell,.sticky-table table tr.sticky-header th.sticky-cell-opposite{z-index:15}
--------------------------------------------------------------------------------
/jquery.stickytable.min.js:
--------------------------------------------------------------------------------
1 | jQuery(document).on("stickyTable",function(){var t,s=((t=document.createElement("a").style).cssText="position:sticky;position:-webkit-sticky;position:-ms-sticky;",-1!==t.position.indexOf("sticky")),i=function(){var t=$('ABCD ').appendTo("body")[0],s="reverse";return t.scrollLeft>0?s="default":(t.scrollLeft=1,0===t.scrollLeft&&(s="negative")),$(t).remove(),s}();if(s){var e=0;$(".sticky-table").each(function(){e=0,$(this).find("table tr.sticky-header").each(function(){$(this).find("th").css("top",e),$(this).find("td").css("top",e),e+=$(this).outerHeight()}),e=0,$($(this).find("table tr.sticky-footer").get().reverse()).each(function(){$(this).find("th").css("bottom",e),$(this).find("td").css("bottom",e),e+=$(this).outerHeight()})}),$(".sticky-ltr-cells table tr").each(function(){e=0,$(this).find(".sticky-cell").each(function(){$(this).css("left",e),e+=$(this).outerWidth()}),e=0,$($(this).find(".sticky-cell-opposite").get().reverse()).each(function(){$(this).css("right",e),e+=$(this).outerWidth()})})}else navigator.userAgent.match(/Trident\/7\./)&&$(".sticky-table").on("mousewheel",function(t){t.preventDefault();var s=t.originalEvent.wheelDelta,i=$(this).scrollTop();$(this).scrollTop(i-s)}),$(".sticky-table").scroll(function(){$(this).find("table tr.sticky-header th").css("top",$(this).scrollTop()),$(this).find("table tr.sticky-header td").css("top",$(this).scrollTop());var t=$(this).find("table").prop("clientHeight")-$(this).prop("clientHeight");$(this).find("table tr.sticky-footer th").css("bottom",t-$(this).scrollTop()),$(this).find("table tr.sticky-footer td").css("bottom",t-$(this).scrollTop())}).scroll(),$(".sticky-ltr-cells").scroll(function(){$(this).find("table th.sticky-cell").css("left",$(this).scrollLeft()),$(this).find("table td.sticky-cell").css("left",$(this).scrollLeft());var t=$(this).find("table").prop("clientWidth")-$(this).prop("clientWidth");$(this).find("table th.sticky-cell-opposite").css("right",t-$(this).scrollLeft()),$(this).find("table td.sticky-cell-opposite").css("right",t-$(this).scrollLeft())}).scroll();!$(".sticky-rtl-cells").length||s&&"negative"==i||(s&&($(".sticky-rtl-cells table th.sticky-cell").css("position","relative"),$(".sticky-rtl-cells table td.sticky-cell").css("position","relative"),$(".sticky-rtl-cells table th.sticky-cell-opposite").css("position","relative"),$(".sticky-rtl-cells table td.sticky-cell-opposite").css("position","relative"),$(".sticky-table").scroll(function(){$(this).find("table tr.sticky-header .sticky-cell").css("top",$(this).scrollTop()),$(this).find("table tr.sticky-header .sticky-cell-opposite").css("top",$(this).scrollTop());var t=$(this).find("table").prop("clientHeight")-$(this).prop("clientHeight");$(this).find("table tr.sticky-footer .sticky-cell").css("bottom",t-$(this).scrollTop()),$(this).find("table tr.sticky-footer .sticky-cell-opposite").css("bottom",t-$(this).scrollTop())}).scroll()),$(".sticky-rtl-cells").scroll(function(){var t=$(this).find("table").prop("clientWidth")-$(this).prop("clientWidth");switch(i){case"default":$(this).find("table th.sticky-cell").css("right",t-$(this).scrollLeft()),$(this).find("table td.sticky-cell").css("right",t-$(this).scrollLeft()),$(this).find("table th.sticky-cell-opposite").css("left",$(this).scrollLeft()),$(this).find("table td.sticky-cell-opposite").css("left",$(this).scrollLeft());break;case"negative":$(this).find("table th.sticky-cell").css("right",-1*$(this).scrollLeft()),$(this).find("table td.sticky-cell").css("right",-1*$(this).scrollLeft()),$(this).find("table th.sticky-cell-opposite").css("left",t+$(this).scrollLeft()),$(this).find("table td.sticky-cell-opposite").css("left",t+$(this).scrollLeft());break;case"reverse":$(this).find("table th.sticky-cell").css("right",$(this).scrollLeft()),$(this).find("table td.sticky-cell").css("right",$(this).scrollLeft()),$(this).find("table th.sticky-cell-opposite").css("left",t-$(this).scrollLeft()),$(this).find("table td.sticky-cell-opposite").css("left",t-$(this).scrollLeft())}}).scroll()),$(window).resize(function(){$(".sticky-table").scroll()})}),$(document).ready(function(){$(document).trigger("stickyTable")});
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-sticky-table-plugin",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "jquery": {
8 | "version": "3.5.1",
9 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
10 | "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-sticky-table-plugin",
3 | "version": "1.0.0",
4 | "description": "jquery.stickytable is a lightweight plugin to help developers have fixed rows or columns in a ` |
---|