~blake-rouse/maas/is-importing-2.1

« back to all changes in this revision

Viewing changes to src/maasserver/static/js/angular/3rdparty/sticky.js

  • Committer: LaMont Jones
  • Date: 2016-12-07 12:59:10 UTC
  • mfrom: (5561 2.1)
  • mto: This revision was merged to the branch mainline in revision 5563.
  • Revision ID: lamont@canonical.com-20161207125910-fow7gg8v9bo0s1iq
merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * ngSticky - https://github.com/d-oliveros/ngSticky
 
3
 *
 
4
 * A simple, pure javascript (No jQuery required!) AngularJS directive
 
5
 * to make elements stick when scrolling down.
 
6
 *
 
7
 * Credits: https://github.com/d-oliveros/ngSticky/graphs/contributors
 
8
 */
 
9
(function() {
 
10
  'use strict';
 
11
 
 
12
  var module = angular.module('sticky', []);
 
13
 
 
14
  /**
 
15
   * Directive: sticky
 
16
   */
 
17
  module.directive('sticky', ['$window', '$timeout', function($window, $timeout) {
 
18
      return {
 
19
        restrict: 'A', // this directive can only be used as an attribute.
 
20
        scope: {
 
21
          disabled: '=disabledSticky'
 
22
        },
 
23
        link: function linkFn($scope, $elem, $attrs) {
 
24
 
 
25
          // Initial scope
 
26
          var scrollableNodeTagName = 'sticky-scroll';
 
27
          var initialPosition = $elem.css('position');
 
28
          var initialStyle = $elem.attr('style') || '';
 
29
          var stickyBottomLine = 0;
 
30
          var isSticking = false;
 
31
          var onStickyHeighUnbind;
 
32
          var originalInitialCSS;
 
33
          var originalOffset;
 
34
          var placeholder;
 
35
          var stickyLine;
 
36
          var initialCSS;
 
37
 
 
38
          // Optional Classes
 
39
          var stickyClass = $attrs.stickyClass || '';
 
40
          var unstickyClass = $attrs.unstickyClass || '';
 
41
          var bodyClass = $attrs.bodyClass || '';
 
42
          var bottomClass = $attrs.bottomClass || '';
 
43
 
 
44
          // Find scrollbar
 
45
          var scrollbar = deriveScrollingViewport ($elem);
 
46
 
 
47
          // Define elements
 
48
          var windowElement = angular.element($window);
 
49
          var scrollbarElement = angular.element(scrollbar);
 
50
          var $body = angular.element(document.body);
 
51
 
 
52
          // Resize callback
 
53
          var $onResize = function () {
 
54
            if ($scope.$root && !$scope.$root.$$phase) {
 
55
              $scope.$apply(onResize);
 
56
            } else {
 
57
              onResize();
 
58
            }
 
59
          };
 
60
 
 
61
          // Define options
 
62
          var usePlaceholder = ($attrs.usePlaceholder !== 'false');
 
63
          var anchor = $attrs.anchor === 'bottom' ? 'bottom' : 'top';
 
64
          var confine = ($attrs.confine === 'true');
 
65
 
 
66
          // flag: can react to recalculating the initial CSS dimensions later
 
67
          // as link executes prematurely. defaults to immediate checking
 
68
          var isStickyLayoutDeferred = $attrs.isStickyLayoutDeferred !== undefined
 
69
            ? ($attrs.isStickyLayoutDeferred === 'true')
 
70
            : false;
 
71
 
 
72
          // flag: is sticky content constantly observed for changes.
 
73
          // Should be true if content uses ngBind to show text
 
74
          // that may vary in size over time
 
75
          var isStickyLayoutWatched = $attrs.isStickyLayoutWatched !== undefined
 
76
          ? ($attrs.isStickyLayoutWatched === 'true')
 
77
          : true;
 
78
 
 
79
 
 
80
          var offset = $attrs.offset
 
81
            ? parseInt ($attrs.offset.replace(/px;?/, ''))
 
82
            : 0;
 
83
 
 
84
          /**
 
85
           * Trigger to initialize the sticky
 
86
           * Because of the `timeout()` method for the call of
 
87
           * @type {Boolean}
 
88
           */
 
89
          var shouldInitialize = true;
 
90
 
 
91
          /**
 
92
           * Initialize Sticky
 
93
           */
 
94
          function initSticky() {
 
95
 
 
96
            if (shouldInitialize) {
 
97
 
 
98
              // Listeners
 
99
              scrollbarElement.on('scroll', checkIfShouldStick);
 
100
              windowElement.on('resize', $onResize);
 
101
 
 
102
              memorizeDimensions(); // remember sticky's layout dimensions
 
103
 
 
104
              // Setup watcher on digest and change
 
105
              $scope.$watch(onDigest, onChange);
 
106
 
 
107
              // Clean up
 
108
              $scope.$on('$destroy', onDestroy);
 
109
              shouldInitialize = false;
 
110
            }
 
111
          };
 
112
 
 
113
          /**
 
114
           * need to recall sticky's DOM attributes (make sure layout has occured)
 
115
           */
 
116
          function memorizeDimensions() {
 
117
            // immediate assignment, but there is the potential for wrong values if content not ready
 
118
            initialCSS = $scope.getInitialDimensions();
 
119
 
 
120
            // option to calculate the dimensions when layout is 'ready'
 
121
            if (isStickyLayoutDeferred) {
 
122
 
 
123
              // logic: when this directive link() runs before the content has had a chance to layout on browser, height could be 0
 
124
              if (!$elem[0].getBoundingClientRect().height) {
 
125
 
 
126
                onStickyHeighUnbind = $scope.$watch(
 
127
                    function() {
 
128
                      return $elem.height();
 
129
                    },
 
130
 
 
131
                    // state change: sticky content's height set
 
132
                    function onStickyContentLayoutInitialHeightSet(newValue, oldValue) {
 
133
                      if (newValue > 0) {
 
134
                        // now can memorize
 
135
                        initialCSS = $scope.getInitialDimensions();
 
136
 
 
137
                        if (!isStickyLayoutWatched) {
 
138
                          // preference was to do just a one-time async watch on the sticky's content; now stop watching
 
139
                          onStickyHeighUnbind();
 
140
                        }
 
141
                      }
 
142
                    }
 
143
               );
 
144
              }
 
145
            }
 
146
          }
 
147
 
 
148
          /**
 
149
           * Determine if the element should be sticking or not.
 
150
           */
 
151
          var checkIfShouldStick = function() {
 
152
            if ($scope.disabled === true || mediaQueryMatches()) {
 
153
              if (isSticking) unStickElement();
 
154
              return false;
 
155
            }
 
156
 
 
157
            // What's the document client top for?
 
158
            var scrollbarPosition = scrollbarYPos();
 
159
            var shouldStick;
 
160
 
 
161
            if (anchor === 'top') {
 
162
              if (confine === true) {
 
163
                shouldStick = scrollbarPosition > stickyLine && scrollbarPosition <= stickyBottomLine;
 
164
              } else {
 
165
                shouldStick = scrollbarPosition > stickyLine;
 
166
              }
 
167
            } else {
 
168
              shouldStick = scrollbarPosition <= stickyLine;
 
169
            }
 
170
 
 
171
            // Switch the sticky mode if the element crosses the sticky line
 
172
            // $attrs.stickLimit - when it's equal to true it enables the user
 
173
            // to turn off the sticky function when the elem height is
 
174
            // bigger then the viewport
 
175
            var closestLine = getClosest (scrollbarPosition, stickyLine, stickyBottomLine);
 
176
 
 
177
            if (shouldStick && !shouldStickWithLimit ($attrs.stickLimit) && !isSticking) {
 
178
              stickElement (closestLine);
 
179
            } else if (!shouldStick && isSticking) {
 
180
              unStickElement(closestLine, scrollbarPosition);
 
181
            } else if (confine && !shouldStick) {
 
182
              // If we are confined to the parent, refresh, and past the stickyBottomLine
 
183
              // We should 'remember' the original offset and unstick the element which places it at the stickyBottomLine
 
184
              originalOffset = elementsOffsetFromTop ($elem[0]);
 
185
              unStickElement (closestLine, scrollbarPosition);
 
186
            }
 
187
          };
 
188
 
 
189
          /**
 
190
           * determine the respective node that handles scrolling, defaulting to browser window
 
191
           */
 
192
          function deriveScrollingViewport(stickyNode) {
 
193
            // derive relevant scrolling by ascending the DOM tree
 
194
            var match =findAncestorTag (scrollableNodeTagName, stickyNode);
 
195
            return (match.length === 1) ? match[0] : $window;
 
196
          }
 
197
 
 
198
          /**
 
199
           * since jqLite lacks closest(), this is a pseudo emulator (by tag name)
 
200
           */
 
201
          function findAncestorTag(tag, context) {
 
202
            var m = []; // nodelist container
 
203
            var n = context.parent(); // starting point
 
204
            var p;
 
205
 
 
206
            do {
 
207
              var node = n[0]; // break out of jqLite
 
208
              // limit DOM territory
 
209
              if (node.nodeType !== 1) {
 
210
                break;
 
211
              }
 
212
 
 
213
              // success
 
214
              if (node.tagName.toUpperCase() === tag.toUpperCase()) {
 
215
                return n;
 
216
              }
 
217
 
 
218
              p = n.parent();
 
219
              n = p; // set to parent
 
220
            } while (p.length !== 0);
 
221
 
 
222
            return m; // empty set
 
223
          }
 
224
 
 
225
          /**
 
226
           * Seems to be undocumented functionality
 
227
           */
 
228
          function shouldStickWithLimit(shouldApplyWithLimit) {
 
229
            return shouldApplyWithLimit === 'true'
 
230
              ? ($window.innerHeight - ($elem[0].offsetHeight + parseInt(offset)) < 0)
 
231
              : false;
 
232
          }
 
233
 
 
234
          /**
 
235
           * Finds the closest value from a set of numbers in an array.
 
236
           */
 
237
          function getClosest(scrollTop, stickyLine, stickyBottomLine) {
 
238
            var closest = 'top';
 
239
            var topDistance = Math.abs(scrollTop - stickyLine);
 
240
            var bottomDistance = Math.abs(scrollTop - stickyBottomLine);
 
241
 
 
242
            if (topDistance > bottomDistance) {
 
243
              closest = 'bottom';
 
244
            }
 
245
 
 
246
            return closest;
 
247
          }
 
248
 
 
249
          /**
 
250
           * Unsticks the element
 
251
           */
 
252
          function unStickElement(fromDirection) {
 
253
            if (initialStyle) {
 
254
              $elem.attr('style', initialStyle);
 
255
            }
 
256
            isSticking = false;
 
257
 
 
258
            initialCSS.width = $scope.getInitialDimensions().width;
 
259
 
 
260
            $body.removeClass(bodyClass);
 
261
            $elem.removeClass(stickyClass);
 
262
            $elem.addClass(unstickyClass);
 
263
 
 
264
            if (fromDirection === 'top') {
 
265
              $elem.removeClass(bottomClass);
 
266
 
 
267
              $elem
 
268
                .css('z-index', 10)
 
269
                .css('width', initialCSS.width)
 
270
                .css('top', initialCSS.top)
 
271
                .css('position', initialCSS.position)
 
272
                .css('left', initialCSS.cssLeft)
 
273
                .css('margin-top', initialCSS.marginTop)
 
274
                .css('height', initialCSS.height);
 
275
            } else if (fromDirection === 'bottom' && confine === true) {
 
276
              $elem.addClass(bottomClass);
 
277
 
 
278
              // It's possible to page down page and skip the 'stickElement'.
 
279
              // In that case we should create a placeholder so the offsets don't get off.
 
280
              createPlaceholder();
 
281
 
 
282
              $elem
 
283
                .css('z-index', 10)
 
284
                .css('width', initialCSS.width)
 
285
                .css('top', '')
 
286
                .css('bottom', 0)
 
287
                .css('position', 'absolute')
 
288
                .css('left', initialCSS.cssLeft)
 
289
                .css('margin-top', initialCSS.marginTop)
 
290
                .css('margin-bottom', initialCSS.marginBottom)
 
291
                .css('height', initialCSS.height);
 
292
            }
 
293
 
 
294
            if (placeholder && fromDirection === anchor) {
 
295
              placeholder.remove();
 
296
            }
 
297
          }
 
298
 
 
299
          /**
 
300
           * Sticks the element
 
301
           */
 
302
          function stickElement(closestLine) {
 
303
            // Set sticky state
 
304
            isSticking = true;
 
305
            $timeout(function() {
 
306
              initialCSS.offsetWidth = $elem[0].offsetWidth;
 
307
            }, 0);
 
308
            $body.addClass(bodyClass);
 
309
            $elem.removeClass(unstickyClass);
 
310
            $elem.removeClass(bottomClass);
 
311
            $elem.addClass(stickyClass);
 
312
 
 
313
            createPlaceholder();
 
314
 
 
315
            $elem
 
316
              .css('z-index', '10')
 
317
              .css('width', $elem[0].offsetWidth + 'px')
 
318
              .css('position', 'fixed')
 
319
              .css('left', $elem.css('left').replace('px', '') + 'px')
 
320
              .css(anchor, (offset + elementsOffsetFromTop (scrollbar)) + 'px')
 
321
              .css('margin-top', 0);
 
322
 
 
323
            if (anchor === 'bottom') {
 
324
              $elem.css('margin-bottom', 0);
 
325
            }
 
326
          }
 
327
 
 
328
          /**
 
329
           * Clean up directive
 
330
           */
 
331
          var onDestroy = function() {
 
332
            scrollbarElement.off('scroll', checkIfShouldStick);
 
333
            windowElement.off('resize', $onResize);
 
334
 
 
335
            $onResize = null;
 
336
 
 
337
            $body.removeClass(bodyClass);
 
338
 
 
339
            if (placeholder) {
 
340
              placeholder.remove();
 
341
            }
 
342
          };
 
343
 
 
344
          /**
 
345
           * Updates on resize.
 
346
           */
 
347
          function onResize() {
 
348
            unStickElement (anchor);
 
349
            checkIfShouldStick();
 
350
          }
 
351
 
 
352
          /**
 
353
           * Triggered on load / digest cycle
 
354
           * return `0` if the DOM element is hidden
 
355
           */
 
356
          var onDigest = function() {
 
357
            if ($scope.disabled === true) {
 
358
              return unStickElement();
 
359
            }
 
360
            var offsetFromTop = elementsOffsetFromTop ($elem[0]);
 
361
            if (offsetFromTop === 0) {
 
362
              return offsetFromTop;
 
363
            }
 
364
            if (anchor === 'top') {
 
365
              return (originalOffset || offsetFromTop) - elementsOffsetFromTop (scrollbar) + scrollbarYPos();
 
366
            } else {
 
367
              return offsetFromTop - scrollbarHeight() + $elem[0].offsetHeight + scrollbarYPos();
 
368
            }
 
369
          };
 
370
 
 
371
          /**
 
372
           * Triggered on change
 
373
           */
 
374
          var onChange = function (newVal, oldVal) {
 
375
 
 
376
            /**
 
377
             * Indicate if the DOM element is showed, or not
 
378
             * @type {boolean}
 
379
             */
 
380
            var elemIsShowed = !!newVal;
 
381
 
 
382
            /**
 
383
             * Indicate if the DOM element was showed, or not
 
384
             * @type {boolean}
 
385
             */
 
386
            var elemWasHidden = !oldVal;
 
387
            var valChange = (newVal !== oldVal || typeof stickyLine === 'undefined');
 
388
            var notSticking = (!isSticking && !isBottomedOut());
 
389
 
 
390
            if (valChange && notSticking && newVal > 0 && elemIsShowed) {
 
391
              stickyLine = newVal - offset;
 
392
              //Update dimensions of sticky element when is showed
 
393
              if (elemIsShowed && elemWasHidden) {
 
394
                $scope.updateStickyContentUpdateDimensions($elem[0].offsetWidth, $elem[0].offsetHeight);
 
395
              }
 
396
              // IF the sticky is confined, we want to make sure the parent is relatively positioned,
 
397
              // otherwise it won't bottom out properly
 
398
              if (confine) {
 
399
                $elem.parent().css({
 
400
                  'position': 'relative'
 
401
                });
 
402
              }
 
403
 
 
404
              // Get Parent height, so we know when to bottom out for confined stickies
 
405
              var parent = $elem.parent()[0];
 
406
 
 
407
              // Offset parent height by the elements height, if we're not using a placeholder
 
408
              var parentHeight = parseInt (parent.offsetHeight) - (usePlaceholder ? 0 : $elem[0].offsetHeight);
 
409
 
 
410
              // and now lets ensure we adhere to the bottom margins
 
411
              // TODO: make this an attribute? Maybe like ignore-margin?
 
412
              var marginBottom = parseInt ($elem.css('margin-bottom').replace(/px;?/, '')) || 0;
 
413
 
 
414
              // specify the bottom out line for the sticky to unstick
 
415
              var elementsDistanceFromTop = elementsOffsetFromTop ($elem[0]);
 
416
              var parentsDistanceFromTop = elementsOffsetFromTop (parent)
 
417
              var scrollbarDistanceFromTop = elementsOffsetFromTop (scrollbar);
 
418
 
 
419
              var elementsDistanceFromScrollbarStart = elementsDistanceFromTop - scrollbarDistanceFromTop;
 
420
              var elementsDistanceFromBottom = parentsDistanceFromTop + parentHeight - elementsDistanceFromTop;
 
421
 
 
422
              stickyBottomLine = elementsDistanceFromScrollbarStart
 
423
                + elementsDistanceFromBottom
 
424
                - $elem[0].offsetHeight
 
425
                - marginBottom
 
426
                - offset
 
427
                + +scrollbarYPos();
 
428
 
 
429
              checkIfShouldStick();
 
430
            }
 
431
          };
 
432
 
 
433
          /**
 
434
           * Helper Functions
 
435
           */
 
436
 
 
437
          /**
 
438
           * Create a placeholder
 
439
           */
 
440
          function createPlaceholder() {
 
441
            if (usePlaceholder) {
 
442
              // Remove the previous placeholder
 
443
              if (placeholder) {
 
444
                placeholder.remove();
 
445
              }
 
446
 
 
447
              placeholder = angular.element('<div>');
 
448
              var elementsHeight = $elem[0].offsetHeight;
 
449
              var computedStyle = $elem[0].currentStyle || window.getComputedStyle($elem[0]);
 
450
              elementsHeight += parseInt(computedStyle.marginTop, 10);
 
451
              elementsHeight += parseInt(computedStyle.marginBottom, 10);
 
452
              elementsHeight += parseInt(computedStyle.borderTopWidth, 10);
 
453
              elementsHeight += parseInt(computedStyle.borderBottomWidth, 10);
 
454
              placeholder.css('height', $elem[0].offsetHeight + 'px');
 
455
 
 
456
              $elem.after(placeholder);
 
457
            }
 
458
          }
 
459
 
 
460
          /**
 
461
           * Are we bottomed out of the parent element?
 
462
           */
 
463
          function isBottomedOut() {
 
464
            if (confine && scrollbarYPos() > stickyBottomLine) {
 
465
              return true;
 
466
            }
 
467
 
 
468
            return false;
 
469
          }
 
470
 
 
471
          /**
 
472
           * Fetch top offset of element
 
473
           */
 
474
          function elementsOffsetFromTop(element) {
 
475
            var offset = 0;
 
476
 
 
477
            if (element.getBoundingClientRect) {
 
478
              offset = element.getBoundingClientRect().top;
 
479
            }
 
480
 
 
481
            return offset;
 
482
          }
 
483
 
 
484
          /**
 
485
           * Retrieves top scroll distance
 
486
           */
 
487
          function scrollbarYPos() {
 
488
            var position;
 
489
 
 
490
            if (typeof scrollbar.scrollTop !== 'undefined') {
 
491
              position = scrollbar.scrollTop;
 
492
            } else if (typeof scrollbar.pageYOffset !== 'undefined') {
 
493
              position = scrollbar.pageYOffset;
 
494
            } else {
 
495
              position = document.documentElement.scrollTop;
 
496
            }
 
497
 
 
498
            return position;
 
499
          }
 
500
 
 
501
          /**
 
502
           * Determine scrollbar's height
 
503
           */
 
504
          function scrollbarHeight() {
 
505
            var height;
 
506
 
 
507
            if (scrollbarElement[0] instanceof HTMLElement) {
 
508
              // isn't bounding client rect cleaner than insane regex mess?
 
509
              height = $window.getComputedStyle(scrollbarElement[0], null)
 
510
                  .getPropertyValue('height')
 
511
                  .replace(/px;?/, '');
 
512
            } else {
 
513
              height = $window.innerHeight;
 
514
            }
 
515
 
 
516
            return parseInt (height) || 0;
 
517
          }
 
518
 
 
519
          /**
 
520
           * Checks if the media matches
 
521
           */
 
522
          function mediaQueryMatches() {
 
523
            var mediaQuery = $attrs.mediaQuery || false;
 
524
            var matchMedia = $window.matchMedia;
 
525
 
 
526
            return mediaQuery && !(matchMedia ('(' + mediaQuery + ')').matches || matchMedia (mediaQuery).matches);
 
527
          }
 
528
 
 
529
          /**
 
530
           * Get more accurate CSS values
 
531
           */
 
532
          function getCSS($el, prop){
 
533
            var el = $el[0],
 
534
                computed = window.getComputedStyle(el),
 
535
                prevDisplay = computed.display,
 
536
                val;
 
537
 
 
538
            // hide the element so that we can get original css
 
539
            // values instead of computed values
 
540
            el.style.display = "none";
 
541
 
 
542
            // NOTE - computed style declaration object is a reference
 
543
            // to the element's CSSStyleDeclaration, so it will always
 
544
            // reflect the current style of the element
 
545
            val = computed[prop];
 
546
 
 
547
            // restore previous display value
 
548
            el.style.display = prevDisplay;
 
549
 
 
550
            return val;
 
551
          }
 
552
 
 
553
          // public accessors for the controller to hitch into. Helps with external API access
 
554
          $scope.getElement = function() { return $elem; };
 
555
          $scope.getScrollbar = function() { return scrollbar; };
 
556
          $scope.getInitialCSS = function() { return initialCSS; };
 
557
          $scope.getAnchor = function() { return anchor; };
 
558
          $scope.isSticking = function() { return isSticking; };
 
559
          $scope.getOriginalInitialCSS = function() { return originalInitialCSS; };
 
560
          // pass through aliases
 
561
          $scope.processUnStickElement = function(anchor) { unStickElement(anchor)};
 
562
          $scope.processCheckIfShouldStick =function() { checkIfShouldStick(); };
 
563
 
 
564
          /**
 
565
           * set the dimensions for the defaults of the content block occupied by the sticky element
 
566
           */
 
567
          $scope.getInitialDimensions = function() {
 
568
            return {
 
569
              zIndex: $elem.css('z-index'),
 
570
              top: $elem.css('top'),
 
571
              position: initialPosition, // revert to true initial state
 
572
              marginTop: $elem.css('margin-top'),
 
573
              marginBottom: $elem.css('margin-bottom'),
 
574
              cssLeft: getCSS($elem, 'left'),
 
575
              width: $elem[0].offsetWidth,
 
576
              height: $elem.css('height')
 
577
            };
 
578
          };
 
579
 
 
580
          /**
 
581
           * only change content box dimensions
 
582
           */
 
583
          $scope.updateStickyContentUpdateDimensions = function(width, height) {
 
584
            if (width && height) {
 
585
              initSticky();
 
586
              initialCSS.width = width + 'px';
 
587
              initialCSS.height = height + 'px';
 
588
            }
 
589
          };
 
590
 
 
591
          // ----------- configuration -----------
 
592
 
 
593
          $timeout(function() {
 
594
            originalInitialCSS = $scope.getInitialDimensions(); // preserve a copy
 
595
            // Init the directive
 
596
            initSticky();
 
597
          },0);
 
598
        },
 
599
 
 
600
        /**
 
601
         * +++++++++ public APIs+++++++++++++
 
602
         */
 
603
        controller: ['$scope', '$window', function($scope, $window) {
 
604
 
 
605
          /**
 
606
           * integration method allows for an outside client to reset the pinned state back to unpinned.
 
607
           * Useful for when refreshing the scrollable DIV content completely
 
608
           * if newWidth and newHeight integer values are not supplied then function will make a best guess
 
609
           */
 
610
          this.resetLayout = function(newWidth, newHeight) {
 
611
 
 
612
            var scrollbar = $scope.getScrollbar(),
 
613
                initialCSS = $scope.getInitialCSS(),
 
614
                anchor = $scope.getAnchor();
 
615
 
 
616
            function _resetScrollPosition() {
 
617
 
 
618
              // reset means content is scrolled to anchor position
 
619
              if (anchor === 'top') {
 
620
                // window based scroller
 
621
                if (scrollbar === $window) {
 
622
                  $window.scrollTo(0, 0);
 
623
                  // DIV based sticky scroller
 
624
                } else {
 
625
                  if (scrollbar.scrollTop > 0) {
 
626
                    scrollbar.scrollTop = 0;
 
627
                  }
 
628
                }
 
629
              }
 
630
              // todo: need bottom use case
 
631
            }
 
632
 
 
633
            // only if pinned, force unpinning, otherwise height is inadvertently reset to 0
 
634
            if ($scope.isSticking()) {
 
635
              $scope.processUnStickElement (anchor);
 
636
              $scope.processCheckIfShouldStick();
 
637
            }
 
638
            // remove layout-affecting attribures that were modified by this sticky
 
639
            $scope.getElement().css({ 'width': '', 'height': '', 'position': '', 'top': '', zIndex: '' });
 
640
            // model resets
 
641
            initialCSS.position = $scope.getOriginalInitialCSS().position; // revert to original state
 
642
            delete initialCSS.offsetWidth; // stickElement affected
 
643
 
 
644
            // use this directive element's as default, if no measurements passed in
 
645
            if (newWidth === undefined && newHeight === undefined) {
 
646
              var e_bcr = $scope.getElement()[0].getBoundingClientRect();
 
647
              newWidth = e_bcr.width;
 
648
              newHeight = e_bcr.height;
 
649
            }
 
650
 
 
651
            // update model with new dimensions (if supplied from client's own measurement)
 
652
            $scope.updateStickyContentUpdateDimensions(newWidth, newHeight); // update layout dimensions only
 
653
 
 
654
            _resetScrollPosition();
 
655
          };
 
656
 
 
657
          /**
 
658
           * return a reference to the scrolling element (window or DIV with overflow)
 
659
           */
 
660
          this.getScrollbar = function() {
 
661
            return $scope.getScrollbar();
 
662
          };
 
663
        }]
 
664
      };
 
665
    }]
 
666
 );
 
667
 
 
668
  // Shiv: matchMedia
 
669
  window.matchMedia = window.matchMedia || (function() {
 
670
      var warning = 'angular-sticky: This browser does not support ' +
 
671
        'matchMedia, therefore the minWidth option will not work on ' +
 
672
        'this browser. Polyfill matchMedia to fix this issue.';
 
673
 
 
674
      if (window.console && console.warn) {
 
675
        console.warn(warning);
 
676
      }
 
677
 
 
678
      return function() {
 
679
        return {
 
680
          matches: true
 
681
        };
 
682
      };
 
683
    }());
 
684
}());