Przeglądaj źródła

Vendorize angular-inview

Contains a patch for page visiblity support
Danilo Bargen 8 lat temu
rodzic
commit
14330b70fa

+ 0 - 1
dist/package.sh

@@ -74,7 +74,6 @@ targets=(
     angular-translate/dist/angular-translate.min.js
     angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js
     angular-translate/dist/angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.min.js
-    angular-inview/angular-inview.js
     angular-messages/angular-messages.min.js
     sdp/sdp.js
 )

+ 1 - 1
gather-licenses.sh

@@ -6,7 +6,7 @@ LICENSE_FILES=(
     'angular' 'node_modules/angular/LICENSE.md'
     'angular-animate' 'node_modules/angular-animate/LICENSE.md'
     'angular-aria' 'node_modules/angular-aria/LICENSE.md'
-    'angular-inview' 'node_modules/angular-inview/LICENSE'
+    'angular-inview' 'public/libs/angular-inview/LICENSE'
     'angular-material' 'node_modules/angular-material/LICENSE'
     'angular-messages' 'node_modules/angular-messages/LICENSE.md'
     'angular-qrcode' '.licenses/angular-qrcode'

+ 1 - 1
index.html

@@ -109,7 +109,7 @@
     <script src="node_modules/angular-ui-router/release/angular-ui-router.min.js?v=[[VERSION]]"></script>
     <script src="libs/emojione/emojione.min.js?v=[[VERSION]]"></script>
     <script src="node_modules/angularjs-scroll-glue/src/scrollglue.js?v=[[VERSION]]"></script>
-    <script src="node_modules/angular-inview/angular-inview.js?v=[[VERSION]]"></script>
+    <script src="libs/angular-inview/angular-inview.js?v=[[VERSION]]"></script>
 
     <!-- Translation -->
     <script src="node_modules/messageformat/messageformat.min.js?v=[[VERSION]]"></script>

+ 0 - 5
npm-shrinkwrap.json

@@ -89,11 +89,6 @@
       "from": "angular-aria@>=1.5.10 <1.6.0",
       "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.5.11.tgz"
     },
-    "angular-inview": {
-      "version": "2.1.0",
-      "from": "angular-inview@>=2.1.0 <2.2.0",
-      "resolved": "https://registry.npmjs.org/angular-inview/-/angular-inview-2.1.0.tgz"
-    },
     "angular-material": {
       "version": "1.1.1",
       "from": "angular-material@>=1.1.1 <1.2.0",

+ 0 - 1
package.json

@@ -36,7 +36,6 @@
     "angular": "~1.5.10",
     "angular-animate": "~1.5.10",
     "angular-aria": "~1.5.10",
-    "angular-inview": "~2.1.0",
     "angular-material": "~1.1.1",
     "angular-messages": "~1.6.1",
     "angular-qrcode": "~6.2.1",

+ 21 - 0
public/libs/angular-inview/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Nicola Peduzzi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 3 - 0
public/libs/angular-inview/README.md

@@ -0,0 +1,3 @@
+angular-inview library with pull request 122 applied (commit e7c57e031489b2e7c2aaeed6dff09455495fcb51)
+
+https://github.com/thenikso/angular-inview/pull/122

+ 388 - 0
public/libs/angular-inview/angular-inview.js

@@ -0,0 +1,388 @@
+// # Angular-Inview
+// - Author: [Nicola Peduzzi](https://github.com/thenikso)
+// - Repository: https://github.com/thenikso/angular-inview
+// - Install with: `npm install angular-inview`
+// - Version: **2.2.0**
+(function() {
+'use strict';
+
+// An [angular.js](https://angularjs.org) directive to evaluate an expression if
+// a DOM element is or not in the current visible browser viewport.
+// Use it in your AngularJS app by including the javascript and requireing it:
+//
+// `angular.module('myApp', ['angular-inview'])`
+var angularInviewModule = angular.module('angular-inview', [])
+
+// ## in-view directive
+//
+// ### Usage
+// ```html
+// <any in-view="{expression}" [in-view-options="{object}"]></any>
+// ```
+.directive('inView', ['$parse', inViewDirective])
+
+// ## in-view-container directive
+.directive('inViewContainer', inViewContainerDirective);
+
+// ## Implementation
+function inViewDirective ($parse) {
+  return {
+    // Evaluate the expression passet to the attribute `in-view` when the DOM
+    // element is visible in the viewport.
+    restrict: 'A',
+    require: '?^^inViewContainer',
+    link: function inViewDirectiveLink (scope, element, attrs, container) {
+      // in-view-options attribute can be specified with an object expression
+      // containing:
+      //   - `offset`: An array of values to offset the element position.
+      //     Offsets are expressed as arrays of 4 numbers [top, right, bottom, left].
+      //     Like CSS, you can also specify only 2 numbers [top/bottom, left/right].
+      //     Instead of numbers, some array elements can be a string with a percentage.
+      //     Positive numbers are offsets outside the element rectangle and
+      //     negative numbers are offsets to the inside.
+      //   - `viewportOffset`: Like the element offset but appied to the viewport.
+      //   - `generateDirection`: Indicate if the `direction` information should
+      //     be included in `$inviewInfo` (default false).
+      //   - `generateParts`: Indicate if the `parts` information should
+      //     be included in `$inviewInfo` (default false).
+      //   - `throttle`: Specify a number of milliseconds by which to limit the
+      //     number of incoming events.
+      var options = {};
+      if (attrs.inViewOptions) {
+        options = scope.$eval(attrs.inViewOptions);
+      }
+      if (options.offset) {
+        options.offset = normalizeOffset(options.offset);
+      }
+      if (options.viewportOffset) {
+        options.viewportOffset = normalizeOffset(options.viewportOffset);
+      }
+
+      // Build reactive chain from an initial event
+      var viewportEventSignal = signalSingle({ type: 'initial' })
+
+      // Merged with the window events
+      .merge(signalFromEvent(window, 'checkInView click ready wheel mousewheel DomMouseScroll MozMousePixelScroll resize scroll touchmove mouseup keydown'));
+
+      // Merged with the page visibility events
+      if (options.considerPageVisibility) {
+        viewportEventSignal = viewportEventSignal.merge(signalFromEvent(document, 'visibilitychange'));
+      }
+
+      // Merge with container's events signal
+      if (container) {
+        viewportEventSignal = viewportEventSignal.merge(container.eventsSignal);
+      }
+
+      // Throttle if option specified
+      if (options.throttle) {
+        viewportEventSignal = viewportEventSignal.throttle(options.throttle);
+      }
+
+      // Map to viewport intersection and in-view informations
+      var inviewInfoSignal = viewportEventSignal
+
+      // Inview information structure contains:
+      //   - `inView`: a boolean value indicating if the element is
+      //     visible in the viewport;
+      //   - `changed`: a boolean value indicating if the inview status
+      //     changed after the last event;
+      //   - `event`: the event that initiated the in-view check;
+      .map(function(event) {
+        var viewportRect;
+        if (container) {
+          viewportRect = container.getViewportRect();
+          // TODO merge with actual window!
+        } else {
+          viewportRect = getViewportRect();
+        }
+        viewportRect = offsetRect(viewportRect, options.viewportOffset);
+        var elementRect = offsetRect(element[0].getBoundingClientRect(), options.offset);
+        var isVisible = !!(element[0].offsetWidth || element[0].offsetHeight || element[0].getClientRects().length);
+        var documentVisible = !options.considerPageVisibility || document.visibilityState === 'visible' || document.hidden === false;
+        var info = {
+          inView: documentVisible && isVisible && intersectRect(elementRect, viewportRect),
+          event: event,
+          element: element,
+          elementRect: elementRect,
+          viewportRect: viewportRect
+        };
+        // Add inview parts
+        if (options.generateParts && info.inView) {
+          info.parts = {};
+          info.parts.top = elementRect.top >= viewportRect.top;
+          info.parts.left = elementRect.left >= viewportRect.left;
+          info.parts.bottom = elementRect.bottom <= viewportRect.bottom;
+          info.parts.right = elementRect.right <= viewportRect.right;
+        }
+        return info;
+      })
+
+      // Add the changed information to the inview structure.
+      .scan({}, function (lastInfo, newInfo) {
+        // Add inview direction info
+        if (options.generateDirection && newInfo.inView && lastInfo.elementRect) {
+          newInfo.direction = {
+            horizontal: newInfo.elementRect.left - lastInfo.elementRect.left,
+            vertical: newInfo.elementRect.top - lastInfo.elementRect.top
+          };
+        }
+        // Calculate changed flag
+        newInfo.changed =
+          newInfo.inView !== lastInfo.inView ||
+          !angular.equals(newInfo.parts, lastInfo.parts) ||
+          !angular.equals(newInfo.direction, lastInfo.direction);
+        return newInfo;
+      })
+
+      // Filters only informations that should be forwarded to the callback
+      .filter(function (info) {
+        // Don't forward if no relevant infomation changed
+        if (!info.changed) {
+          return false;
+        }
+        // Don't forward if not initially in-view
+        if (info.event.type === 'initial' && !info.inView) {
+          return false;
+        }
+        return true;
+      });
+
+      // Execute in-view callback
+      var inViewExpression = $parse(attrs.inView);
+      var dispose = inviewInfoSignal.subscribe(function (info) {
+        scope.$applyAsync(function () {
+          inViewExpression(scope, {
+            '$inview': info.inView,
+            '$inviewInfo': info
+          });
+        });
+      });
+
+      // Dispose of reactive chain
+      scope.$on('$destroy', dispose);
+    }
+  }
+}
+
+function inViewContainerDirective () {
+  return {
+    restrict: 'A',
+    controller: ['$element', function ($element) {
+      this.element = $element;
+      this.eventsSignal = signalFromEvent($element, 'scroll');
+      this.getViewportRect = function () {
+        return $element[0].getBoundingClientRect();
+      };
+    }]
+  }
+}
+
+// ## Utilities
+
+function getViewportRect () {
+  var result = {
+    top: 0,
+    left: 0,
+    width: window.innerWidth,
+    right: window.innerWidth,
+    height: window.innerHeight,
+    bottom: window.innerHeight
+  };
+  if (result.height) {
+    return result;
+  }
+  var mode = document.compatMode;
+  if (mode === 'CSS1Compat') {
+    result.width = result.right = document.documentElement.clientWidth;
+    result.height = result.bottom = document.documentElement.clientHeight;
+  } else {
+    result.width = result.right = document.body.clientWidth;
+    result.height = result.bottom = document.body.clientHeight;
+  }
+  return result;
+}
+
+function intersectRect (r1, r2) {
+  return !(r2.left > r1.right ||
+           r2.right < r1.left ||
+           r2.top > r1.bottom ||
+           r2.bottom < r1.top);
+}
+
+function normalizeOffset (offset) {
+  if (!angular.isArray(offset)) {
+    return [offset, offset, offset, offset];
+  }
+  if (offset.length == 2) {
+    return offset.concat(offset);
+  }
+  else if (offset.length == 3) {
+    return offset.concat([offset[1]]);
+  }
+  return offset;
+}
+
+function offsetRect (rect, offset) {
+  if (!offset) {
+    return rect;
+  }
+  var offsetObject = {
+    top: isPercent(offset[0]) ? (parseFloat(offset[0]) * rect.height) : offset[0],
+    right: isPercent(offset[1]) ? (parseFloat(offset[1]) * rect.width) : offset[1],
+    bottom: isPercent(offset[2]) ? (parseFloat(offset[2]) * rect.height) : offset[2],
+    left: isPercent(offset[3]) ? (parseFloat(offset[3]) * rect.width) : offset[3]
+  };
+  // Note: ClientRect object does not allow its properties to be written to therefore a new object has to be created.
+  return {
+    top: rect.top - offsetObject.top,
+    left: rect.left - offsetObject.left,
+    bottom: rect.bottom + offsetObject.bottom,
+    right: rect.right + offsetObject.right,
+    height: rect.height + offsetObject.top + offsetObject.bottom,
+    width: rect.width + offsetObject.left + offsetObject.right
+  };
+}
+
+function isPercent (n) {
+  return angular.isString(n) && n.indexOf('%') > 0;
+}
+
+// ## QuickSignal FRP
+// A quick and dirty implementation of Rx to have a streamlined code in the
+// directives.
+
+// ### QuickSignal
+//
+// - `didSubscribeFunc`: a function receiving a `subscriber` as described below
+//
+// Usage:
+//     var mySignal = new QuickSignal(function(subscriber) { ... })
+function QuickSignal (didSubscribeFunc) {
+  this.didSubscribeFunc = didSubscribeFunc;
+}
+
+// Subscribe to a signal and consume the steam of data.
+//
+// Returns a function that can be called to stop the signal stream of data and
+// perform cleanup.
+//
+// A `subscriber` is a function that will be called when a new value arrives.
+// a `subscriber.$dispose` property can be set to a function to be called uppon
+// disposal. When setting the `$dispose` function, the previously set function
+// should be chained.
+QuickSignal.prototype.subscribe = function (subscriber) {
+  this.didSubscribeFunc(subscriber);
+  var dispose = function () {
+    if (subscriber.$dispose) {
+      subscriber.$dispose();
+      subscriber.$dispose = null;
+    }
+  }
+  return dispose;
+}
+
+QuickSignal.prototype.map = function (f) {
+  var s = this;
+  return new QuickSignal(function (subscriber) {
+    subscriber.$dispose = s.subscribe(function (nextValue) {
+      subscriber(f(nextValue));
+    });
+  });
+};
+
+QuickSignal.prototype.filter = function (f) {
+  var s = this;
+  return new QuickSignal(function (subscriber) {
+    subscriber.$dispose = s.subscribe(function (nextValue) {
+      if (f(nextValue)) {
+        subscriber(nextValue);
+      }
+    });
+  });
+};
+
+QuickSignal.prototype.scan = function (initial, scanFunc) {
+  var s = this;
+  return new QuickSignal(function (subscriber) {
+    var last = initial;
+    subscriber.$dispose = s.subscribe(function (nextValue) {
+      last = scanFunc(last, nextValue);
+      subscriber(last);
+    });
+  });
+}
+
+QuickSignal.prototype.merge = function (signal) {
+  return signalMerge(this, signal);
+};
+
+QuickSignal.prototype.throttle = function (threshhold) {
+  var s = this, last, deferTimer;
+  return new QuickSignal(function (subscriber) {
+    var chainDisposable = s.subscribe(function () {
+      var now = +new Date,
+          args = arguments;
+      if (last && now < last + threshhold) {
+        clearTimeout(deferTimer);
+        deferTimer = setTimeout(function () {
+          last = now;
+          subscriber.apply(null, args);
+        }, threshhold);
+      } else {
+        last = now;
+        subscriber.apply(null, args);
+      }
+    });
+    subscriber.$dispose = function () {
+      clearTimeout(deferTimer);
+      if (chainDisposable) chainDisposable();
+    };
+  });
+};
+
+function signalMerge () {
+  var signals = arguments;
+  return new QuickSignal(function (subscriber) {
+    var disposables = [];
+    for (var i = signals.length - 1; i >= 0; i--) {
+      disposables.push(signals[i].subscribe(function () {
+        subscriber.apply(null, arguments);
+      }));
+    }
+    subscriber.$dispose = function () {
+      for (var i = disposables.length - 1; i >= 0; i--) {
+        if (disposables[i]) disposables[i]();
+      }
+    }
+  });
+}
+
+// Returns a signal from DOM events of a target.
+function signalFromEvent (target, event) {
+  return new QuickSignal(function (subscriber) {
+    var handler = function (e) {
+      subscriber(e);
+    };
+    var el = angular.element(target);
+    el.on(event, handler);
+    subscriber.$dispose = function () {
+      el.off(event, handler);
+    };
+  });
+}
+
+function signalSingle (value) {
+  return new QuickSignal(function (subscriber) {
+    setTimeout(function() { subscriber(value); });
+  });
+}
+
+// Module loaders exports
+if (typeof define === 'function' && define.amd) {
+  define(['angular'], angularInviewModule);
+} else if (typeof module !== 'undefined' && module && module.exports) {
+  module.exports = angularInviewModule;
+}
+
+})();