├── .editorconfig
├── .gitignore
├── .jshintrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── bower.json
├── build
├── angular-scroll-watch.js
└── angular-scroll-watch.min.js
├── example
├── README.md
├── assets
│ ├── digest-count.js
│ ├── edit-on-plunker.js
│ └── lesshat-prefixed.less
├── digest-sync
│ ├── index.html
│ ├── style.css
│ └── style.less
├── infinite-scroll
│ ├── index.html
│ ├── style.css
│ └── style.less
├── locals
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-broadcast-through-emit
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-broadcast
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-class-with-ng-repeat
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-class
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-stage
│ ├── index.html
│ ├── style.css
│ └── style.less
├── sw-style-touch
│ ├── index.html
│ ├── style.css
│ └── style.less
└── sw-style
│ ├── index.html
│ ├── style.css
│ └── style.less
├── gulpfile.js
├── images
├── how_much_angular_do_you_want.gif
└── lovely_slides.gif
├── index.html
├── package.json
└── src
└── angular-scroll-watch.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | insert_final_newline = true
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | *.sublime-*
4 | .tern-port
5 | .DS_Store
6 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "undef": true,
3 | "predef": ["angular"]
4 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v0.6.1
4 |
5 | - Fix package name typo
6 |
7 | ## v0.6.0
8 |
9 | - Publish to NPM ([#8](https://github.com/pc035860/angular-scroll-watch/issues/8))
10 | - Support browserify/webpack/requirejs with UMD
11 |
12 | ## v0.5.5
13 |
14 | - Fix `sw-stage` destroy issue ([#6](https://github.com/pc035860/angular-scroll-watch/issues/6))
15 |
16 | ## v0.5.4
17 |
18 | - Update bower main path ([#3](https://github.com/pc035860/angular-scroll-watch/pull/3))
19 |
20 | ## v0.5.3
21 |
22 | - Support AngularJS 1.3 class animations ([#2](https://github.com/pc035860/angular-scroll-watch/issues/2))
23 |
24 | ## v0.5.2
25 |
26 | - Prevent inifinite digest on `scroll-watch`
27 |
28 | ## v0.5.1
29 |
30 | - Fix `sw-stage` annotation error
31 |
32 | ## v0.5.0
33 |
34 | - New directive: `sw-stage`
35 | - Support more locals: `$height`, `$offsetTop`, `$stageTop`
36 |
37 | ## v0.4.0
38 |
39 | - Rename the **digest hook** config to `digestSync`
40 |
41 | ## v0.3.0
42 |
43 | - Introduce **digest hook** as `digest` in `scroll-watch` configs
44 |
45 | ## v0.2.0
46 |
47 | - New directive attribute: `sw-broadcast`
48 |
49 | ## v0.1.1
50 |
51 | - Make a debounced scroll value update in `scrollWatchService.addConfig()`
52 | - Correctly remove the config on element destruction
53 |
54 | ## v0.1.0
55 |
56 | - First release
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Chih-Hsuan Fan
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 | # angular-scroll-watch [](https://gitter.im/pc035860/angular-scroll-watch?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2 |
3 | Scroll-aware AngularJS with ease.
4 |
5 |
6 |
7 | #### Features
8 |
9 | - Pure AngularJS, no dependencies
10 | - **style** and **class** directives with scrolling locals
11 | - Supports multiple **stages**
12 | - Triggers scope digest only when needed
13 | - Of course it utilizes [requestAnimationFrame](http://www.html5rocks.com/en/tutorials/speed/animations/)
14 |
15 | #### Examples
16 |
17 | Scroll them to see the effects!
18 |
19 | - [How much angular do you want? (`sw-class` with `ng-repeat`)](http://pc035860.github.io/angular-scroll-watch/example/sw-class-with-ng-repeat/)
20 | - [Lovely slides (`sw-broadcast`)](http://pc035860.github.io/angular-scroll-watch/example/sw-broadcast/)
21 | - [Two controls on the shield (`sw-stage`)](http://pc035860.github.com/angular-scroll-watch/example/sw-stage/)
22 |
23 | Check out the [example directory](example/) for a full list of examples.
24 |
25 | ## Requirements
26 |
27 | AngularJS 1.2+
28 |
29 | ## Getting started
30 |
31 | Include the `angular-scroll-watch` module with AngularJS script in your page.
32 |
33 | ```html
34 |
35 |
36 | ```
37 |
38 | Add `pc035860.scrollWatch` to your app module's dependency.
39 |
40 | ```js
41 | angular.module('myApp', ['pc035860.scrollWatch']);
42 | ```
43 |
44 | ### Install with Bower
45 |
46 | ```sh
47 | bower install angular-scroll-watch
48 | ```
49 |
50 | ### Install with npm
51 |
52 | ```sh
53 | npm install angular-scroll-watch
54 | ```
55 |
56 | ## Usage
57 |
58 | ### scroll-watch
59 |
60 | **Type**: `expression`
61 |
62 | Base directive to specify a scroll-watch configuration. **Required for any watching activity.**
63 |
64 | `scroll-watch` should be used at least one of these directives: `sw-style`, `sw-class`, `sw-broadcast` to take effect, since itself is just a configuration directive.
65 |
66 | ```html
67 |
69 |
70 | ```
71 |
72 | #### Options
73 |
74 | Name | Type | Description | Required
75 | --- | --- | --- | :---:
76 | from | Number | Watch-range starting point. Can be a positive or a negative (calculated from bottom to top) value. Note that `from`'s visual value (**scrollTop**) must be higher than `to`. | Yes
77 | to | Number | Watch-range starting point. Can be a positive or a negative (calculated from bottom to top) value. Note that `to`'s visual value (**scrollTop**) musts be lower than `from`. | Yes
78 | stage | String | Specify the stage name to watch for scrolling. Stages are defined via `sw-stage`. If no stage is specified, default to browser window. | No
79 | digestSync | Boolean | Normally, `scroll-watch` only reevaluate watchs on `scroll` event fired. Setting `digestSync` to `true` will force `scroll-watch` to do the reevaluation everytime the binded scope gets digested. | No
80 |
81 | #### Examples
82 |
83 | - [All examples listed](example/)
84 |
85 |
86 | ### sw-style
87 |
88 | **Type**: `expression`
89 |
90 | Provides basically the same function with [built-in `ng-style`](https://docs.angularjs.org/api/ng/directive/ngStyle).
91 |
92 | `sw-style` gets reevaluated when the target stage firse `scroll` event or the scope it belongs to get digested (available with `digestSync` option set to `true`).
93 |
94 | There are couple of **locals** available in the expression. See [Locals](#locals) section for more information.
95 |
96 | ```html
97 |
99 |
100 | ```
101 |
102 | #### Examples
103 |
104 | - [`sw-style` basic](http://pc035860.github.io/angular-scroll-watch/example/sw-style/)
105 | - [`sw-style` touch-enabled](http://pc035860.github.io/angular-scroll-watch/example/sw-style-touch/)
106 | - [Digest sync](http://pc035860.github.com/angular-scroll-watch/example/digest-sync/)
107 |
108 |
109 | ### sw-class
110 |
111 | **Type**: `expression`
112 |
113 | Provides basically the same function with [built-in `ng-class`](https://docs.angularjs.org/api/ng/directive/ngClass). All the animation goodies added after AngularJS 1.2 are also supported.
114 |
115 | `sw-class` gets reevaluated when the target stage fires `scroll` event or the scope it belongs to get digested (available with `digestSync` option set to `true`).
116 |
117 | There are couple of **locals** available in the expression. See [Locals](#locals) section for more information.
118 |
119 | ```html
120 |
127 |
128 | ```
129 |
130 | #### Examples
131 |
132 | - [`sw-class` basic](http://pc035860.github.com/angular-scroll-watch/example/sw-class/)
133 | - [`sw-class` with `ng-repeat`](http://pc035860.github.com/angular-scroll-watch/example/sw-class-with-ng-repeat/)
134 |
135 |
136 | ### sw-broadcast
137 |
138 | **Type**: `expression`
139 |
140 | `$broadcast`(or `$emit`) certain event when specified condition expression result changes from `false` to `true` or from `true` to `false`.
141 |
142 | **Note that conditions must be written as String rather than Expression.**
143 |
144 | ```html
145 |
149 |
150 | ```
151 |
152 | By default, all the events `$broadcast`(or `$emit`) by `sw-broadcast` will be **inside the digest loop**. From time to time, you might need the event to be `$broadcast`(or `$emit`) on every stage `scroll`. Setting the condition to `true` will do the work, and no longer trigger the scope digest due to performance consideration.
153 |
154 | ```html
155 |
159 |
160 | ```
161 |
162 | #### The event
163 |
164 | We then receive the event with `$scope.$on`.
165 |
166 | ```js
167 | $scope.$on('event name', function ($evt, active, locals) {
168 | /**
169 | * active
170 | *
171 | * The evaluation result of the condition.
172 | * Will be `null` when used with "keep firing" events.
173 | */
174 |
175 | /**
176 | * locals
177 | *
178 | * See the Locals section for more information.
179 | */
180 | });
181 | ```
182 |
183 | #### Special options
184 |
185 | To cover various use cases, `sw-broadcast` comes with serveral special options. **They are all optional.**
186 |
187 | Name | Type | Description |
188 | --- | --- | ---
189 | $rootScope | Boolean | `$broadcast`(or `$emit`) the event from `$rootScope`. Default to `false`.
190 | $emit | Boolean | Use `$emit` instead of `$broadcast`. Default to `false`.
191 |
192 | ```html
193 |
199 |
200 |
201 | ```
202 |
203 | #### Examples
204 |
205 | - [`sw-broadcast` basic](http://pc035860.github.com/angular-scroll-watch/example/sw-broadcast/)
206 | - [`sw-broadcast` through `$emit`](http://pc035860.github.com/angular-scroll-watch/example/sw-broadcast-through-emit/)
207 | - [Locals](http://pc035860.github.com/angular-scroll-watch/example/locals/)
208 | - [Infinite scroll](http://pc035860.github.com/angular-scroll-watch/example/infinite-scroll/)
209 |
210 |
211 | ### sw-stage
212 |
213 | **Type**: `string` (interpolation-ready)
214 |
215 | `sw-stage` let you specify the scrolling element (the container) to watch with a customized name.
216 |
217 | A default stage named `pc035860` (Ya!!), which is the browser window, will always be presented. (And will be used if you don't specify the `stage` option in `scroll-watch`.)
218 |
219 | Basically there's no restriction on the DOM structure of `scroll-watch` and `sw-stage`, even the directive creation order doesn't matter.
220 |
221 | ```html
222 |
227 |
228 |
229 |
232 | ```
233 |
234 | #### Examples
235 |
236 | - [`sw-stage` basic](http://pc035860.github.io/angular-scroll-watch/example/sw-stage/)
237 | - [Locals](http://pc035860.github.io/angular-scroll-watch/example/locals/)
238 |
239 |
240 | ### Locals
241 |
242 | **Locals** here means a set of locally available variables inside our `sw-style`, `sw-class`, `sw-broadcast` expressions, which can be very useful when we're implmenting various effects.
243 |
244 | Their values depend on which stage your expression is watching (specified in `scroll-watch`'s `stage`) and where you're `scroll-watch` located in DOM.
245 |
246 | **All locals are presented as Number.**
247 |
248 | Name | Description
249 | --- | ---
250 | $positive | Scrolled value in pixel.
251 | $negative | Scrolled value in pixel, but calculated from the stage bottom. This is a negative number.
252 | $progress | Scrolling progress. Ranged from `0` to `1`.
253 | $percentage | Scrolling progress presented in percentage. Ranged from `0` to `100`.
254 | $direction | Scrolling direction. `1` means from top to bottom. `-1` means from bottom to top.
255 | $height | The watcher(`scroll-watch`) element's DOM height.
256 | $offsetTop | The watcher(`scroll-watch`) element's **overall top value**.
257 | $stageTop | The watcher(`scroll-watch`) element's **relative top value to the stage**. **This value is only presented when the watcher is a children of its stage.**
258 |
259 | #### Examples
260 |
261 | - [Locals](http://pc035860.github.io/angular-scroll-watch/example/locals/)
262 | - [All the others listed](example/)
263 |
264 |
265 |
266 | ## Development
267 |
268 | Thie module uses [gulp.js](http://gulpjs.com/) for development tasks.
269 |
270 | ### Setup
271 |
272 | Install all the required node packages.
273 |
274 | ```sh
275 | # Install node packages
276 | npm install
277 | ```
278 |
279 | ### Gulp tasks
280 |
281 | ```sh
282 | # Lint the source file
283 | gulp lint
284 |
285 | # Build
286 | gulp build
287 |
288 | # Watch the source file for auto-build
289 | gulp watch
290 |
291 |
292 | # Serve the example at http://localhost:9000
293 | # Gulp will also watch for source/example changes
294 | gulp example
295 | ```
296 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-scroll-watch",
3 | "version": "0.5.5",
4 | "description": "Basic scroll-aware directives for AngularJS.",
5 | "main": "build/angular-scroll-watch.js",
6 | "ignore": [
7 | "**/.*",
8 | "node_modules",
9 | "gulpfile.js",
10 | "package.json",
11 | "test",
12 | "tests",
13 | "index.html"
14 | ],
15 | "dependencies": {},
16 | "devDependencies": {}
17 | }
18 |
--------------------------------------------------------------------------------
/build/angular-scroll-watch.js:
--------------------------------------------------------------------------------
1 | /*! angular-scroll-watch
2 | version: 0.6.1
3 | build date: 2016-2-13
4 | author: [object Object]
5 | https://github.com/pc035860/angular-scroll-watch.git */
6 | /* jshint node:true */
7 | /* global define */
8 | (function (root, factory) {
9 | if (typeof exports === "object" || (typeof module === "object" && module.exports)) {
10 | module.exports = factory(require("angular"));
11 | } else if (typeof define === "function" && define.amd) {
12 | define(["angular"], factory);
13 | } else {
14 | root.returnExports = factory(root.angular);
15 | }
16 | }(this, function (angular) {
17 |
18 | var MODULE_NAME = 'pc035860.scrollWatch';
19 |
20 | var DIR_STYLE = 'swStyle',
21 | DIR_CLASS = 'swClass',
22 | DIR_BROADCAST = 'swBroadcast',
23 | DIR_STAGE = 'swStage';
24 |
25 | var STAGE_NAME_DEFAULT = 'pc035860';
26 |
27 | var CACHE_ID_STAGE_POOL = 'scrollWatch.stages';
28 |
29 | angular.module(MODULE_NAME, [])
30 |
31 | .factory('scrollWatchStageFactory', ["$window", "$document", "$parse", "$log", "$rootScope", "$animate", function (
32 | $window, $document, $parse, $log, $rootScope, $animate
33 | ) {
34 | // ref: http://davidwalsh.name/function-debounce
35 | var debounce = function (func, wait, immediate) {
36 | var timeout;
37 | return function() {
38 | var context = this, args = arguments;
39 | $window.clearTimeout(timeout);
40 | timeout = $window.setTimeout(function() {
41 | timeout = null;
42 | if (!immediate) func.apply(context, args);
43 | }, wait);
44 | if (immediate && !timeout) func.apply(context, args);
45 | };
46 | };
47 |
48 | var requestAnimFrame = (function () {
49 | return $window.requestAnimationFrame ||
50 | $window.webkitRequestAnimationFrame ||
51 | $window.mozRequestAnimationFrame ||
52 | $window.oRequestAnimationFrame ||
53 | $window.msRequestAnimationFrame ||
54 | function(/* function */ callback, /* DOMElement */ element){
55 | $window.setTimeout(callback, 1000 / 60);
56 | };
57 | })();
58 |
59 | var $win = angular.element($window);
60 |
61 | /**
62 | * Stage class
63 | */
64 | var Stage = function (name, $elm) {
65 | this.init(name, $elm);
66 | };
67 |
68 | var p = Stage.prototype;
69 |
70 | p.name = null;
71 | p.element = null;
72 | p.configs = null;
73 | p._configId = 0;
74 | p._binded = false;
75 |
76 | p.init = function (name, $elm) {
77 | this.name = name;
78 | this.element = $elm || null;
79 |
80 | this.scrollHandler = this._digest.bind(this);
81 | this._digestDebounced = debounce(this._digest, 50);
82 |
83 | this._digestDebounced();
84 | };
85 |
86 | p.setElement = function ($elm) {
87 | this.element = $elm;
88 |
89 | if (this.configs !== null && !this._binded) {
90 | this._bind(this.element);
91 | }
92 |
93 | this._digestDebounced();
94 | };
95 |
96 | p.clearElement = function () {
97 | if (this._binded) {
98 | this._unbind(this.element);
99 | }
100 | this.element = null;
101 | };
102 |
103 | p.addConfig = function (config) {
104 | angular.forEach(['target', 'from', 'to'], function (key) {
105 | if (angular.isUndefined(config[key])) {
106 | throw new Error('`'+ key +'` should be provided');
107 | }
108 | });
109 |
110 | if (this.configs === null) {
111 | this.configs = {};
112 |
113 | if (this.element !== null) {
114 | this._bind(this.element);
115 | }
116 | }
117 |
118 | this._configId++;
119 |
120 | if (config.styleExpr) {
121 | config.styleGetter = $parse(config.styleExpr);
122 | }
123 | if (config.classExpr) {
124 | config.classGetter = $parse(config.classExpr);
125 | }
126 | if (config.brdcstExpr) {
127 | var buf = config.scope.$eval(config.brdcstExpr);
128 |
129 | if (buf.$rootScope) {
130 | config.brdcstScope = $rootScope;
131 | delete buf.$rootScope;
132 | }
133 | else {
134 | config.brdcstScope = config.scope;
135 | }
136 |
137 | if (buf.$emit) {
138 | config.brdcstIsEmit = true;
139 | delete buf.$emit;
140 | }
141 | else {
142 | config.brdcstIsEmit = false;
143 | }
144 |
145 | config.brdcstList = [];
146 | angular.forEach(buf, function (expr, event) {
147 | var pack = {
148 | event: event
149 | };
150 |
151 | if (!angular.isString(expr)) {
152 | pack.always = true;
153 | }
154 | else {
155 | pack.condition = $parse(expr);
156 | pack.wasActive = null;
157 | }
158 |
159 | config.brdcstList.push(pack);
160 | });
161 | }
162 |
163 | this.configs[this._configId] = config;
164 |
165 | this._digestDebounced();
166 |
167 | return this._configId;
168 | };
169 |
170 | p.removeConfig = function (configId) {
171 | if (this.configs && this.configs[configId]) {
172 | delete this.configs[configId];
173 |
174 | if (objectSize(this.configs) === 0) {
175 | this.configs = null;
176 |
177 | if (this.element !== null) {
178 | this._unbind(this.element);
179 | }
180 | }
181 | }
182 | };
183 |
184 | p.digest = function (configId) {
185 | this._digest(null, configId);
186 | };
187 |
188 | p.destroy = function () {
189 | this.clearElement();
190 | this.configs = null;
191 | this.scrollHandler = null;
192 | this._digestDebounced = null;
193 | };
194 |
195 | p.couldDestroy = function () {
196 | return this.element === null && this.configs === null;
197 | };
198 |
199 | p._isDefault = function () {
200 | return this.element[0] === $window;
201 | };
202 |
203 | p._getElementMetrics = function ($elm) {
204 | var rect, metrics, scrollTop, elm, stageTop;
205 |
206 | elm = $elm[0];
207 | rect = elm.getBoundingClientRect();
208 | scrollTop = this._scrollTop();
209 |
210 | metrics = {
211 | offsetTop: rect.top + scrollTop
212 | };
213 |
214 | if (this._isDefault()) {
215 | stageTop = metrics.offsetTop;
216 | }
217 | else {
218 | stageTop = this._traverseStageTop(elm);
219 | }
220 |
221 | if (angular.isDefined(stageTop) && stageTop !== null) {
222 | metrics.stageTop = stageTop;
223 | }
224 |
225 | return metrics;
226 | };
227 |
228 | p._traverseStageTop = function (elm) {
229 | var stageElm = this.element[0],
230 | top = 0, cursor, progress;
231 |
232 | var updateProgress = function (cursor, progress) {
233 | if (!progress) {
234 | progress = {};
235 | }
236 | progress.parentNode = cursor.offsetParent;
237 | progress.offsetTop = cursor.offsetTop;
238 | progress.hitStage = progress.parentNode === stageElm;
239 | return progress;
240 | };
241 |
242 | var c = 0;
243 |
244 | cursor = elm;
245 | progress = updateProgress(cursor);
246 |
247 | do {
248 | cursor = cursor.parentNode || cursor;
249 |
250 | if (progress.parentNode === cursor) {
251 | top += progress.offsetTop;
252 |
253 | if (progress.hitStage) {
254 | return top;
255 | }
256 |
257 | progress = updateProgress(cursor, progress);
258 | }
259 | else if (cursor === stageElm) {
260 | return top + progress.offsetTop - stageElm.offsetTop;
261 | }
262 |
263 | if (++c >= 10) {
264 | break;
265 | }
266 | } while (cursor.tagName !== 'BODY' || elm === cursor);
267 |
268 | return null;
269 | };
270 |
271 | p._contentHeight = function () {
272 | if (this._isDefault()) {
273 | var doc = $document[0].documentElement,
274 | body = $document[0].body;
275 |
276 | return Math.max(
277 | body.scrollHeight, doc.scrollHeight,
278 | body.offsetHeight, doc.offsetHeight,
279 | doc.clientHeight
280 | );
281 | }
282 | return this.element[0].scrollHeight;
283 | };
284 |
285 | p._containerHeight = function () {
286 | if (this._isDefault()) {
287 | var h1 = $document[0].documentElement.clientHeight,
288 | h2 = $window.innerHeight;
289 | if (h1 > h2) {
290 | return h2;
291 | }
292 | return h1;
293 | }
294 | return this.element[0].offsetHeight;
295 | };
296 |
297 | p._scrollTop = function () {
298 | if (this._isDefault()) {
299 | return $window.pageYOffset;
300 | }
301 | return this.element[0].scrollTop;
302 | };
303 |
304 | p._digest = (function () {
305 | var reBpCond = /((?:>|<)?=?)\s*?((?:-(?!p))|(?:p(?!-)))?(\d+)/;
306 |
307 | var _handleStyle,
308 |
309 | _handleClass, _addClasses, _removeClasses,
310 | _digestClassCounts, _updateClasses,
311 |
312 | _handleBrdcst, _apply;
313 |
314 | /**
315 | * Style related functions
316 | */
317 | _handleStyle = function (locals, config) {
318 | config.target.css(config.styleGetter(config.scope, locals));
319 | };
320 |
321 | /**
322 | * Class related functions
323 | */
324 | _addClasses = function (config, classes) {
325 | var attr = config.attr;
326 | var newClasses = _digestClassCounts(config, classes, 1);
327 | attr.$addClass(newClasses);
328 | };
329 | _removeClasses = function (config, classes) {
330 | var attr = config.attr;
331 | var newClasses = _digestClassCounts(config, classes, -1);
332 | attr.$removeClass(newClasses);
333 | };
334 | _digestClassCounts = function (config, classes, count) {
335 | var element = config.target;
336 | var classCounts = element.data('$classCounts') || {};
337 | var classesToUpdate = [];
338 | angular.forEach(classes, function (className) {
339 | if (count > 0 || classCounts[className]) {
340 | classCounts[className] = (classCounts[className] || 0) + count;
341 | if (classCounts[className] === +(count > 0)) {
342 | classesToUpdate.push(className);
343 | }
344 | }
345 | });
346 | element.data('$classCounts', classCounts);
347 | return classesToUpdate.join(' ');
348 | };
349 | _updateClasses = function (config, oldClasses, newClasses) {
350 | var element = config.target;
351 | var toAdd = arrayDifference(newClasses, oldClasses);
352 | var toRemove = arrayDifference(oldClasses, newClasses);
353 | toRemove = _digestClassCounts(config, toRemove, -1);
354 | toAdd = _digestClassCounts(config, toAdd, 1);
355 |
356 | if (toAdd.length === 0) {
357 | $animate.removeClass(element, toRemove);
358 | } else if (toRemove.length === 0) {
359 | $animate.addClass(element, toAdd);
360 | } else {
361 | $animate.setClass(element, toAdd, toRemove);
362 | }
363 | config.scope.$digest();
364 | };
365 | _handleClass = function (locals, config) {
366 | var newVal = config.classGetter(config.scope, locals),
367 | oldVal = config._oldClassVal;
368 | var newClasses = arrayClasses(newVal || []);
369 | if (!oldVal) {
370 | _addClasses(config, newClasses);
371 | }
372 | else if (!angular.equals(newVal, oldVal)) {
373 | var oldClasses = arrayClasses(oldVal);
374 | _updateClasses(config, oldClasses, newClasses);
375 | }
376 | config._oldClassVal = shallowCopy(newVal);
377 | };
378 |
379 | /**
380 | * Broadcast condition -> event
381 | */
382 | _apply = function (scope, fn) {
383 | var phase = scope.$root.$$phase;
384 | if(phase == '$apply' || phase == '$digest') {
385 | if(fn && (typeof(fn) === 'function')) {
386 | fn();
387 | }
388 | } else {
389 | scope.$apply(fn);
390 | }
391 | };
392 | _handleBrdcst = function (locals, config) {
393 | angular.forEach(config.brdcstList, function (v) {
394 | var active, funcName;
395 |
396 | funcName = config.brdcstIsEmit ? '$emit' : '$broadcast';
397 |
398 | if (v.always) {
399 | config.brdcstScope[funcName](v.event, null, locals);
400 | }
401 | else if (v.condition) {
402 | active = v.condition(config.scope, locals);
403 | if (v.wasActive === null || active !== v.wasActive) {
404 | _apply(config.brdcstScope, function () {
405 | config.brdcstScope[funcName](v.event, active, locals);
406 | });
407 | }
408 | v.wasActive = active;
409 | }
410 | });
411 | };
412 |
413 | function _update(configId) {
414 | var positive, negative, numReverse, processConfig;
415 |
416 | var containerHeight = this._containerHeight(),
417 | contentHeight = this._contentHeight(),
418 | maxScrollTop = contentHeight - containerHeight,
419 | scrollTop = this._scrollTop();
420 |
421 | var self = this;
422 |
423 | positive = function (negative) {
424 | return maxScrollTop + negative;
425 | };
426 | negative = function (positive) {
427 | return positive - maxScrollTop;
428 | };
429 | numReverse = function (num) {
430 | return (num > 0) ? negative(num) : positive(num);
431 | };
432 |
433 | processConfig = function (config) {
434 | var from, to, locals, progress, elmMetrics;
435 |
436 | from = config.from < 0 ? positive(config.from) : config.from;
437 | to = config.to < 0 ? positive(config.to) : config.to;
438 |
439 | /**
440 | * Create local context
441 | */
442 | if (scrollTop < from) {
443 | progress = 0;
444 | locals = {
445 | $positive: from,
446 | $negative: negative(from)
447 | };
448 | }
449 | else if (scrollTop > to) {
450 | progress = 1;
451 | locals = {
452 | $positive: to,
453 | $negative: negative(to)
454 | };
455 | }
456 | else if (scrollTop >= from && scrollTop <= to) {
457 | progress = (scrollTop - from) / (to - from);
458 | locals = {
459 | $positive: scrollTop,
460 | $negative: negative(scrollTop)
461 | };
462 | }
463 |
464 | locals.$progress = progress;
465 | locals.$percentage = progress * 100;
466 |
467 | if (!config._lastProgress || config._lastProgress === progress) {
468 | locals.$direction = 0;
469 | }
470 | else if (config._lastProgress > progress) {
471 | locals.$direction = -1;
472 | }
473 | else if (config._lastProgress < progress) {
474 | locals.$direction = 1;
475 | }
476 |
477 | locals.$height = config.target[0].offsetHeight;
478 | angular.forEach(
479 | self._getElementMetrics(config.target),
480 | function (v, k) {
481 | locals['$' + k] = v;
482 | });
483 |
484 | /**
485 | * Applying
486 | */
487 | // to style
488 | if (config.styleGetter) {
489 | _handleStyle(locals, config);
490 | }
491 |
492 | // to class
493 | if (config.classGetter) {
494 | _handleClass(locals, config);
495 | }
496 |
497 | // trigger breakpoints
498 | if (config.brdcstList) {
499 | _handleBrdcst(locals, config);
500 | }
501 |
502 | config._lastProgress = progress;
503 | };
504 |
505 | if (angular.isUndefined(configId)) {
506 | angular.forEach(this.configs, processConfig);
507 | }
508 | else if (this.configs[configId]) {
509 | processConfig(this.configs[configId]);
510 | }
511 | }
512 |
513 | return function ($event, configId) {
514 | if (this.element === null) {
515 | return;
516 | }
517 |
518 | if (this._digesting && angular.isUndefined(configId)) {
519 | return;
520 | }
521 |
522 | var self = this;
523 |
524 | this._digesting = true;
525 |
526 | requestAnimFrame(function () {
527 | _update.call(self, configId);
528 |
529 | self._digesting = false;
530 | });
531 | };
532 | }());
533 |
534 | p._bind = function ($elm) {
535 | this._binded = true;
536 |
537 | if (this._isDefault()) {
538 | $win
539 | .on('scroll', this.scrollHandler)
540 | .on('resize', this.scrollHandler);
541 | }
542 | else {
543 | $win.on('resize', this.scrollHandler);
544 | $elm.on('scroll', this.scrollHandler);
545 | }
546 | };
547 |
548 | p._unbind = function ($elm) {
549 | this._binded = false;
550 |
551 | if (this._isDefault()) {
552 | $win
553 | .off('scroll', this.scrollHandler)
554 | .off('resize', this.scrollHandler);
555 | }
556 | else {
557 | $win.off('resize', this.scrollHandler);
558 | $elm.off('scroll', this.scrollHandler);
559 | }
560 | };
561 |
562 | return function scrollWatchStageFactory(name, $elm) {
563 | return new Stage(name, $elm);
564 | };
565 | }])
566 |
567 | .service('scrollWatchService',
568 | ["scrollWatchStageFactory", "$window", "$log", "$cacheFactory", function scrollWatchService(
569 | scrollWatchStageFactory, $window, $log, $cacheFactory
570 | ) {
571 | var defaultStage = scrollWatchStageFactory(
572 | STAGE_NAME_DEFAULT,
573 | angular.element($window)
574 | );
575 |
576 | this.stages = $cacheFactory(CACHE_ID_STAGE_POOL);
577 |
578 | this.stages.put(STAGE_NAME_DEFAULT, defaultStage);
579 |
580 | this.addStage = function (stageName, $elm) {
581 | var stage = this.stages.get(stageName);
582 |
583 | if (stage) {
584 | stage.setElement($elm);
585 | return;
586 | }
587 |
588 | stage = scrollWatchStageFactory(stageName, $elm);
589 | this.stages.put(stageName, stage);
590 | };
591 |
592 | this.removeStage = function (stageName) {
593 | var stage = this.stages.get(stageName);
594 |
595 | if (stage) {
596 | stage.clearElement();
597 | this._checkStageDestroy(stage);
598 | }
599 | };
600 |
601 | this.addConfig = function (config) {
602 | var stageName = config.stage,
603 | stage = this.stages.get(stageName);
604 |
605 | if (!stage) {
606 | // Create a stage without element
607 | stage = scrollWatchStageFactory(stageName);
608 | this.stages.put(stageName, stage);
609 | }
610 |
611 | return [stageName, stage.addConfig(config)];
612 | };
613 |
614 | this.removeConfig = function (handle) {
615 | var configId = handle[1],
616 | stage = this._getStage(handle);
617 |
618 | if (stage) {
619 | stage.removeConfig(configId);
620 | this._checkStageDestroy(stage);
621 | }
622 | };
623 |
624 | this.digest = function (handle) {
625 | var configId = handle[1],
626 | stage = this._getStage(handle);
627 |
628 | if (stage) {
629 | stage.digest(configId);
630 | }
631 | };
632 |
633 | this._checkStageDestroy = function (stage) {
634 | if (stage.couldDestroy()) {
635 | stage.destroy();
636 | this.stages.remove(stage.name);
637 | }
638 | };
639 |
640 | this._getStage = function (handle) {
641 | var stageName = handle[0];
642 | return this.stages.get(stageName);
643 | };
644 | }])
645 |
646 | .directive('scrollWatch', ["scrollWatchService", "$parse", function (scrollWatchService, $parse) {
647 | return {
648 | restrict: 'A',
649 | link: function postLink(scope, iElm, iAttrs) {
650 | var configHandle, deregisterDigestSync;
651 |
652 | if (iAttrs[DIR_STYLE] || iAttrs[DIR_CLASS] || iAttrs[DIR_BROADCAST]) {
653 | scope.$watch(iAttrs.scrollWatch, scrollWatchChange, true);
654 |
655 | iElm.on('$destroy', function () {
656 | if (configHandle) {
657 | scrollWatchService.removeConfig(configHandle);
658 | }
659 | });
660 | }
661 |
662 | function scrollWatchChange(config) {
663 | if (config && angular.isObject(config)) {
664 | // Make sure it won't modify the scope variable
665 | config = angular.copy(config);
666 |
667 | if (configHandle) {
668 | scrollWatchService.removeConfig(configHandle);
669 | (deregisterDigestSync || angular.noop)();
670 | }
671 |
672 | config.target = iElm;
673 | config.scope = scope;
674 | config.stage = config.stage || STAGE_NAME_DEFAULT;
675 |
676 | if (iAttrs[DIR_STYLE]) {
677 | config.styleExpr = iAttrs[DIR_STYLE];
678 | }
679 |
680 | if (iAttrs[DIR_CLASS]) {
681 | config.classExpr = iAttrs[DIR_CLASS];
682 | config.attr = iAttrs;
683 | }
684 |
685 | if (iAttrs[DIR_BROADCAST]) {
686 | config.brdcstExpr = iAttrs[DIR_BROADCAST];
687 | }
688 |
689 | if (config.digestSync) {
690 | deregisterDigestSync = scope.$watch(digestSync);
691 | }
692 |
693 | configHandle = scrollWatchService.addConfig(config);
694 | }
695 | }
696 |
697 | function digestSync () {
698 | if (configHandle) {
699 | scrollWatchService.digest(configHandle);
700 | }
701 | }
702 | }
703 | };
704 | }])
705 |
706 | .directive('swStage', ["scrollWatchService", function (scrollWatchService) {
707 | return {
708 | restrict: 'A',
709 | link: function postLink(scope, iElm, iAttrs) {
710 | var stageName;
711 |
712 | iAttrs.$observe(DIR_STAGE, function (val) {
713 | if (val) {
714 | if (stageName) {
715 | scrollWatchService.removeStage(stageName);
716 | }
717 |
718 | stageName = val;
719 | scrollWatchService.addStage(stageName, iElm);
720 | }
721 | });
722 |
723 | iElm.on('$destroy', function () {
724 | if (stageName) {
725 | scrollWatchService.removeStage(stageName);
726 | }
727 | });
728 | }
729 | };
730 | }]);
731 |
732 | function objectSize(obj) {
733 | var c = 0;
734 | angular.forEach(obj, function () {
735 | c++;
736 | });
737 | return c;
738 | }
739 |
740 | function arrayDifference(tokens1, tokens2) {
741 | var values = [];
742 |
743 | outer:
744 | for(var i = 0; i < tokens1.length; i++) {
745 | var token = tokens1[i];
746 | for(var j = 0; j < tokens2.length; j++) {
747 | if(token == tokens2[j]) continue outer;
748 | }
749 | values.push(token);
750 | }
751 | return values;
752 | }
753 |
754 | function arrayClasses (classVal) {
755 | if (angular.isArray(classVal)) {
756 | return classVal;
757 | } else if (angular.isString(classVal)) {
758 | return classVal.split(' ');
759 | } else if (angular.isObject(classVal)) {
760 | var classes = [], i = 0;
761 | angular.forEach(classVal, function(v, k) {
762 | if (v) {
763 | classes = classes.concat(k.split(' '));
764 | }
765 | });
766 | return classes;
767 | }
768 | return classVal;
769 | }
770 |
771 | function shallowCopy(src, dst) {
772 | if (angular.isArray(src)) {
773 | dst = dst || [];
774 |
775 | for ( var i = 0; i < src.length; i++) {
776 | dst[i] = src[i];
777 | }
778 | } else if (angular.isObject(src)) {
779 | dst = dst || {};
780 |
781 | for (var key in src) {
782 | if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
783 | dst[key] = src[key];
784 | }
785 | }
786 | }
787 |
788 | return dst || src;
789 | }
790 |
791 | return MODULE_NAME;
792 | }));
793 |
--------------------------------------------------------------------------------
/build/angular-scroll-watch.min.js:
--------------------------------------------------------------------------------
1 | /*! angular-scroll-watch
2 | version: 0.6.1
3 | build date: 2016-2-13
4 | author: [object Object]
5 | https://github.com/pc035860/angular-scroll-watch.git */
6 | !function(t,e){"object"==typeof exports||"object"==typeof module&&module.exports?module.exports=e(require("angular")):"function"==typeof define&&define.amd?define(["angular"],e):t.returnExports=e(t.angular)}(this,function(t){function e(e){var n=0;return t.forEach(e,function(){n++}),n}function n(t,e){var n=[];t:for(var i=0;i=10)break}while("BODY"!==e.tagName||t===e);return null},p._contentHeight=function(){if(this._isDefault()){var t=r[0].documentElement,e=r[0].body;return Math.max(e.scrollHeight,t.scrollHeight,e.offsetHeight,t.offsetHeight,t.clientHeight)}return this.element[0].scrollHeight},p._containerHeight=function(){if(this._isDefault()){var t=r[0].documentElement.clientHeight,e=o.innerHeight;return t>e?e:t}return this.element[0].offsetHeight},p._scrollTop=function(){return this._isDefault()?o.pageYOffset:this.element[0].scrollTop},p._digest=function(){function e(e){var n,i,s,c,a=this._containerHeight(),l=this._contentHeight(),f=l-a,u=this._scrollTop(),h=this;n=function(t){return f+t},i=function(t){return t-f},s=function(t){return t>0?i(t):n(t)},c=function(e){var s,c,a,l;s=e.from<0?n(e.from):e.from,c=e.to<0?n(e.to):e.to,s>u?(l=0,a={$positive:s,$negative:i(s)}):u>c?(l=1,a={$positive:c,$negative:i(c)}):u>=s&&c>=u&&(l=(u-s)/(c-s),a={$positive:u,$negative:i(u)}),a.$progress=l,a.$percentage=100*l,e._lastProgress&&e._lastProgress!==l?e._lastProgress>l?a.$direction=-1:e._lastProgress0||o[t])&&(o[t]=(o[t]||0)+i,o[t]===+(i>0)&&r.push(t))}),s.data("$classCounts",o),r.join(" ")},u=function(t,e,i){var s=t.target,o=n(i,e),r=n(e,i);r=l(t,r,-1),o=l(t,o,1),0===o.length?f.removeClass(s,r):0===r.length?f.addClass(s,o):f.setClass(s,o,r),t.scope.$digest()},r=function(e,n){var o=n.classGetter(n.scope,e),r=n._oldClassVal,a=i(o||[]);if(r){if(!t.equals(o,r)){var l=i(r);u(n,l,a)}}else c(n,a);n._oldClassVal=s(o)},g=function(t,e){var n=t.$root.$$phase;"$apply"==n||"$digest"==n?e&&"function"==typeof e&&e():t.$apply(e)},d=function(e,n){t.forEach(n.brdcstList,function(t){var i,s;s=n.brdcstIsEmit?"$emit":"$broadcast",t.always?n.brdcstScope[s](t.event,null,e):t.condition&&(i=t.condition(n.scope,e),(null===t.wasActive||i!==t.wasActive)&&g(n.brdcstScope,function(){n.brdcstScope[s](t.event,i,e)}),t.wasActive=i)})},function(n,i){if(!(null===this.element||this._digesting&&t.isUndefined(i))){var s=this;this._digesting=!0,h(function(){e.call(s,i),s._digesting=!1})}}}(),p._bind=function(t){this._binded=!0,this._isDefault()?d.on("scroll",this.scrollHandler).on("resize",this.scrollHandler):(d.on("resize",this.scrollHandler),t.on("scroll",this.scrollHandler))},p._unbind=function(t){this._binded=!1,this._isDefault()?d.off("scroll",this.scrollHandler).off("resize",this.scrollHandler):(d.off("resize",this.scrollHandler),t.off("scroll",this.scrollHandler))},function(t,e){return new g(t,e)}}]).service("scrollWatchService",["scrollWatchStageFactory","$window","$log","$cacheFactory",function(e,n,i,s){var o=e(f,t.element(n));this.stages=s(u),this.stages.put(f,o),this.addStage=function(t,n){var i=this.stages.get(t);return i?void i.setElement(n):(i=e(t,n),void this.stages.put(t,i))},this.removeStage=function(t){var e=this.stages.get(t);e&&(e.clearElement(),this._checkStageDestroy(e))},this.addConfig=function(t){var n=t.stage,i=this.stages.get(n);return i||(i=e(n),this.stages.put(n,i)),[n,i.addConfig(t)]},this.removeConfig=function(t){var e=t[1],n=this._getStage(t);n&&(n.removeConfig(e),this._checkStageDestroy(n))},this.digest=function(t){var e=t[1],n=this._getStage(t);n&&n.digest(e)},this._checkStageDestroy=function(t){t.couldDestroy()&&(t.destroy(),this.stages.remove(t.name))},this._getStage=function(t){var e=t[0];return this.stages.get(e)}}]).directive("scrollWatch",["scrollWatchService","$parse",function(e){return{restrict:"A",link:function(n,i,s){function o(o){o&&t.isObject(o)&&(o=t.copy(o),u&&(e.removeConfig(u),(h||t.noop)()),o.target=i,o.scope=n,o.stage=o.stage||f,s[r]&&(o.styleExpr=s[r]),s[c]&&(o.classExpr=s[c],o.attr=s),s[a]&&(o.brdcstExpr=s[a]),o.digestSync&&(h=n.$watch(l)),u=e.addConfig(o))}function l(){u&&e.digest(u)}var u,h;(s[r]||s[c]||s[a])&&(n.$watch(s.scrollWatch,o,!0),i.on("$destroy",function(){u&&e.removeConfig(u)}))}}}]).directive("swStage",["scrollWatchService",function(t){return{restrict:"A",link:function(e,n,i){var s;i.$observe(l,function(e){e&&(s&&t.removeStage(s),s=e,t.addStage(s,n))}),n.on("$destroy",function(){s&&t.removeStage(s)})}}}]),o});
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # angular-scroll-watch examples
2 |
3 | ### `sw-style`
4 |
5 | - [Basic](http://pc035860.github.com/angular-scroll-watch/example/sw-style/)
6 |
7 | ### `sw-class`
8 |
9 | - [Basic](http://pc035860.github.com/angular-scroll-watch/example/sw-class/)
10 | - [With `ng-repeat`](http://pc035860.github.com/angular-scroll-watch/example/sw-class-with-ng-repeat/)
11 |
12 | ### `sw-broadcast`
13 |
14 | - [Basic](http://pc035860.github.com/angular-scroll-watch/example/sw-broadcast/)
15 | - [Through `$scope.$emit`](http://pc035860.github.com/angular-scroll-watch/example/sw-broadcast-through-emit/)
16 | - [Infinite scroll](http://pc035860.github.com/angular-scroll-watch/example/infinite-scroll/)
17 |
18 | ### `sw-stage`
19 |
20 | - [Basic](http://pc035860.github.com/angular-scroll-watch/example/sw-stage/)
21 |
22 | ### Miscellaneous
23 |
24 | - [Digest sync](http://pc035860.github.com/angular-scroll-watch/example/digest-sync/)
25 | - [Locals](http://pc035860.github.com/angular-scroll-watch/example/locals/)
26 | - [Touch-enabled](http://pc035860.github.com/angular-scroll-watch/example/sw-style-touch/)
27 |
--------------------------------------------------------------------------------
/example/assets/digest-count.js:
--------------------------------------------------------------------------------
1 | angular.module('app.digest-count', [])
2 |
3 | .directive('digestCount', function ($rootScope) {
4 | return {
5 | restrict: 'EA',
6 | template: 'digest:
',
7 | link: function (scope, iElm, iAttrs) {
8 | var count = 0, dereg;
9 |
10 | dereg = $rootScope.$watch(function () {
11 | iElm.find('span').text(++count);
12 | });
13 |
14 | iElm.bind('$destroy', function () {
15 | if (dereg) {
16 | dereg();
17 | }
18 | });
19 | }
20 | };
21 | });
22 |
--------------------------------------------------------------------------------
/example/assets/edit-on-plunker.js:
--------------------------------------------------------------------------------
1 | (function (module) {
2 |
3 | var DEFAULT_CACHE_KEY = 'pc035860';
4 |
5 | var getCache = function ($cacheFactory) {
6 | var ID = 'to-plunker';
7 | return $cacheFactory.get(ID) || $cacheFactory(ID);
8 | };
9 |
10 | module
11 |
12 | .directive('toPlunker', function ($cacheFactory) {
13 | return {
14 | link: function postLink(scope, iElm, iAttrs) {
15 | var scriptPathsCache, cache, cacheKey;
16 |
17 | if (iElm[0].tagName === 'SCRIPT' && angular.isDefined(iAttrs.toPlunker)) {
18 | scriptPathsCache = getCache($cacheFactory);
19 | cacheKey = iAttrs.toPlunker || DEFAULT_CACHE_KEY;
20 |
21 | cache = scriptPathsCache.get(cacheKey);
22 | if (!cache) {
23 | cache = [];
24 | }
25 | cache.push(iAttrs.src);
26 |
27 | scriptPathsCache.put(cacheKey, cache);
28 | }
29 | }
30 | };
31 | })
32 |
33 | .directive('editOnPlunker', function (openPlunker, $document, $q, $http, $cacheFactory) {
34 | return {
35 | restrict: 'EA',
36 | template: 'Edit on Plunker ',
37 | replace: true,
38 | scope: {
39 | id: '@',
40 | getFiles: '&files',
41 | description: '@',
42 | getTags: '&tags'
43 | },
44 | link: function postLink(scope, iElm, iAttrs) {
45 | var preparePromise = prepareFiles();
46 |
47 | scope.edit = function () {
48 | var description = scope.description || $document[0].title,
49 | tags = (scope.getTags || angular.noop)() || [];
50 |
51 | preparePromise.then(function (fileObjs) {
52 | openPlunker(fileObjs, description, tags);
53 | });
54 | };
55 |
56 | function prepareFiles () {
57 | var scriptPathsCache = getCache($cacheFactory),
58 | cacheKey = scope.id || DEFAULT_CACHE_KEY,
59 | scripts = scriptPathsCache.get(cacheKey),
60 | files = scope.getFiles(),
61 | promises = [];
62 |
63 | if (scripts && angular.isArray(scripts)) {
64 | files = files.concat(scripts);
65 | }
66 |
67 | angular.forEach(files, function (path) {
68 | var promise = $http.get(path, {transformResponse: transformResponse})
69 | .then(function (res) {
70 | var content = res.data,
71 | filename = getFilename(path);
72 |
73 | if (filename === 'index.html') {
74 | angular.forEach(scripts, function (scriptPath) {
75 | content = content.replace(scriptPath, getFilename(scriptPath));
76 | });
77 | }
78 |
79 | return {
80 | filename: filename,
81 | content: content
82 | };
83 | });
84 | promises.push(promise);
85 | });
86 |
87 | return $q.all(promises);
88 | }
89 |
90 | function transformResponse(data, headerGetter) {
91 | return data;
92 | }
93 |
94 | function getFilename(path) {
95 | return path.substring(path.lastIndexOf('/') + 1);
96 | }
97 | }
98 | };
99 | })
100 |
101 | .factory('formPostData', function ($document) {
102 | return function(url, fields) {
103 | var form = angular.element('');
104 | angular.forEach(fields, function(field) {
105 | var name = field.name,
106 | value = field.value;
107 |
108 | var input = angular.element(' ');
109 | input.attr('value', value);
110 | form.append(input);
111 | });
112 | $document.find('body').append(form);
113 | form[0].submit();
114 | form.remove();
115 | };
116 | })
117 |
118 | .factory('openPlunker', function (formPostData) {
119 | return function (files, description, tags) {
120 | var postData = [];
121 |
122 | description = description || '';
123 | tags = tags || [];
124 |
125 | angular.forEach(files, function (file) {
126 | postData.push({
127 | name: 'files[' + file.filename + ']',
128 | value: file.content
129 | });
130 | });
131 |
132 | angular.forEach(tags, function (tag) {
133 | postData.push({
134 | name: 'tags[]',
135 | value: tag
136 | });
137 | });
138 |
139 | postData.push({
140 | name: 'private',
141 | value: true
142 | });
143 | postData.push({
144 | name: 'description',
145 | value: description
146 | });
147 |
148 | formPostData('http://plnkr.co/edit/?p=preview', postData);
149 | };
150 | });
151 |
152 |
153 | })(angular.module('app.edit-on-plunker', []));
154 |
--------------------------------------------------------------------------------
/example/assets/lesshat-prefixed.less:
--------------------------------------------------------------------------------
1 | // * =========================================================== *
2 | // < LESSHat >
3 | // * =========================================================== *
4 | //
5 | // Made with Energy drinks in Prague, Czech Republic.
6 | // Handcrafted by Petr Brzek, lesshat.com
7 | // Works great with CSS Hat csshat.com
8 |
9 | // version: v3.0.2 (2014-06-26)
10 |
11 | // TABLE OF MIXINS:
12 | // align-content
13 | // align-items
14 | // align-self
15 | // animation
16 | // animation-delay
17 | // animation-direction
18 | // animation-duration
19 | // animation-fill-mode
20 | // animation-iteration-count
21 | // animation-name
22 | // animation-play-state
23 | // animation-timing-function
24 | // appearance
25 | // backface-visibility
26 | // background-clip
27 | // background-image
28 | // background-origin
29 | // background-size
30 | // blur
31 | // border-bottom-left-radius
32 | // border-bottom-right-radius
33 | // border-image
34 | // border-radius
35 | // border-top-left-radius
36 | // border-top-right-radius
37 | // box-shadow
38 | // box-sizing
39 | // brightness
40 | // calc
41 | // column-count
42 | // column-gap
43 | // column-rule
44 | // column-width
45 | // columns
46 | // contrast
47 | // display
48 | // drop-shadow
49 | // filter
50 | // flex
51 | // flex-basis
52 | // flex-direction
53 | // flex-grow
54 | // flex-shrink
55 | // flex-wrap
56 | // font-face
57 | // grayscale
58 | // hue-rotate
59 | // hyphens
60 | // invert
61 | // justify-content
62 | // keyframes
63 | // opacity
64 | // order
65 | // perspective
66 | // perspective-origin
67 | // placeholder
68 | // rotate
69 | // rotate3d
70 | // rotateX
71 | // rotateY
72 | // rotateZ
73 | // saturate
74 | // scale
75 | // scale3d
76 | // scaleX
77 | // scaleY
78 | // scaleZ
79 | // selection
80 | // sepia
81 | // size
82 | // skew
83 | // skewX
84 | // skewY
85 | // transform
86 | // transform-origin
87 | // transform-style
88 | // transition
89 | // transition-delay
90 | // transition-duration
91 | // transition-property
92 | // transition-timing-function
93 | // translate
94 | // translate3d
95 | // translateX
96 | // translateY
97 | // translateZ
98 | // user-select
99 |
100 | .lh-align-content(...) {
101 | @process: ~`(function(r){return r=r||"stretch"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
102 | @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t?t="end":"space-between"==t?t="justify":"space-around"==t&&(t="distribute"),t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
103 | -webkit-align-content: @process;
104 | -ms-flex-line-pack: @process_ms;
105 | align-content: @process;
106 | }
107 |
108 | .lh-align-items(...) {
109 | @process_olderwebkit: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
110 | @process_moz: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
111 | @process: ~`(function(t){return t=t||"stretch"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
112 | @process_ms: ~`(function(t){return t=t||"stretch","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
113 | -webkit-box-align: @process_olderwebkit;
114 | -moz-box-align: @process_moz;
115 | -webkit-align-items: @process;
116 | -ms-flex-align: @process_ms;
117 | align-items: @process;
118 | }
119 |
120 | .lh-align-self(...) {
121 | @process: ~`(function(t){return t=t||"auto"})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
122 | @process_ms: ~`(function(t){return t=t||"auto","flex-start"==t?t="start":"flex-end"==t&&(t="end"),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
123 | -webkit-align-self: @process;
124 | -ms-flex-item-align: @process_ms;
125 | align-self: @process;
126 | }
127 |
128 | .lh-animation(...) {
129 | @process: ~`(function(t){return t=t||"none",/^[^, ]*,/.test(t)&&(t=t.replace(/(?:,)(?![^(]*\))/g,"")),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
130 | -webkit-animation: @process;
131 | -moz-animation: @process;
132 | -o-animation: @process;
133 | animation: @process;
134 | }
135 |
136 | .lh-animation-delay(...) {
137 | @process: ~`(function(t){t=t||"0";var r=/(?:\d)(?:ms|s)/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(t)||"0"===t||(t=t.replace(e,function(t){return t+=parseFloat(t,10)>10?"ms":"s"})),t})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
138 | -webkit-animation-delay: @process;
139 | -moz-animation-delay: @process;
140 | -o-animation-delay: @process;
141 | animation-delay: @process;
142 | }
143 |
144 | .lh-animation-direction(...) {
145 | @process: ~`(function(r){return r||"normal"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
146 | -webkit-animation-direction: @process;
147 | -moz-animation-direction: @process;
148 | -o-animation-direction: @process;
149 | animation-direction: @process;
150 | }
151 |
152 | .lh-animation-duration(...) {
153 | @process: ~`(function(r){r=r||"0";var t=/ms|s/gi,e=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(r)||"0"===r||(r=r.replace(e,function(r){return r+=parseFloat(r,10)>10?"ms":"s"})),r})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
154 | -webkit-animation-duration: @process;
155 | -moz-animation-duration: @process;
156 | -o-animation-duration: @process;
157 | animation-duration: @process;
158 | }
159 |
160 | .lh-animation-fill-mode(...) {
161 | @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
162 | -webkit-animation-fill-mode: @process;
163 | -moz-animation-fill-mode: @process;
164 | -o-animation-fill-mode: @process;
165 | animation-fill-mode: @process;
166 | }
167 |
168 | .lh-animation-iteration-count(...) {
169 | @process: ~`(function(r){return r||"0"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
170 | -webkit-animation-iteration-count: @process;
171 | -moz-animation-iteration-count: @process;
172 | -o-animation-iteration-count: @process;
173 | animation-iteration-count: @process;
174 | }
175 |
176 | .lh-animation-name(...) {
177 | @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
178 | -webkit-animation-name: @process;
179 | -moz-animation-name: @process;
180 | -o-animation-name: @process;
181 | animation-name: @process;
182 | }
183 |
184 | .lh-animation-play-state(...) {
185 | @process: ~`(function(r){return r||"running"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
186 | -webkit-animation-play-state: @process;
187 | -moz-animation-play-state: @process;
188 | -o-animation-play-state: @process;
189 | animation-play-state: @process;
190 | }
191 |
192 | .lh-animation-timing-function(...) {
193 | @process: ~`(function(r){return r||"ease"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
194 | -webkit-animation-timing-function: @process;
195 | -moz-animation-timing-function: @process;
196 | -o-animation-timing-function: @process;
197 | animation-timing-function: @process;
198 | }
199 |
200 | .lh-appearance(...) {
201 | @process: ~`(function(r){return r||"none"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
202 | -webkit-appearance: @process;
203 | -moz-appearance: @process;
204 | appearance: @process;
205 | }
206 |
207 | .lh-backface-visibility(...) {
208 | @process: ~`(function(r){return r||"visible"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
209 | -webkit-backface-visibility: @process;
210 | -moz-backface-visibility: @process;
211 | -ms-backface-visibility: @process;
212 | -o-backface-visibility: @process;
213 | backface-visibility: @process;
214 | }
215 |
216 | .lh-background-clip(...) {
217 | @process: ~`(function(r){return r||"border-box"})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
218 | -webkit-background-clip: @process;
219 | -moz-background-clip: @process;
220 | background-clip: @process;
221 | }
222 |
223 | .lh-background-image(...) {
224 | @process_ms: ~`(function(t){function e(t){var e,r,n,a,s,i,u,o,g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",c=0,l=0,f="",d=[];if(!t)return t;do e=t.charCodeAt(c++),r=t.charCodeAt(c++),n=t.charCodeAt(c++),o=e<<16|r<<8|n,a=63&o>>18,s=63&o>>12,i=63&o>>6,u=63&o,d[l++]=g.charAt(a)+g.charAt(s)+g.charAt(i)+g.charAt(u);while(c',svg_start:'',linear_gradient_start:'",radial_gradient_end:"",rect_linear:' ',rect_radial:' ',svg_end:" "};if(r.length){r.forEach(function(t){var e={};if(Object.keys(a).some(function(r){return t.indexOf(r)>=0?(e.svg_direction=a[r],!0):(e.svg_direction=!1,void 0)}),/linear/.test(t))e.svg_type="linear";else if(/radial/.test(t))e.svg_type="radial";else if(!/linear/.test(t)&&!/radial/.test(t))return e.url=t.trim(),e.svg_type="url",e.svg_direction=!0,n.push(e),!1;var r=t.match(/rgb|#[a-zA-Z0-9]|hsl/g).length;e.svg_stops=[],t=t.replace(/transparent/g,"rgba(0,0,0,0)"),t.match(/#[a-zA-Z0-9]/g)&&t.match(/(#[a-zA-Z0-9]+)\s*(\d+%)?/g).forEach(function(t){t=t.split(" "),e.svg_stops.push(' ')}),t.match(/rgba?\(\d+,\s*\d+,\s*\d+(?:,\s*(0|1|\.\d+|0\.\d+))?\)/g)&&t.replace(/rgba?\((\d+,\s*\d+,\s*\d+)(?:,\s*(0|1|\.\d+|0\.\d+))?\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push(' ')}),t.match(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)/g)&&t.replace(/hsla?\((\d+,\s*\d+%,\s*\d+%),\s*(0|1|\.\d+|0\.\d+)\)\s*(\d+%)?/g,function(t,r,n,a){e.svg_stops.push(' ')});var s=Math.floor(100/(r-1));e.svg_stops.forEach(function(t,r){/offset="false"/.test(t)&&(e.svg_stops[r]=t.replace(/offset="false"/,'offset="'+s*r+'%"'))}),e.svg_stops.sort(function(t,e){return t=t.match(/offset="(\d+)%"/),e=e.match(/offset="(\d+)%"/),2==t.length&&2==e.length?t[1]-e[1]:void 0}),n.push(e)});var i=[],u=n.every(function(t){for(var e in t)if(0==t[e]||0==t[e].length)return!1;return!0});if(!u)return 8121991;n.forEach(function(t,e){("linear"==t.svg_type||"radial"==t.svg_type)&&(i[e]=s.xml+s.svg_start),"linear"==t.svg_type?(i[e]+=s.linear_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.linear_gradient_end,i[e]+=s.rect_linear,i[e]+=s.svg_end):"radial"==t.svg_type?(i[e]+=s.radial_gradient_start+" "+t.svg_direction+">",t.svg_stops.forEach(function(t){i[e]+=t}),i[e]+=s.radial_gradient_end,i[e]+=s.rect_radial,i[e]+=s.svg_end):"url"==t.svg_type&&(i[e]=t.url)}),i.forEach(function(t,r){/<\?xml version="1.0" \?>/g.test(t)&&(i[r]=s.uri_data+e(t)+")")}),t=i.join(",")}return t})((function(){var r="@{arguments}";return r=r.replace(/^\[|\]$/g,"")})())`;
225 | @process_webkit: ~`(function(t){if(t=t||8121991,8121991==t)return t;var e={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(e);return n.some(function(n){return t.indexOf(n)>=0?(t=t.replace(new RegExp(n+"(?![ a-z0-9])","g"),e[n]),!0):(r.test(t)&&(t=t.replace(r,function(t,e,r,n,a){return e.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),t=t.replace(/(\d+)\s*deg/g,function(t,e){return 90-e+"deg"}).replace(/(linear|radial)-gradient/g,"-webkit-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
226 | @process_moz: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-moz-$1-gradient")})((function(){var t="@{arguments}";return t=t.replace(/^\[|\]$/g,"")})())`;
227 | @process_opera: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={"to bottom":"top","to left":"right","to top":"bottom","to right":"left","ellipse at center":"center, ellipse cover","circle closest-side":"center center, circle contain","circle farthest-corner":"center center, circle cover","circle farthest-side":"center center, circle cover","ellipse closest-side":"center center, ellipse contain","ellipse farthest-corner":"center center, ellipse cover","ellipse farthest-side":"center center, ellipse cover"},r=/(radial-gradient\()([a-z- ]+)at\s+(\w+%?)\s*(\w*%?)/g,n=Object.keys(t);return n.some(function(n){return e.indexOf(n)>=0?(e=e.replace(new RegExp(n+"(?![ a-z0-9])","g"),t[n]),!0):(r.test(e)&&(e=e.replace(r,function(e,t,r,n,a){return t.trim()+n.trim()+" "+a.trim()+","+r.replace(/closest-side/g,"contain").replace(/farthest-corner/g,"cover").trim()})),void 0)}),e=e.replace(/(\d+)\s*deg/g,function(e,t){return 90-t+"deg"}).replace(/(linear|radial)-gradient/g,"-o-$1-gradient")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
228 | @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t={top:"to bottom",right:"to left",bottom:"to top",left:"to right"},r=Object.keys(t);return r.some(function(r){return e.indexOf(r)>=0&&!new RegExp("to\\s+"+r+"|at\\s+"+r,"g").test(e)?(e=e.replace(new RegExp(r),t[r]),!0):void 0}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
229 | background-image: @process_ms;
230 | background-image: @process_webkit;
231 | background-image: @process_moz;
232 | background-image: @process_opera;
233 | background-image: @process;
234 | }
235 |
236 | .lh-background-origin(...) {
237 | @process: ~`(function(e){return e||"padding-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
238 | -webkit-background-origin: @process;
239 | -moz-background-origin: @process;
240 | background-origin: @process;
241 | }
242 |
243 | .lh-background-size(...) {
244 | @process: ~`(function(e){e=e||"auto auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
245 | -webkit-background-size: @process;
246 | -moz-background-size: @process;
247 | background-size: @process;
248 | }
249 |
250 | .lh-blur(...) {
251 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
252 | -webkit-filter: blur(@process);
253 | -moz-filter: blur(@process);
254 | -ms-filter: blur(@process);
255 | filter: blur(@process);
256 | }
257 |
258 | .lh-border-bottom-left-radius(...) {
259 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
260 | -webkit-border-bottom-left-radius: @process; -webkit-background-clip: padding-box;
261 | -moz-border-radius-bottomleft: @process; -moz-background-clip: padding;
262 | border-bottom-left-radius: @process; background-clip: padding-box;
263 | }
264 |
265 | .lh-border-bottom-right-radius(...) {
266 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
267 | -webkit-border-bottom-right-radius: @process; -webkit-background-clip: padding-box;
268 | -moz-border-radius-bottomright: @process; -moz-background-clip: padding;
269 | border-bottom-right-radius: @process; background-clip: padding-box;
270 | }
271 |
272 | .lh-border-image(...) {
273 | @process: ~`(function(e){return e=e||8121991,/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
274 | -webkit-border-image: @process;
275 | -moz-border-image: @process;
276 | -o-border-image: @process;
277 | border-image: @process;
278 | }
279 |
280 | .lh-border-radius(...) {
281 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
282 | -webkit-border-radius: @process; -webkit-background-clip: padding-box;
283 | -moz-border-radius: @process; -moz-background-clip: padding;
284 | border-radius: @process; background-clip: padding-box;
285 | }
286 |
287 | .lh-border-top-left-radius(...) {
288 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
289 | -webkit-border-top-left-radius: @process; -webkit-background-clip: padding-box;
290 | -moz-border-radius-topleft: @process; -moz-background-clip: padding;
291 | border-top-left-radius: @process; background-clip: padding-box;
292 | }
293 |
294 | .lh-border-top-right-radius(...) {
295 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
296 | -webkit-border-top-right-radius: @process; -webkit-background-clip: padding-box;
297 | -moz-border-radius-topright: @process; -moz-background-clip: padding;
298 | border-top-right-radius: @process; background-clip: padding-box;
299 | }
300 |
301 | .lh-box-shadow(...) {
302 | @process: ~`(function(e){e=e||"0";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
303 | -webkit-box-shadow: @process;
304 | -moz-box-shadow: @process;
305 | box-shadow: @process;
306 | }
307 |
308 | .lh-box-sizing(...) {
309 | @process: ~`(function(e){return e=e||"content-box"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
310 | -webkit-box-sizing: @process;
311 | -moz-box-sizing: @process;
312 | box-sizing: @process;
313 | }
314 |
315 | .lh-brightness(...) {
316 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
317 | -webkit-filter: brightness(@process);
318 | -moz-filter: brightness(@process);
319 | -ms-filter: brightness(@process);
320 | filter: brightness(@process);
321 | }
322 |
323 | .lh-calc(...) {
324 | @process: ~`(function(e){function t(t,r){var a=");\n",c=n.split(","),i=c[0]+":"+t+"("+(c[1].trim()||0)+a;"start"==r?e="0;\n"+i:e+=i}e=e||8121991;var r="@{state}",n=e;if(8121991==e)return e;switch(r){case"1":t("-webkit-calc","start"),t("-moz-calc"),t("calc");break;case"2":t("-webkit-calc","start"),t("-moz-calc");break;case"3":t("-webkit-calc","start"),t("calc");break;case"4":t("-webkit-calc","start");break;case"5":t("-moz-calc","start"),t("calc");break;case"6":t("-moz-calc","start");break;case"7":t("calc","start")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
325 | @state: 1; -lh-property: @process;
326 |
327 | }
328 |
329 | .lh-column-count(...) {
330 | @process: ~`(function(e){return e=e||"auto"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
331 | -webkit-column-count: @process;
332 | -moz-column-count: @process;
333 | column-count: @process;
334 | }
335 |
336 | .lh-column-gap(...) {
337 | @process: ~`(function(e){e=e||"normal";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
338 | -webkit-column-gap: @process;
339 | -moz-column-gap: @process;
340 | column-gap: @process;
341 | }
342 |
343 | .lh-column-rule(...) {
344 | @process: ~`(function(e){e=e||"medium none black";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
345 | -webkit-column-rule: @process;
346 | -moz-column-rule: @process;
347 | column-rule: @process;
348 | }
349 |
350 | .lh-column-width(...) {
351 | @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
352 | -webkit-column-width: @process;
353 | -moz-column-width: @process;
354 | column-width: @process;
355 | }
356 |
357 | .lh-columns(...) {
358 | @process: ~`(function(e){e=e||"auto auto";var t=/^\d+$/;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""),e=e.split(" ")),t.test(e[0])&&(e[0]=e[0]+"px"),e.join(" ")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
359 | -webkit-columns: @process;
360 | -moz-columns: @process;
361 | columns: @process;
362 | }
363 |
364 | .lh-contrast(...) {
365 | @process: ~`(function(e){e=e||"100%";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
366 | -webkit-filter: ~"contrast(@{process})";
367 | -moz-filter: ~"contrast(@{process})";
368 | -ms-filter: ~"contrast(@{process})";
369 | filter: ~"contrast(@{process})";
370 | }
371 |
372 | .lh-display(...) {
373 | @process_oldwebkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
374 | @process_moz: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-moz-box":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
375 | @process_webkit: ~`(function(e){return e="flex"==e||"inline-flex"==e?"-webkit-"+e:8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
376 | @process_ms: ~`(function(e){return e="flex"==e?"-ms-flexbox":"inline-flex"==e?"-ms-inline-flexbox":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
377 | @process: ~`(function(e){return"flex"!=e&&"inline-flex"!=e&&(e=8121991),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
378 | display: @process_oldwebkit;
379 | display: @process_moz;
380 | display: @process_webkit;
381 | display: @process_ms;
382 | display: @process;
383 | }
384 |
385 | .lh-drop-shadow(...) {
386 | @process: ~`(function(e){if(e=e||8121991,8121991==e)return e;var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
387 | -webkit-filter: drop-shadow(@process);
388 | -moz-filter: drop-shadow(@process);
389 | -ms-filter: drop-shadow(@process);
390 | filter: drop-shadow(@process);
391 | }
392 |
393 | .lh-filter(...) {
394 | @process: ~`(function(e){return e=e||"none",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
395 | -webkit-filter: @process;
396 | -moz-filter: @process;
397 | -ms-filter: @process;
398 | filter: @process;
399 | }
400 |
401 | .lh-flex(...) {
402 | @process_olderwebkit: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
403 | @process_moz: ~`(function(e){return/^\d+/.test(e)?e=e.match(/^\d+/)[0]:""==e&&(e="0"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
404 | @process: ~`(function(e){return e=e||"0 1 auto",/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
405 | -webkit-box-flex: @process_olderwebkit;
406 | -moz-box-flex: @process_moz;
407 | -webkit-flex: @process;
408 | -ms-flex: @process;
409 | flex: @process;
410 | }
411 |
412 | .lh-flex-basis(...) {
413 | @process: ~`(function(e){e=e||"auto";var t=/\d/gi,r=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return t.test(e)&&(e=e.replace(r,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
414 | -webkit-flex-basis: @process;
415 | flex-basis: @process;
416 | }
417 |
418 | .lh-flex-direction(...) {
419 | @process_oldestwebkit: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
420 | @process_oldermoz: ~`(function(e){return e="row"==e||"column"==e?"normal":"row-reverse"==e||"column-reverse"==e?"reverse":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
421 | @process_olderwebkit: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
422 | @process_moz: ~`(function(e){return e="row"==e||"row-reverse"==e?"horizontal":"column"==e||"column-reverse"==e?"vertical":8121991})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
423 | @process: ~`(function(e){return e=e||"row"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
424 | -webkit-box-direction: @process_oldestwebkit;
425 | -moz-box-direction: @process_oldermoz;
426 | -webkit-box-orient: @process_olderwebkit;
427 | -moz-box-orient: @process_moz;
428 | -webkit-flex-direction: @process;
429 | -ms-flex-direction: @process;
430 | flex-direction: @process;
431 | }
432 |
433 | .lh-flex-grow(...) {
434 | @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
435 | -webkit-flex-grow: @process;
436 | flex-grow: @process;
437 | }
438 |
439 | .lh-flex-shrink(...) {
440 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
441 | -webkit-flex-shrink: @process;
442 | flex-shrink: @process;
443 | }
444 |
445 | .lh-flex-wrap(...) {
446 | @process: ~`(function(e){return e=e||"nowrap"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
447 | -webkit-flex-wrap: @process;
448 | -ms-flex-wrap: @process;
449 | flex-wrap: @process;
450 | }
451 |
452 | .lh-font-face(@fontname, @fontfile, @fontweight:normal, @fontstyle:normal) {
453 | font-family: "@{fontname}";
454 | src: url("@{fontfile}.eot");
455 | src: url("@{fontfile}.eot?#iefix") format("embedded-opentype"),
456 | url("@{fontfile}.woff") format("woff"),
457 | url("@{fontfile}.ttf") format("truetype"),
458 | url("@{fontfile}.svg#@{fontname}") format("svg");
459 | font-weight: @fontweight;
460 | font-style: @fontstyle;
461 | }
462 |
463 | .lh-grayscale(...) {
464 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
465 | -webkit-filter: grayscale(@process);
466 | -moz-filter: grayscale(@process);
467 | -ms-filter: grayscale(@process);
468 | filter: grayscale(@process);
469 | }
470 |
471 | .lh-hue-rotate(...) {
472 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
473 | -webkit-filter: hue-rotate(@process);
474 | -moz-filter: hue-rotate(@process);
475 | -ms-filter: hue-rotate(@process);
476 | filter: hue-rotate(@process);
477 | }
478 |
479 | .lh-hyphens(...) {
480 | @process: ~`(function(e){return e=e||"manual"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
481 | -webkit-hyphens: @process;
482 | -moz-hyphens: @process;
483 | -ms-hyphens: @process;
484 | hyphens: @process;
485 | }
486 |
487 | .lh-invert(...) {
488 | @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
489 | -webkit-filter: invert(@process);
490 | -moz-filter: invert(@process);
491 | -ms-filter: invert(@process);
492 | filter: invert(@process);
493 | }
494 |
495 | .lh-justify-content(...) {
496 | @process_oldestWebkit: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
497 | @process_moz: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":("space-between"==e||"space-around"==e)&&(e="justify"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
498 | @process_ms: ~`(function(e){return e=e||"start","flex-start"==e?e="start":"flex-end"==e?e="end":"space-between"==e?e="justify":"space-around"==e&&(e="distribute"),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
499 | @process: ~`(function(e){return e=e||"flex-start"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
500 | -webkit-box-pack: @process_oldestWebkit;
501 | -moz-box-pack: @process_moz;
502 | -ms-flex-pack: @process_ms;
503 | -webkit-justify-content: @process;
504 | justify-content: @process;
505 | }
506 |
507 | .lh-keyframes(...) {
508 | @process: ~`(function(e){function r(r,t,c){var i="}\n",u=n.split(/(^[a-zA-Z0-9-]+),/g),s=t+" "+u[1]+"{",o=["-webkit-","-moz-","-ms-",""];c?a.forEach(function(r){-1!==e.indexOf(r)&&(u[2]=u[2].replace(new RegExp(r,"g"),function(e){return c+e}))}):u[2]=u[2].replace(/{([^}]+)}/g,function(e,r){var t=r.split(";");t.forEach(function(e,r){a.forEach(function(n){-1!==e.indexOf(n)&&(t[r]="",o.forEach(function(a){t[r]+=e.trim().replace(new RegExp(n,"g"),function(e){return a+e})+";"}))})});var n=t.join(";").replace(/;;/g,";");return e.replace(r,n)}),s+=u[2]+i,"start"==r?e="0; } \n"+s:"startend"==r?e="0; } \n"+s.replace(i,""):e+="end"==r?s.replace(i,""):s}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;var a=["animation","transform","filter"];switch(t){case"1":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"2":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"3":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"4":r("start","@-webkit-keyframes","-webkit-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"5":r("start","@-webkit-keyframes","-webkit-"),r("end","@-moz-keyframes","-moz-");break;case"6":r("start","@-webkit-keyframes","-webkit-"),r("end","@-o-keyframes","-o-");break;case"7":r("start","@-webkit-keyframes","-webkit-"),r("end","@keyframes");break;case"8":r("startend","@-webkit-keyframes","-webkit-");break;case"9":r("start","@-moz-keyframes","-moz-"),r(null,"@-o-keyframes","-o-"),r("end","@keyframes");break;case"10":r("start","@-moz-keyframes","-moz-"),r("end","@-o-keyframes","-o-");break;case"11":r("start","@-moz-keyframes","-moz-"),r("end","@keyframes");break;case"12":r("startend","@-moz-keyframes","-moz-");break;case"13":r("start","@-o-keyframes","-o-"),r("end","@keyframes");break;case"14":r("startend","@-o-keyframes","-o-");break;case"15":r("startend","@keyframes")}return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
509 | @state: 1; lesshat-selector { -lh-property: @process; }
510 |
511 |
512 |
513 | }
514 |
515 | .lh-opacity(...) {
516 | @process_ms: ~`(function(e){return e=e||"filter: alpha(opacity=100)","alpha(opacity="+Math.floor(100*e)+")"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
517 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
518 | zoom: 1; filter: @process_ms;
519 | -webkit-opacity: @process;
520 | -moz-opacity: @process;
521 | opacity: @process;
522 | }
523 |
524 | .lh-order(...) {
525 | @process: ~`(function(e){return e=e||"0"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
526 | -webkit-box-ordinal-group: @process;
527 | -moz-box-ordinal-group: @process;
528 | -ms-flex-order: @process;
529 | -webkit-order: @process;
530 | order: @process;
531 | }
532 |
533 | .lh-perspective(...) {
534 | @process: ~`(function(e){e=e||"none";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"px"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
535 | -webkit-perspective: @process;
536 | -moz-perspective: @process;
537 | perspective: @process;
538 | }
539 |
540 | .lh-perspective-origin(...) {
541 | @process: ~`(function(e){e=e||"50% 50%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
542 | -webkit-perspective-origin: @process;
543 | -moz-perspective-origin: @process;
544 | perspective-origin: @process;
545 | }
546 |
547 | .lh-placeholder(@color:#aaa, @element: 08121991) {
548 | .inception (@arguments) when not (@element = 08121991) {
549 | @{element}::-webkit-input-placeholder {
550 | color: @color;
551 | }
552 | @{element}:-moz-placeholder {
553 | color: @color;
554 | }
555 | @{element}::-moz-placeholder {
556 | color: @color;
557 | }
558 | @{element}:-ms-input-placeholder {
559 | color: @color;
560 | }
561 | }
562 | .inception (@arguments) when (@element = 08121991) {
563 | &::-webkit-input-placeholder {
564 | color: @color;
565 | }
566 | &:-moz-placeholder {
567 | color: @color;
568 | }
569 | &::-moz-placeholder {
570 | color: @color;
571 | }
572 | &:-ms-input-placeholder {
573 | color: @color;
574 | }
575 | }
576 | .inception(@arguments);
577 | }
578 |
579 | .lh-rotate(...) {
580 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
581 | -webkit-transform: rotate(@process);
582 | -moz-transform: rotate(@process);
583 | -ms-transform: rotate(@process);
584 | -o-transform: rotate(@process);
585 | transform: rotate(@process);
586 | }
587 |
588 | .lh-rotate3d(...) {
589 | @process: ~`(function(e){return e=e||"0, 0, 0, 0",e=e.replace(/,\s*\d+$/,function(e){return e+"deg"})})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
590 | -webkit-transform: rotate3d(@process);
591 | -moz-transform: rotate3d(@process);
592 | -ms-transform: rotate3d(@process);
593 | -o-transform: rotate3d(@process);
594 | transform: rotate3d(@process);
595 | }
596 |
597 | .lh-rotateX(...) {
598 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
599 | -webkit-transform: rotateX(@process);
600 | -moz-transform: rotateX(@process);
601 | -ms-transform: rotateX(@process);
602 | -o-transform: rotateX(@process);
603 | transform: rotateX(@process);
604 | }
605 |
606 | .lh-rotateY(...) {
607 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
608 | -webkit-transform: rotateY(@process);
609 | -moz-transform: rotateY(@process);
610 | -ms-transform: rotateY(@process);
611 | -o-transform: rotateY(@process);
612 | transform: rotateY(@process);
613 | }
614 |
615 | .lh-rotateZ(...) {
616 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
617 | -webkit-transform: rotateZ(@process);
618 | -moz-transform: rotateZ(@process);
619 | -ms-transform: rotateZ(@process);
620 | -o-transform: rotateZ(@process);
621 | transform: rotateZ(@process);
622 | }
623 |
624 | .lh-saturate(...) {
625 | @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
626 | -webkit-filter: ~"saturate(@{process})";
627 | -moz-filter: ~"saturate(@{process})";
628 | -ms-filter: ~"saturate(@{process})";
629 | filter: ~"saturate(@{process})";
630 | }
631 |
632 | .lh-scale(...) {
633 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
634 | -webkit-transform: scale(@process);
635 | -moz-transform: scale(@process);
636 | -ms-transform: scale(@process);
637 | -o-transform: scale(@process);
638 | transform: scale(@process);
639 | }
640 |
641 | .lh-scale3d(...) {
642 | @process: ~`(function(e){return e=e||"1, 1, 1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
643 | -webkit-transform: scale3d(@process);
644 | -moz-transform: scale3d(@process);
645 | -ms-transform: scale3d(@process);
646 | -o-transform: scale3d(@process);
647 | transform: scale3d(@process);
648 | }
649 |
650 | .lh-scaleX(...) {
651 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
652 | -webkit-transform: scaleX(@process);
653 | -moz-transform: scaleX(@process);
654 | -ms-transform: scaleX(@process);
655 | -o-transform: scaleX(@process);
656 | transform: scaleX(@process);
657 | }
658 |
659 | .lh-scaleY(...) {
660 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
661 | -webkit-transform: scaleY(@process);
662 | -moz-transform: scaleY(@process);
663 | -ms-transform: scaleY(@process);
664 | -o-transform: scaleY(@process);
665 | transform: scaleY(@process);
666 | }
667 |
668 | .lh-scaleZ(...) {
669 | @process: ~`(function(e){return e=e||"1"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
670 | -webkit-transform: scaleZ(@process);
671 | -moz-transform: scaleZ(@process);
672 | -ms-transform: scaleZ(@process);
673 | -o-transform: scaleZ(@process);
674 | transform: scaleZ(@process);
675 | }
676 |
677 | .lh-selection(...) {
678 | @process: ~`(function(e){function r(r,t){var a="}\n",c=n.split(","),u=(c[1]||"")+t+"{"+c[0]+a;"start"==r?e="0; } \n"+u:"startend"==r?e="0; } \n"+u.replace(a,""):e+="end"==r?u.replace(a,""):u}e=e||8121991;var t="@{state}",n=e;if(8121991==e)return e;switch(t){case"1":r("start","::selection"),r("end","::-moz-selection");break;case"2":r("startend","::selection");break;case"3":r("startend","::-moz-selection")}return e=e.replace(/;$/g,"")})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
679 | @state: 1; lesshat-selector { -lh-property: @process; }
680 |
681 | }
682 |
683 | .lh-sepia(...) {
684 | @process: ~`(function(e){e=e||"100%";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
685 | -webkit-filter: sepia(@process);
686 | -moz-filter: sepia(@process);
687 | -ms-filter: sepia(@process);
688 | filter: sepia(@process);
689 | }
690 |
691 | .lh-size(@square) {
692 | @unit: 'px';
693 | .process(@square) when (ispixel(@square)), (isem(@square)), (ispercentage(@square)), (iskeyword(@square)) {
694 | width: @square;
695 | height: @square;
696 | }
697 |
698 | .process(@square) when not (ispixel(@square)) and not (isem(@square)) and not (ispercentage(@square)) and not (isstring(@square)) and not (iskeyword(@square)) {
699 | width: ~`@{square} + @{unit}`;
700 | height: ~`@{square} + @{unit}`;
701 | }
702 |
703 | .process(@square);
704 |
705 | }
706 |
707 | .lh-size(@width, @height) {
708 | @unit: 'px';
709 | .process(@width, @height) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) {
710 | .kittens(@height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) {
711 | width: @width;
712 | height: @height;
713 | }
714 | .kittens(@height) when not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) {
715 | width: @width;
716 | height: ~`@{height} + @{unit}`;
717 | }
718 | .kittens(@height);
719 | }
720 |
721 | .process(@width, @height) when (ispixel(@height)), (isem(@height)), (ispercentage(@height)), (iskeyword(@height)) {
722 | .kittens(@width) when (ispixel(@width)), (isem(@width)), (ispercentage(@width)), (iskeyword(@width)) {}
723 | .kittens(@width) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) {
724 | width: ~`@{width} + @{unit}`;
725 | height: @height;
726 | }
727 | .kittens(@width);
728 | }
729 |
730 | .process(@width, @height) when not (ispixel(@width)) and not (isem(@width)) and not (ispercentage(@width)) and not (iskeyword(@width)) and not (ispixel(@height)) and not (isem(@height)) and not (ispercentage(@height)) and not (iskeyword(@height)) {
731 | width: ~`@{width} + @{unit}`;
732 | height: ~`@{height} + @{unit}`;
733 | }
734 |
735 | .process(@width, @height);
736 |
737 | }
738 |
739 | .lh-skew(...) {
740 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
741 | -webkit-transform: skew(@process);
742 | -moz-transform: skew(@process);
743 | -ms-transform: skew(@process);
744 | -o-transform: skew(@process);
745 | transform: skew(@process);
746 | }
747 |
748 | .lh-skewX(...) {
749 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
750 | -webkit-transform: skewX(@process);
751 | -moz-transform: skewX(@process);
752 | -ms-transform: skewX(@process);
753 | -o-transform: skewX(@process);
754 | transform: skewX(@process);
755 | }
756 |
757 | .lh-skewY(...) {
758 | @process: ~`(function(e){e=e||"0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"deg"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
759 | -webkit-transform: skewY(@process);
760 | -moz-transform: skewY(@process);
761 | -ms-transform: skewY(@process);
762 | -o-transform: skewY(@process);
763 | transform: skewY(@process);
764 | }
765 |
766 | .lh-transform(...) {
767 | @process: ~`(function(e){e=e||"none";var r={translate:"px",rotate:"deg",rotate3d:"deg",skew:"deg"};/^\w*\(?[a-z0-9.]*\)?/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));for(var t in r)e.indexOf(t)>=0&&(e=e.replace(new RegExp(t+"[\\w]?\\([a-z0-9, %]*\\)"),function(e){var n=/(\d+\.?\d*)(?!\w|%)/g;return"rotate3d"==t&&(n=/,\s*\d+$/),e.replace(n,function(e){return e+r[t]})}));return e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
768 | -webkit-transform: @process;
769 | -moz-transform: @process;
770 | -ms-transform: @process;
771 | -o-transform: @process;
772 | transform: @process;
773 | }
774 |
775 | .lh-transform-origin(...) {
776 | @process: ~`(function(e){e=e||"50% 50% 0";var r=/\d/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.test(e)&&(e=e.replace(t,function(e){return 0==e&&e||e+"%"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
777 | -webkit-transform-origin: @process;
778 | -moz-transform-origin: @process;
779 | -ms-transform-origin: @process;
780 | -o-transform-origin: @process;
781 | transform-origin: @process;
782 | }
783 |
784 | .lh-transform-style(...) {
785 | @process: ~`(function(e){return e=e||"flat"})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
786 | -webkit-transform-style: @process;
787 | -moz-transform-style: @process;
788 | -ms-transform-style: @process;
789 | -o-transform-style: @process;
790 | transform-style: @process;
791 | }
792 |
793 | .lh-transition(...) {
794 | @process_webkit: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","border-radius","border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","box-shadow","column","transform","filter"],t="-webkit-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
795 | @process_moz: ~`(function(e){e=e||"all 0 ease 0";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
796 | @process_opera: ~`(function(e){e=e||"all 0 ease 0";var r=["transform"],t="-o-",n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;return/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,"")),r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),n.test(e)||"0"===e||(e=e.replace(a,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
797 | @process: ~`(function(e){e=e||"all 0 ease 0";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=/(?:\d)(?:ms|s)/gi,a=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%)/gi;/^[^, ]*,/.test(e)&&(e=e.replace(/(?:,)(?![^(]*\))/g,""));var c=e.split(/(?:,)(?![^(]*\))/g);return c.forEach(function(e,n){t.forEach(function(t){-1!==e.indexOf(t)&&(c[n]="",r.forEach(function(a,u){c[n]+=e.trim().replace(new RegExp(t,"g"),function(e){return a+e}),u10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
798 | -webkit-transition: @process_webkit;
799 | -moz-transition: @process_moz;
800 | -o-transition: @process_opera;
801 | transition: @process;
802 | }
803 |
804 | .lh-transition-delay(...) {
805 | @process: ~`(function(e){e=e||"0";var r=/(?:\d)(?:ms|s)/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
806 | -webkit-transition-delay: @process;
807 | -moz-transition-delay: @process;
808 | -o-transition-delay: @process;
809 | transition-delay: @process;
810 | }
811 |
812 | .lh-transition-duration(...) {
813 | @process: ~`(function(e){e=e||"0";var r=/ms|s/gi,t=/(?:\s|^)(\.?\d+\.?\d*)(?![^(]*\)|\w|%|\.)/gi;return r.test(e)||"0"===e||(e=e.replace(t,function(e){return e+=parseFloat(e,10)>10?"ms":"s"})),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
814 | -webkit-transition-duration: @process;
815 | -moz-transition-duration: @process;
816 | -o-transition-duration: @process;
817 | transition-duration: @process;
818 | }
819 |
820 | .lh-transition-property(...) {
821 | @process_webkit: ~`(function(e){e=e||"all";var r=["background-size","border-radius","border-bottom-left-radius","border-bottom-right-radius","border-top-left-radius","border-top-right-radius","box-shadow","column","transform","filter"],t="-webkit-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
822 | @process_moz: ~`(function(e){e=e||"all";var r=["background-size","box-shadow","column","transform","filter"],t="-moz-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
823 | @process_opera: ~`(function(e){e=e||"all";var r=["transform"],t="-o-";return r.forEach(function(r){-1!==e.indexOf(r)&&(e=e.replace(new RegExp(r,"g"),function(e){return t+e}))}),e})((function(){var e="@{arguments}";return e=e.replace(/^\[|\]$/g,"")})())`;
824 | @process: ~`(function(e){e=e||"all";var r=["-webkit-","-moz-","-o-",""],t=["column","transform","filter"],n=e.split(/(?:,)(?![^(]*\))/g);return n.forEach(function(e,a){t.forEach(function(t){-1!==e.indexOf(t)&&(n[a]="",r.forEach(function(c,u){n[a]+=e.trim().replace(new RegExp(t,"g"),function(e){return c+e}),u
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: digest sync
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
52 |
53 |
54 |
55 |
60 |
61 |
Scale factor: {{ scaleFactor }}
62 |
Rand
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/example/digest-sync/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | height: 2000px;
7 | }
8 | #hero {
9 | -webkit-transform: translate(-50%, -50%);
10 | -moz-transform: translate(-50%, -50%);
11 | -ms-transform: translate(-50%, -50%);
12 | -o-transform: translate(-50%, -50%);
13 | transform: translate(-50%, -50%);
14 | position: fixed;
15 | top: 50%;
16 | left: 50%;
17 | text-align: center;
18 | }
19 | #hero p {
20 | color: #FAC15F;
21 | }
22 |
--------------------------------------------------------------------------------
/example/digest-sync/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | height: 2000px;
10 | }
11 |
12 | #hero {
13 | .lh-translate(-50%, -50%);
14 |
15 | position: fixed;
16 | top: 50%;
17 | left: 50%;
18 |
19 | text-align: center;
20 |
21 | p {
22 | color: #FAC15F;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/infinite-scroll/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: infinite scroll
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
98 |
99 |
100 |
101 |
Infinite scroll
102 |
Automatically append more items when the scroll distance from bottom is less than 400.
103 |
104 |
105 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
{{ item.id }}
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/example/infinite-scroll/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | background-color: #EEFFD8;
5 | }
6 | #content {
7 | position: relative;
8 | }
9 | .jumbotron {
10 | background-color: transparent;
11 | }
12 | .jumbotron .btn {
13 | position: static !important;
14 | left: auto !important;
15 | top: auto !important;
16 | margin: 0 !important;
17 | }
18 | .item {
19 | -webkit-border-radius: 5px;
20 | -webkit-background-clip: padding-box;
21 | -moz-border-radius: 5px;
22 | -moz-background-clip: padding;
23 | border-radius: 5px;
24 | background-clip: padding-box;
25 | margin-bottom: 10px;
26 | text-align: center;
27 | min-height: 80px;
28 | line-height: 80px;
29 | color: #A662B2;
30 | font-size: 24px;
31 | border: 5px solid #F5BFFF;
32 | }
33 | .item-anim.ng-enter {
34 | -webkit-animation: zoomInUp 800ms both;
35 | -moz-animation: zoomInUp 800ms both;
36 | -o-animation: zoomInUp 800ms both;
37 | animation: zoomInUp 800ms both;
38 | }
39 | .item-anim.ng-enter-stagger {
40 | -webkit-animation-delay: 25ms;
41 | -moz-animation-delay: 25ms;
42 | -o-animation-delay: 25ms;
43 | animation-delay: 25ms;
44 | }
45 |
--------------------------------------------------------------------------------
/example/infinite-scroll/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 |
7 | background-color: #EEFFD8;
8 | }
9 |
10 | #content {
11 | position: relative;
12 | }
13 |
14 | .jumbotron {
15 | background-color: transparent;
16 | .btn {
17 | position: static !important;
18 | left: auto !important;
19 | top: auto !important;
20 | margin: 0 !important;
21 | }
22 | }
23 |
24 | .item {
25 | @h: 80px;
26 |
27 | .lh-border-radius(5px);
28 |
29 | margin-bottom: 10px;
30 |
31 | text-align: center;
32 | min-height: @h;
33 | line-height: @h;
34 | color: #A662B2;
35 | font-size: 24px;
36 | border: 5px solid #F5BFFF;
37 | }
38 |
39 | .item-anim {
40 | &.ng-enter {
41 | .lh-animation(zoomInUp 800ms both);
42 |
43 | &-stagger {
44 | .lh-animation-delay(25ms);
45 | }
46 |
47 | &-active {
48 |
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/example/locals/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: locals
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
71 |
72 |
78 |
79 |
80 |
81 |
82 |
83 |
Stage:
84 |
Locals (scroll to observe)
85 |
86 |
87 |
88 |
sub
stage changes background color after scrolling pass the watcher
element.
89 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/example/locals/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | height: 5000px;
7 | }
8 | #locals {
9 | position: fixed;
10 | top: 0;
11 | left: 0;
12 | width: 100%;
13 | height: 100%;
14 | }
15 | #locals .container {
16 | -webkit-transform: translate(-50%, -50%);
17 | -moz-transform: translate(-50%, -50%);
18 | -ms-transform: translate(-50%, -50%);
19 | -o-transform: translate(-50%, -50%);
20 | transform: translate(-50%, -50%);
21 | position: absolute;
22 | top: 50%;
23 | left: 50%;
24 | }
25 | @media (max-width: 767px) {
26 | #locals .container {
27 | width: 85%;
28 | }
29 | }
30 | #locals pre {
31 | padding: 0;
32 | }
33 | #locals .hljs {
34 | font-size: 140%;
35 | }
36 | #sub-scroll-stage {
37 | -webkit-transition: background-color 350ms ease-out;
38 | -moz-transition: background-color 350ms ease-out;
39 | -o-transition: background-color 350ms ease-out;
40 | transition: background-color 350ms ease-out;
41 | -webkit-border-radius: 4px;
42 | -webkit-background-clip: padding-box;
43 | -moz-border-radius: 4px;
44 | -moz-background-clip: padding;
45 | border-radius: 4px;
46 | background-clip: padding-box;
47 | width: 100%;
48 | height: 348px;
49 | overflow-y: auto;
50 | border: 1px solid #ccc;
51 | }
52 | @media (max-width: 991px) {
53 | #sub-scroll-stage {
54 | height: 150px;
55 | }
56 | }
57 | #sub-scroll-stage.colored {
58 | background-color: rgba(190, 236, 238, 0.38);
59 | }
60 | #sub-scroll-stage .placeholder {
61 | position: relative;
62 | height: 1000px;
63 | }
64 | #sub-scroll-stage .placeholder .dot {
65 | position: absolute;
66 | top: 300px;
67 | left: 0;
68 | width: 100%;
69 | font-size: 24px;
70 | color: white;
71 | text-align: center;
72 | background-color: #3fa4ff;
73 | }
74 |
--------------------------------------------------------------------------------
/example/locals/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | height: 5000px;
10 | }
11 |
12 | #locals {
13 | position: fixed;
14 | top: 0;
15 | left: 0;
16 |
17 | width: 100%;
18 | height: 100%;
19 |
20 | .container {
21 | .lh-translate(-50%, -50%);
22 |
23 | position: absolute;
24 | top: 50%;
25 | left: 50%;
26 |
27 | @media (max-width: 767px) {
28 | width: 85%;
29 | }
30 | }
31 |
32 | pre {
33 | padding: 0;
34 | }
35 |
36 | .hljs {
37 | font-size: 140%;
38 | }
39 | }
40 |
41 | #sub-scroll-stage {
42 | .lh-transition(background-color 350ms ease-out);
43 | .lh-border-radius(4px);
44 |
45 | width: 100%;
46 | height: 348px;
47 |
48 | overflow-y: auto;
49 | border: 1px solid #ccc;
50 |
51 | @media (max-width: 991px) {
52 | height: 150px;
53 | }
54 |
55 | &.colored {
56 | background-color: rgba(190, 236, 238, 0.38);
57 | }
58 |
59 | .placeholder {
60 | position: relative;
61 | height: 1000px;
62 |
63 | .dot {
64 | position: absolute;
65 | top: 300px;
66 | left: 0;
67 |
68 | width: 100%;
69 |
70 | font-size: 24px;
71 | color: white;
72 | text-align: center;
73 | background-color: rgba(63, 164, 255, 1);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/example/sw-broadcast-through-emit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-broadcast through $scope.$emit
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
50 |
51 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/example/sw-broadcast-through-emit/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | height: 5000px;
7 | }
8 | .slide {
9 | width: 100%;
10 | height: 100%;
11 | position: fixed;
12 | z-index: 1;
13 | left: 0;
14 | top: 0;
15 | color: white;
16 | }
17 | .slide h2 {
18 | -webkit-transform: translate(-50%, -50%);
19 | -moz-transform: translate(-50%, -50%);
20 | -ms-transform: translate(-50%, -50%);
21 | -o-transform: translate(-50%, -50%);
22 | transform: translate(-50%, -50%);
23 | position: fixed;
24 | top: 50%;
25 | left: 50%;
26 | font-size: 80px;
27 | }
28 | .slide.ng-hide-add,
29 | .slide.ng-hide-remove {
30 | display: block !important;
31 | }
32 | .slide--1 {
33 | background-color: #3498db;
34 | }
35 | .slide--1.ng-hide-add {
36 | -webkit-animation: bounceOut 1s both;
37 | -moz-animation: bounceOut 1s both;
38 | -o-animation: bounceOut 1s both;
39 | animation: bounceOut 1s both;
40 | }
41 | .slide--1.ng-hide-remove {
42 | -webkit-animation: bounceIn 1s 300ms both;
43 | -moz-animation: bounceIn 1s 300ms both;
44 | -o-animation: bounceIn 1s 300ms both;
45 | animation: bounceIn 1s 300ms both;
46 | z-index: 2;
47 | }
48 | .slide--2 {
49 | background-color: #e74c3c;
50 | }
51 | .slide--2.ng-hide-add {
52 | -webkit-animation: zoomOutRight 1s both;
53 | -moz-animation: zoomOutRight 1s both;
54 | -o-animation: zoomOutRight 1s both;
55 | animation: zoomOutRight 1s both;
56 | }
57 | .slide--2.ng-hide-remove {
58 | -webkit-animation: zoomInLeft 1s 300ms both;
59 | -moz-animation: zoomInLeft 1s 300ms both;
60 | -o-animation: zoomInLeft 1s 300ms both;
61 | animation: zoomInLeft 1s 300ms both;
62 | z-index: 2;
63 | }
64 | .slide--3 {
65 | background-color: #34495e;
66 | }
67 | .slide--3.ng-hide-add {
68 | -webkit-animation: fadeOutLeft 1s both;
69 | -moz-animation: fadeOutLeft 1s both;
70 | -o-animation: fadeOutLeft 1s both;
71 | animation: fadeOutLeft 1s both;
72 | }
73 | .slide--3.ng-hide-remove {
74 | -webkit-animation: fadeInRight 1s 300ms both;
75 | -moz-animation: fadeInRight 1s 300ms both;
76 | -o-animation: fadeInRight 1s 300ms both;
77 | animation: fadeInRight 1s 300ms both;
78 | z-index: 2;
79 | }
80 | .slide--4 {
81 | background-color: #1abc9c;
82 | }
83 | .slide--4.ng-hide-add {
84 | -webkit-animation: bounceOutDown 1s both;
85 | -moz-animation: bounceOutDown 1s both;
86 | -o-animation: bounceOutDown 1s both;
87 | animation: bounceOutDown 1s both;
88 | }
89 | .slide--4.ng-hide-remove {
90 | -webkit-animation: bounceInDown 1s 300ms both;
91 | -moz-animation: bounceInDown 1s 300ms both;
92 | -o-animation: bounceInDown 1s 300ms both;
93 | animation: bounceInDown 1s 300ms both;
94 | z-index: 2;
95 | }
96 | .slide--5 {
97 | background-color: #ecf0f1;
98 | color: #333;
99 | }
100 | .slide--5.ng-hide-add {
101 | -webkit-animation: zoomOutUp 1s both;
102 | -moz-animation: zoomOutUp 1s both;
103 | -o-animation: zoomOutUp 1s both;
104 | animation: zoomOutUp 1s both;
105 | }
106 | .slide--5.ng-hide-remove {
107 | -webkit-animation: zoomInUp 1s 300ms both;
108 | -moz-animation: zoomInUp 1s 300ms both;
109 | -o-animation: zoomInUp 1s 300ms both;
110 | animation: zoomInUp 1s 300ms both;
111 | z-index: 2;
112 | }
113 |
--------------------------------------------------------------------------------
/example/sw-broadcast-through-emit/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | height: 5000px;
10 | }
11 |
12 | .slide {
13 | .lh-size(100%);
14 |
15 | position: fixed; z-index: 1;
16 | left: 0;
17 | top: 0;
18 |
19 | color: white;
20 |
21 | h2 {
22 | .lh-translate(-50%, -50%);
23 |
24 | position: fixed;
25 | top: 50%;
26 | left: 50%;
27 |
28 | font-size: 80px;
29 | }
30 |
31 | &.ng-hide-add, &.ng-hide-remove {
32 | display: block !important;
33 | }
34 |
35 | .setup-anim (@show; @hide) {
36 | &.ng-hide-add {
37 | .lh-animation(@hide 1s both);
38 | }
39 | &.ng-hide-remove {
40 | .lh-animation(@show 1s 300ms both);
41 | z-index: 2;
42 | }
43 | }
44 |
45 | &--1 {
46 | .setup-anim(bounceIn; bounceOut);
47 | background-color: #3498db;
48 | }
49 | &--2 {
50 | .setup-anim(zoomInLeft; zoomOutRight);
51 | background-color: #e74c3c;
52 | }
53 | &--3 {
54 | .setup-anim(fadeInRight; fadeOutLeft);
55 | background-color: #34495e;
56 | }
57 | &--4 {
58 | .setup-anim(bounceInDown; bounceOutDown);
59 | background-color: #1abc9c;
60 | }
61 | &--5 {
62 | .setup-anim(zoomInUp; zoomOutUp);
63 | background-color: #ecf0f1;
64 | color: #333;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/example/sw-broadcast/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-broadcast
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
54 |
55 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/example/sw-broadcast/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | height: 5000px;
7 | }
8 | .slide {
9 | width: 100%;
10 | height: 100%;
11 | position: fixed;
12 | z-index: 1;
13 | left: 0;
14 | top: 0;
15 | color: white;
16 | }
17 | .slide h2 {
18 | -webkit-transform: translate(-50%, -50%);
19 | -moz-transform: translate(-50%, -50%);
20 | -ms-transform: translate(-50%, -50%);
21 | -o-transform: translate(-50%, -50%);
22 | transform: translate(-50%, -50%);
23 | position: fixed;
24 | top: 50%;
25 | left: 50%;
26 | font-size: 80px;
27 | }
28 | .slide.ng-hide-add,
29 | .slide.ng-hide-remove {
30 | display: block !important;
31 | }
32 | .slide--1 {
33 | background-color: #3498db;
34 | }
35 | .slide--1.ng-hide-add {
36 | -webkit-animation: bounceOut 1s both;
37 | -moz-animation: bounceOut 1s both;
38 | -o-animation: bounceOut 1s both;
39 | animation: bounceOut 1s both;
40 | }
41 | .slide--1.ng-hide-remove {
42 | -webkit-animation: bounceIn 1s 300ms both;
43 | -moz-animation: bounceIn 1s 300ms both;
44 | -o-animation: bounceIn 1s 300ms both;
45 | animation: bounceIn 1s 300ms both;
46 | z-index: 2;
47 | }
48 | .slide--2 {
49 | background-color: #e74c3c;
50 | }
51 | .slide--2.ng-hide-add {
52 | -webkit-animation: zoomOutRight 1s both;
53 | -moz-animation: zoomOutRight 1s both;
54 | -o-animation: zoomOutRight 1s both;
55 | animation: zoomOutRight 1s both;
56 | }
57 | .slide--2.ng-hide-remove {
58 | -webkit-animation: zoomInLeft 1s 300ms both;
59 | -moz-animation: zoomInLeft 1s 300ms both;
60 | -o-animation: zoomInLeft 1s 300ms both;
61 | animation: zoomInLeft 1s 300ms both;
62 | z-index: 2;
63 | }
64 | .slide--3 {
65 | background-color: #34495e;
66 | }
67 | .slide--3.ng-hide-add {
68 | -webkit-animation: fadeOutLeft 1s both;
69 | -moz-animation: fadeOutLeft 1s both;
70 | -o-animation: fadeOutLeft 1s both;
71 | animation: fadeOutLeft 1s both;
72 | }
73 | .slide--3.ng-hide-remove {
74 | -webkit-animation: fadeInRight 1s 300ms both;
75 | -moz-animation: fadeInRight 1s 300ms both;
76 | -o-animation: fadeInRight 1s 300ms both;
77 | animation: fadeInRight 1s 300ms both;
78 | z-index: 2;
79 | }
80 | .slide--4 {
81 | background-color: #1abc9c;
82 | }
83 | .slide--4.ng-hide-add {
84 | -webkit-animation: bounceOutDown 1s both;
85 | -moz-animation: bounceOutDown 1s both;
86 | -o-animation: bounceOutDown 1s both;
87 | animation: bounceOutDown 1s both;
88 | }
89 | .slide--4.ng-hide-remove {
90 | -webkit-animation: bounceInDown 1s 300ms both;
91 | -moz-animation: bounceInDown 1s 300ms both;
92 | -o-animation: bounceInDown 1s 300ms both;
93 | animation: bounceInDown 1s 300ms both;
94 | z-index: 2;
95 | }
96 | .slide--5 {
97 | background-color: #ecf0f1;
98 | color: #333;
99 | }
100 | .slide--5.ng-hide-add {
101 | -webkit-animation: zoomOutUp 1s both;
102 | -moz-animation: zoomOutUp 1s both;
103 | -o-animation: zoomOutUp 1s both;
104 | animation: zoomOutUp 1s both;
105 | }
106 | .slide--5.ng-hide-remove {
107 | -webkit-animation: zoomInUp 1s 300ms both;
108 | -moz-animation: zoomInUp 1s 300ms both;
109 | -o-animation: zoomInUp 1s 300ms both;
110 | animation: zoomInUp 1s 300ms both;
111 | z-index: 2;
112 | }
113 |
--------------------------------------------------------------------------------
/example/sw-broadcast/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | height: 5000px;
10 | }
11 |
12 | .slide {
13 | .lh-size(100%);
14 |
15 | position: fixed; z-index: 1;
16 | left: 0;
17 | top: 0;
18 |
19 | color: white;
20 |
21 | h2 {
22 | .lh-translate(-50%, -50%);
23 |
24 | position: fixed;
25 | top: 50%;
26 | left: 50%;
27 |
28 | font-size: 80px;
29 | }
30 |
31 | &.ng-hide-add, &.ng-hide-remove {
32 | display: block !important;
33 | }
34 |
35 | .setup-anim (@show; @hide) {
36 | &.ng-hide-add {
37 | .lh-animation(@hide 1s both);
38 | }
39 | &.ng-hide-remove {
40 | .lh-animation(@show 1s 300ms both);
41 | z-index: 2;
42 | }
43 | }
44 |
45 | &--1 {
46 | .setup-anim(bounceIn; bounceOut);
47 | background-color: #3498db;
48 | }
49 | &--2 {
50 | .setup-anim(zoomInLeft; zoomOutRight);
51 | background-color: #e74c3c;
52 | }
53 | &--3 {
54 | .setup-anim(fadeInRight; fadeOutLeft);
55 | background-color: #34495e;
56 | }
57 | &--4 {
58 | .setup-anim(bounceInDown; bounceOutDown);
59 | background-color: #1abc9c;
60 | }
61 | &--5 {
62 | .setup-anim(zoomInUp; zoomOutUp);
63 | background-color: #ecf0f1;
64 | color: #333;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/example/sw-class-with-ng-repeat/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-class with ng-repeat
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
87 |
88 |
89 |
90 |
91 |
100 |
101 |
106 |
107 |
108 |
109 |
110 |
How much angular do you want?
111 |
112 |
113 |
114 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/example/sw-class-with-ng-repeat/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | background-color: #333;
7 | height: 10000px;
8 | }
9 | #form {
10 | -webkit-transform: translate(-50%, -50%);
11 | -moz-transform: translate(-50%, -50%);
12 | -ms-transform: translate(-50%, -50%);
13 | -o-transform: translate(-50%, -50%);
14 | transform: translate(-50%, -50%);
15 | width: 600px;
16 | height: 230px;
17 | -webkit-border-radius: 5px;
18 | -webkit-background-clip: padding-box;
19 | -moz-border-radius: 5px;
20 | -moz-background-clip: padding;
21 | border-radius: 5px;
22 | background-clip: padding-box;
23 | position: fixed;
24 | top: 50%;
25 | left: 50%;
26 | z-index: 10;
27 | text-align: center;
28 | padding: 0 30px;
29 | background-color: rgba(177, 161, 120, 0.42);
30 | }
31 | #form h2 {
32 | margin-bottom: 20px;
33 | color: #ffd16e;
34 | text-shadow: 0 1px 1px #553e03;
35 | }
36 | #form input {
37 | height: 120px;
38 | font-size: 80px;
39 | text-align: center;
40 | }
41 | #angular-container {
42 | width: 100%;
43 | height: 100%;
44 | position: fixed;
45 | top: 0;
46 | left: 0;
47 | z-index: 5;
48 | }
49 | #angular-container .angular {
50 | position: absolute;
51 | }
52 | #angular-container .angular img {
53 | opacity: 0.8;
54 | }
55 | #angular-container .anim-1 {
56 | display: none;
57 | }
58 | #angular-container .anim-1.in-view {
59 | display: block;
60 | }
61 | #angular-container .anim-1.in-view-add {
62 | -webkit-animation: bounceInDown 1s both;
63 | -moz-animation: bounceInDown 1s both;
64 | -o-animation: bounceInDown 1s both;
65 | animation: bounceInDown 1s both;
66 | }
67 | #angular-container .anim-1.in-view-remove {
68 | -webkit-animation: bounceOutDown 1s both;
69 | -moz-animation: bounceOutDown 1s both;
70 | -o-animation: bounceOutDown 1s both;
71 | animation: bounceOutDown 1s both;
72 | display: block;
73 | }
74 | #angular-container .anim-2 {
75 | display: none;
76 | }
77 | #angular-container .anim-2.in-view {
78 | display: block;
79 | }
80 | #angular-container .anim-2.in-view-add {
81 | -webkit-animation: bounceInRight 1s both;
82 | -moz-animation: bounceInRight 1s both;
83 | -o-animation: bounceInRight 1s both;
84 | animation: bounceInRight 1s both;
85 | }
86 | #angular-container .anim-2.in-view-remove {
87 | -webkit-animation: bounceOutLeft 1s both;
88 | -moz-animation: bounceOutLeft 1s both;
89 | -o-animation: bounceOutLeft 1s both;
90 | animation: bounceOutLeft 1s both;
91 | display: block;
92 | }
93 | #angular-container .anim-3 {
94 | display: none;
95 | }
96 | #angular-container .anim-3.in-view {
97 | display: block;
98 | }
99 | #angular-container .anim-3.in-view-add {
100 | -webkit-animation: bounceInUp 1s both;
101 | -moz-animation: bounceInUp 1s both;
102 | -o-animation: bounceInUp 1s both;
103 | animation: bounceInUp 1s both;
104 | }
105 | #angular-container .anim-3.in-view-remove {
106 | -webkit-animation: bounceOutUp 1s both;
107 | -moz-animation: bounceOutUp 1s both;
108 | -o-animation: bounceOutUp 1s both;
109 | animation: bounceOutUp 1s both;
110 | display: block;
111 | }
112 | #angular-container .anim-4 {
113 | display: none;
114 | }
115 | #angular-container .anim-4.in-view {
116 | display: block;
117 | }
118 | #angular-container .anim-4.in-view-add {
119 | -webkit-animation: fadeInDown 1s both;
120 | -moz-animation: fadeInDown 1s both;
121 | -o-animation: fadeInDown 1s both;
122 | animation: fadeInDown 1s both;
123 | }
124 | #angular-container .anim-4.in-view-remove {
125 | -webkit-animation: fadeOutDown 1s both;
126 | -moz-animation: fadeOutDown 1s both;
127 | -o-animation: fadeOutDown 1s both;
128 | animation: fadeOutDown 1s both;
129 | display: block;
130 | }
131 | #angular-container .anim-5 {
132 | display: none;
133 | }
134 | #angular-container .anim-5.in-view {
135 | display: block;
136 | }
137 | #angular-container .anim-5.in-view-add {
138 | -webkit-animation: fadeInRight 1s both;
139 | -moz-animation: fadeInRight 1s both;
140 | -o-animation: fadeInRight 1s both;
141 | animation: fadeInRight 1s both;
142 | }
143 | #angular-container .anim-5.in-view-remove {
144 | -webkit-animation: fadeOutLeft 1s both;
145 | -moz-animation: fadeOutLeft 1s both;
146 | -o-animation: fadeOutLeft 1s both;
147 | animation: fadeOutLeft 1s both;
148 | display: block;
149 | }
150 | #angular-container .anim-6 {
151 | display: none;
152 | }
153 | #angular-container .anim-6.in-view {
154 | display: block;
155 | }
156 | #angular-container .anim-6.in-view-add {
157 | -webkit-animation: fadeInUp 1s both;
158 | -moz-animation: fadeInUp 1s both;
159 | -o-animation: fadeInUp 1s both;
160 | animation: fadeInUp 1s both;
161 | }
162 | #angular-container .anim-6.in-view-remove {
163 | -webkit-animation: fadeOutUp 1s both;
164 | -moz-animation: fadeOutUp 1s both;
165 | -o-animation: fadeOutUp 1s both;
166 | animation: fadeOutUp 1s both;
167 | display: block;
168 | }
169 | #angular-container .anim-7 {
170 | display: none;
171 | }
172 | #angular-container .anim-7.in-view {
173 | display: block;
174 | }
175 | #angular-container .anim-7.in-view-add {
176 | -webkit-animation: rotateIn 1s both;
177 | -moz-animation: rotateIn 1s both;
178 | -o-animation: rotateIn 1s both;
179 | animation: rotateIn 1s both;
180 | }
181 | #angular-container .anim-7.in-view-remove {
182 | -webkit-animation: rotateOut 1s both;
183 | -moz-animation: rotateOut 1s both;
184 | -o-animation: rotateOut 1s both;
185 | animation: rotateOut 1s both;
186 | display: block;
187 | }
188 | #angular-container .anim-8 {
189 | display: none;
190 | }
191 | #angular-container .anim-8.in-view {
192 | display: block;
193 | }
194 | #angular-container .anim-8.in-view-add {
195 | -webkit-animation: flipInX 1s both;
196 | -moz-animation: flipInX 1s both;
197 | -o-animation: flipInX 1s both;
198 | animation: flipInX 1s both;
199 | }
200 | #angular-container .anim-8.in-view-remove {
201 | -webkit-animation: flipOutX 1s both;
202 | -moz-animation: flipOutX 1s both;
203 | -o-animation: flipOutX 1s both;
204 | animation: flipOutX 1s both;
205 | display: block;
206 | }
207 | #angular-container .anim-9 {
208 | display: none;
209 | }
210 | #angular-container .anim-9.in-view {
211 | display: block;
212 | }
213 | #angular-container .anim-9.in-view-add {
214 | -webkit-animation: flipInY 1s both;
215 | -moz-animation: flipInY 1s both;
216 | -o-animation: flipInY 1s both;
217 | animation: flipInY 1s both;
218 | }
219 | #angular-container .anim-9.in-view-remove {
220 | -webkit-animation: flipOutY 1s both;
221 | -moz-animation: flipOutY 1s both;
222 | -o-animation: flipOutY 1s both;
223 | animation: flipOutY 1s both;
224 | display: block;
225 | }
226 | #angular-container .anim-10 {
227 | display: none;
228 | }
229 | #angular-container .anim-10.in-view {
230 | display: block;
231 | }
232 | #angular-container .anim-10.in-view-add {
233 | -webkit-animation: zoomInDown 1s both;
234 | -moz-animation: zoomInDown 1s both;
235 | -o-animation: zoomInDown 1s both;
236 | animation: zoomInDown 1s both;
237 | }
238 | #angular-container .anim-10.in-view-remove {
239 | -webkit-animation: zoomOutDown 1s both;
240 | -moz-animation: zoomOutDown 1s both;
241 | -o-animation: zoomOutDown 1s both;
242 | animation: zoomOutDown 1s both;
243 | display: block;
244 | }
245 | #angular-container .anim-11 {
246 | display: none;
247 | }
248 | #angular-container .anim-11.in-view {
249 | display: block;
250 | }
251 | #angular-container .anim-11.in-view-add {
252 | -webkit-animation: zoomInRight 1s both;
253 | -moz-animation: zoomInRight 1s both;
254 | -o-animation: zoomInRight 1s both;
255 | animation: zoomInRight 1s both;
256 | }
257 | #angular-container .anim-11.in-view-remove {
258 | -webkit-animation: zoomOutLeft 1s both;
259 | -moz-animation: zoomOutLeft 1s both;
260 | -o-animation: zoomOutLeft 1s both;
261 | animation: zoomOutLeft 1s both;
262 | display: block;
263 | }
264 | #angular-container .anim-12 {
265 | display: none;
266 | }
267 | #angular-container .anim-12.in-view {
268 | display: block;
269 | }
270 | #angular-container .anim-12.in-view-add {
271 | -webkit-animation: zoomInUp 1s both;
272 | -moz-animation: zoomInUp 1s both;
273 | -o-animation: zoomInUp 1s both;
274 | animation: zoomInUp 1s both;
275 | }
276 | #angular-container .anim-12.in-view-remove {
277 | -webkit-animation: zoomOutUp 1s both;
278 | -moz-animation: zoomOutUp 1s both;
279 | -o-animation: zoomOutUp 1s both;
280 | animation: zoomOutUp 1s both;
281 | display: block;
282 | }
283 | #angular-container .anim-13 {
284 | display: none;
285 | }
286 | #angular-container .anim-13.in-view {
287 | display: block;
288 | }
289 | #angular-container .anim-13.in-view-add {
290 | -webkit-animation: rollIn 1s both;
291 | -moz-animation: rollIn 1s both;
292 | -o-animation: rollIn 1s both;
293 | animation: rollIn 1s both;
294 | }
295 | #angular-container .anim-13.in-view-remove {
296 | -webkit-animation: rollOut 1s both;
297 | -moz-animation: rollOut 1s both;
298 | -o-animation: rollOut 1s both;
299 | animation: rollOut 1s both;
300 | display: block;
301 | }
302 |
--------------------------------------------------------------------------------
/example/sw-class-with-ng-repeat/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | background-color: #333;
10 | height: 10000px;
11 | }
12 |
13 | #form {
14 | .lh-translate(-50%, -50%);
15 | .lh-size(600px, 230px);
16 | .lh-border-radius(5px);
17 |
18 | position: fixed;
19 | top: 50%;
20 | left: 50%;
21 | z-index: 10;
22 |
23 | text-align: center;
24 |
25 | padding: 0 30px;
26 | background-color: rgba(177, 161, 120, 0.42);
27 |
28 | h2 {
29 | margin-bottom: 20px;
30 | color: rgb(255, 209, 110);
31 | text-shadow: 0 1px 1px rgb(85, 62, 3);
32 | }
33 |
34 | input {
35 | @font-size: 80px;
36 | @line-height: 1.5;
37 | height: @font-size * @line-height;
38 | font-size: @font-size;
39 | text-align: center;
40 | }
41 | }
42 |
43 | #angular-container {
44 | .lh-size(100%);
45 |
46 | position: fixed;
47 | top: 0; left: 0;
48 | z-index: 5;
49 |
50 | .angular {
51 | position: absolute;
52 |
53 | img {
54 | opacity: 0.8;
55 | }
56 | }
57 |
58 | .setup-anim (@no; @add-anim; @remove-anim) {
59 | .anim-@{no} {
60 | display: none;
61 |
62 | &.in-view {
63 | display: block;
64 |
65 | &-add {
66 | .lh-animation(@add-anim 1s both);
67 | }
68 | &-remove {
69 | .lh-animation(@remove-anim 1s both);
70 | display: block;
71 | }
72 | }
73 | }
74 | }
75 |
76 | .setup-anim(1; bounceInDown; bounceOutDown);
77 | .setup-anim(2; bounceInRight; bounceOutLeft);
78 | .setup-anim(3; bounceInUp; bounceOutUp);
79 |
80 | .setup-anim(4; fadeInDown; fadeOutDown);
81 | .setup-anim(5; fadeInRight; fadeOutLeft);
82 | .setup-anim(6; fadeInUp; fadeOutUp);
83 |
84 | .setup-anim(7; rotateIn; rotateOut);
85 |
86 | .setup-anim(8; flipInX; flipOutX);
87 | .setup-anim(9; flipInY; flipOutY);
88 |
89 | .setup-anim(10; zoomInDown; zoomOutDown);
90 | .setup-anim(11; zoomInRight; zoomOutLeft);
91 | .setup-anim(12; zoomInUp; zoomOutUp);
92 |
93 | .setup-anim(13; rollIn; rollOut);
94 | }
95 |
--------------------------------------------------------------------------------
/example/sw-class/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-class
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
49 |
50 |
51 |
52 | Stay with me!!
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/example/sw-class/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB2aWV3Qm94PSIwIDAgMSAxIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIj48bGluZWFyR3JhZGllbnQgaWQ9Imxlc3NoYXQtZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9IiNmYWM2OTUiIHN0b3Atb3BhY2l0eT0iMSIvPjxzdG9wIG9mZnNldD0iNDclIiBzdG9wLWNvbG9yPSIjZjVhYjY2IiBzdG9wLW9wYWNpdHk9IjEiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlZjhkMzEiIHN0b3Atb3BhY2l0eT0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNsZXNzaGF0LWdlbmVyYXRlZCkiIC8+PC9zdmc+);
7 | background-image: -webkit-linear-gradient(0deg, #fac695 0, #f5ab66 47%, #ef8d31 100%);
8 | background-image: -moz-linear-gradient(0deg, #fac695 0, #f5ab66 47%, #ef8d31 100%);
9 | background-image: -o-linear-gradient(0deg, #fac695 0, #f5ab66 47%, #ef8d31 100%);
10 | background-image: linear-gradient(90deg, #fac695 0, #f5ab66 47%, #ef8d31 100%);
11 | -webkit-background-size: auto auto;
12 | -moz-background-size: auto auto;
13 | background-size: auto auto;
14 | -webkit-background-origin: padding-box;
15 | -moz-background-origin: padding-box;
16 | background-origin: padding-box;
17 | -webkit-background-clip: border-box;
18 | -moz-background-clip: border-box;
19 | background-clip: border-box;
20 | height: 5000px;
21 | }
22 | #hero {
23 | -webkit-transform: translate(-50%, -50%);
24 | -moz-transform: translate(-50%, -50%);
25 | -ms-transform: translate(-50%, -50%);
26 | -o-transform: translate(-50%, -50%);
27 | transform: translate(-50%, -50%);
28 | position: fixed;
29 | top: 50%;
30 | left: 50%;
31 | }
32 | .p20 {
33 | font-size: 20px;
34 | }
35 | .p20-add {
36 | -webkit-animation: shake 1s;
37 | -moz-animation: shake 1s;
38 | -o-animation: shake 1s;
39 | animation: shake 1s;
40 | font-size: 20px;
41 | }
42 | .p20-remove {
43 | -webkit-transition: all 500ms ease-in-out;
44 | -moz-transition: all 500ms ease-in-out;
45 | -o-transition: all 500ms ease-in-out;
46 | transition: all 500ms ease-in-out;
47 | }
48 | .p40 {
49 | font-size: 60px;
50 | }
51 | .p40-add {
52 | -webkit-animation: tada 1s;
53 | -moz-animation: tada 1s;
54 | -o-animation: tada 1s;
55 | animation: tada 1s;
56 | font-size: 60px;
57 | }
58 | .p40-remove {
59 | -webkit-transition: all 500ms ease-in-out;
60 | -moz-transition: all 500ms ease-in-out;
61 | -o-transition: all 500ms ease-in-out;
62 | transition: all 500ms ease-in-out;
63 | }
64 | .p80 {
65 | font-size: 100px;
66 | }
67 | .p80-add {
68 | -webkit-animation: rubberBand 1s;
69 | -moz-animation: rubberBand 1s;
70 | -o-animation: rubberBand 1s;
71 | animation: rubberBand 1s;
72 | font-size: 100px;
73 | }
74 | .p80-remove {
75 | -webkit-transition: all 500ms ease-in-out;
76 | -moz-transition: all 500ms ease-in-out;
77 | -o-transition: all 500ms ease-in-out;
78 | transition: all 500ms ease-in-out;
79 | }
80 | .p100 {
81 | font-size: 140px;
82 | }
83 | .p100-add {
84 | -webkit-animation: flip 1s;
85 | -moz-animation: flip 1s;
86 | -o-animation: flip 1s;
87 | animation: flip 1s;
88 | font-size: 140px;
89 | }
90 | .p100-remove {
91 | -webkit-transition: all 500ms ease-in-out;
92 | -moz-transition: all 500ms ease-in-out;
93 | -o-transition: all 500ms ease-in-out;
94 | transition: all 500ms ease-in-out;
95 | }
96 |
--------------------------------------------------------------------------------
/example/sw-class/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | .lh-background-image(linear-gradient(90deg, rgba(250,198,149,1) 0, rgba(245,171,102,1) 47%, rgba(239,141,49,1) 100%));
10 | .lh-background-size(auto, auto);
11 | .lh-background-origin(padding-box);
12 | .lh-background-clip(border-box);
13 |
14 | height: 5000px;
15 | }
16 |
17 | #hero {
18 | .lh-translate(-50%, -50%);
19 |
20 | position: fixed;
21 | top: 50%;
22 | left: 50%;
23 | }
24 |
25 | .make-progress(@font-size; @animation) {
26 | font-size: @font-size;
27 |
28 | &-add {
29 | .lh-animation(@animation);
30 | font-size: @font-size;
31 | }
32 | &-remove {
33 | .lh-transition(all 500ms ease-in-out);
34 | }
35 | }
36 |
37 | .p20 {
38 | .make-progress(20px; shake 1s);
39 | }
40 |
41 | .p40 {
42 | .make-progress(60px; tada 1s);
43 | }
44 |
45 | .p80 {
46 | .make-progress(100px; rubberBand 1s);
47 | }
48 |
49 | .p100 {
50 | .make-progress(140px; flip 1s);
51 | }
52 |
--------------------------------------------------------------------------------
/example/sw-stage/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-stage
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
65 |
66 |
67 |
68 |
74 |
75 |
87 |
88 |
89 |
92 |
93 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/example/sw-stage/style.css:
--------------------------------------------------------------------------------
1 | lesshat-selector {
2 | -lh-property: 0; }
3 | @-webkit-keyframes rotating{ from{-webkit-transform: rotateY(0);} to{-webkit-transform: rotateY(360deg);}}
4 | @-moz-keyframes rotating{ from{-moz-transform: rotateY(0);} to{-moz-transform: rotateY(360deg);}}
5 | @-o-keyframes rotating{ from{-o-transform: rotateY(0);} to{-o-transform: rotateY(360deg);}}
6 | @keyframes rotating{ from{-webkit-transform: rotateY(0);-moz-transform: rotateY(0);-ms-transform: rotateY(0);transform: rotateY(0);} to{-webkit-transform: rotateY(360deg);-moz-transform: rotateY(360deg);-ms-transform: rotateY(360deg);transform: rotateY(360deg);};
7 | }
8 | body {
9 | margin: 0;
10 | padding: 0;
11 | }
12 | #wrap {
13 | -webkit-transform: translate(-50%, -50%);
14 | -moz-transform: translate(-50%, -50%);
15 | -ms-transform: translate(-50%, -50%);
16 | -o-transform: translate(-50%, -50%);
17 | transform: translate(-50%, -50%);
18 | position: fixed;
19 | top: 50%;
20 | left: 50%;
21 | height: 60%;
22 | }
23 | .speed-control,
24 | .size-control {
25 | position: absolute;
26 | left: -170px;
27 | top: 0;
28 | width: 120px;
29 | height: 100%;
30 | max-height: 415px;
31 | overflow-y: auto;
32 | background-color: rgba(0, 0, 0, 0.3);
33 | }
34 | .speed-control__height,
35 | .size-control__height {
36 | height: 400%;
37 | }
38 | .speed-control:hover,
39 | .size-control:hover {
40 | background-color: rgba(0, 0, 0, 0.5);
41 | }
42 | .size-control {
43 | left: auto;
44 | right: -170px;
45 | }
46 | .shield-holder {
47 | -webkit-perspective: 400px;
48 | -moz-perspective: 400px;
49 | perspective: 400px;
50 | }
51 | .shield-holder img {
52 | display: block;
53 | }
54 | .shield-holder img.anim {
55 | -webkit-animation: rotating 4s linear both infinite;
56 | -moz-animation: rotating 4s linear both infinite;
57 | -o-animation: rotating 4s linear both infinite;
58 | animation: rotating 4s linear both infinite;
59 | }
60 | .shield-holder img.anim.paused {
61 | -webkit-animation-play-state: paused;
62 | -moz-animation-play-state: paused;
63 | -o-animation-play-state: paused;
64 | animation-play-state: paused;
65 | }
66 |
--------------------------------------------------------------------------------
/example/sw-stage/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | .lh-keyframes(~"rotating, from{transform: rotateY(0);} to{transform: rotateY(360deg);}");
4 |
5 | @control-width: 120px;
6 | @control-offset: 50px;
7 |
8 | body {
9 | margin: 0;
10 | padding: 0;
11 | }
12 |
13 | #wrap {
14 | .lh-translate(-50%, -50%);
15 |
16 | position: fixed;
17 | top: 50%;
18 | left: 50%;
19 |
20 | height: 60%;
21 | }
22 |
23 | .speed-control {
24 | position: absolute;
25 | left: -(@control-width + @control-offset); top: 0;
26 |
27 | width: @control-width;
28 | height: 100%;
29 | max-height: 415px;
30 |
31 | overflow-y: auto;
32 |
33 | background-color: rgba(0, 0, 0, 0.3);
34 |
35 | &__height {
36 | height: 400%;
37 | }
38 |
39 | &:hover {
40 | background-color: rgba(0, 0, 0, 0.5);
41 | }
42 | }
43 |
44 | .size-control {
45 | &:extend(.speed-control all);
46 |
47 | left: auto;
48 | right: -(@control-width + @control-offset);
49 | }
50 |
51 |
52 | .shield-holder {
53 | .lh-perspective(400);
54 |
55 | img {
56 | display: block;
57 | &.anim {
58 | .lh-animation(rotating 4s linear both infinite);
59 |
60 | &.paused {
61 | .lh-animation-play-state(paused);
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/example/sw-style-touch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | angular-scroll-watch: sw-style touch-enabled
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
52 |
53 |
58 |
59 |
60 | YA!!
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/example/sw-style-touch/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #touch-wrap {
6 | width: 100%;
7 | height: 100vh;
8 | overflow-y: auto;
9 | }
10 | #scroll-stage {
11 | height: 150vh;
12 | }
13 | #hero {
14 | -webkit-transform: translate(-50%, -50%);
15 | -moz-transform: translate(-50%, -50%);
16 | -ms-transform: translate(-50%, -50%);
17 | -o-transform: translate(-50%, -50%);
18 | transform: translate(-50%, -50%);
19 | -webkit-perspective: 400px;
20 | -moz-perspective: 400px;
21 | perspective: 400px;
22 | position: fixed;
23 | top: 50%;
24 | left: 50%;
25 | pointer-events: none;
26 | }
27 | #hero .text {
28 | font-size: 200%;
29 | }
30 |
--------------------------------------------------------------------------------
/example/sw-style-touch/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #touch-wrap {
9 | width: 100%;
10 | height: 100vh;
11 |
12 | overflow-y: auto;
13 | }
14 |
15 | #scroll-stage {
16 | height: 150vh;
17 | }
18 |
19 | #hero {
20 | .lh-translate(-50%, -50%);
21 | .lh-perspective(400);
22 |
23 | position: fixed;
24 | top: 50%;
25 | left: 50%;
26 |
27 | pointer-events: none;
28 |
29 | .text {
30 | font-size: 200%;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/example/sw-style/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | angular-scroll-watch: sw-style
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
50 |
51 |
54 |
55 |
56 |
62 | Stay with me!!
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/example/sw-style/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | #scroll-stage {
6 | height: 5000px;
7 | }
8 | #hero {
9 | -webkit-transform: translate(-50%, -50%);
10 | -moz-transform: translate(-50%, -50%);
11 | -ms-transform: translate(-50%, -50%);
12 | -o-transform: translate(-50%, -50%);
13 | transform: translate(-50%, -50%);
14 | position: fixed;
15 | top: 50%;
16 | left: 50%;
17 | }
18 |
--------------------------------------------------------------------------------
/example/sw-style/style.less:
--------------------------------------------------------------------------------
1 | @import "../assets/lesshat-prefixed";
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | }
7 |
8 | #scroll-stage {
9 | height: 5000px;
10 | }
11 |
12 | #hero {
13 | .lh-translate(-50%, -50%);
14 |
15 | position: fixed;
16 | top: 50%;
17 | left: 50%;
18 | }
19 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /*global require*/
2 | var gulp = require('gulp'),
3 | gutil = require('gulp-util');
4 |
5 | var connect = require('gulp-connect'),
6 | livereload = require('gulp-livereload'),
7 | uglify = require('gulp-uglify'),
8 | jshint = require('gulp-jshint'),
9 | changed = require('gulp-changed'),
10 | cache = require('gulp-cached'),
11 | rename = require('gulp-rename'),
12 | annotate = require('gulp-ng-annotate'),
13 | header = require('gulp-header'),
14 | less = require('gulp-less');
15 |
16 | var pkg = require('./package.json');
17 |
18 | var getTodayStr = function () {
19 | var date = new Date(),
20 | y = date.getFullYear(),
21 | m = date.getMonth() + 1,
22 | d = date.getDate();
23 |
24 | return y + '-' + m + '-' + d;
25 | };
26 |
27 | var config = {
28 | appRoot: '',
29 | src: 'src/angular-scroll-watch.js',
30 | buildDir: 'build',
31 | banner: '/*! <%= pkg.name %>\n' +
32 | 'version: <%= pkg.version %>\n' +
33 | 'build date: <%= today %>\n' +
34 | 'author: <%= pkg.author %>\n' +
35 | '<%= pkg.repository.url %> */\n'
36 | };
37 |
38 | gulp.task('build', ['lint'], function () {
39 | return gulp.src(config.src)
40 | .pipe(annotate())
41 | .pipe(header(config.banner, {pkg: pkg, today: getTodayStr()}))
42 | .pipe(gulp.dest(config.buildDir))
43 | .pipe(uglify())
44 | .pipe(rename({extname: '.min.js'}))
45 | .pipe(header(config.banner, {pkg: pkg, today: getTodayStr()}))
46 | .pipe(gulp.dest(config.buildDir));
47 | });
48 | gulp.task('lint', function () {
49 | return gulp.src(config.src)
50 | .pipe(jshint())
51 | .pipe(jshint.reporter('jshint-stylish'));
52 | });
53 | gulp.task('watch', function () {
54 | gulp.watch(config.src, ['build']);
55 | });
56 |
57 |
58 | gulp.task('server', function () {
59 | connect.server({
60 | root: config.appRoot,
61 | port: 9000
62 | });
63 | });
64 | gulp.task('watch:example', function () {
65 | livereload.listen();
66 |
67 | var paths = [
68 | config.src,
69 | 'example/{,**/}*.{js,html,css}',
70 | 'example/*/*.less'
71 | ];
72 | gulp.watch(paths, ['lint:example', 'less:example'])
73 | .on('change', livereload.changed);
74 | });
75 | gulp.task('lint:example', function () {
76 | return gulp.src('example/{,**/}*.{html,js}', {base: './'})
77 | .pipe(cache('lint-example'))
78 | .pipe(jshint.extract('auto'))
79 | .pipe(jshint())
80 | .pipe(jshint.reporter('jshint-stylish'));
81 | });
82 | gulp.task('less:example', function () {
83 | return gulp.src('example/*/style.less', {base: './'})
84 | .pipe(changed('./', {extension: '.css'}))
85 | .pipe(less())
86 | .pipe(gulp.dest('./'));
87 | });
88 |
89 | gulp.task('default', ['build']);
90 | gulp.task('example', ['server', 'watch', 'watch:example']);
91 |
--------------------------------------------------------------------------------
/images/how_much_angular_do_you_want.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pc035860/angular-scroll-watch/74f98efe97c5a8ea7f160cd027c60d2d05191e85/images/how_much_angular_do_you_want.gif
--------------------------------------------------------------------------------
/images/lovely_slides.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pc035860/angular-scroll-watch/74f98efe97c5a8ea7f160cd027c60d2d05191e85/images/lovely_slides.gif
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-scroll-watch",
3 | "version": "0.6.1",
4 | "description": "Basic scroll-aware directives for AngularJS.",
5 | "main": "build/angular-scroll-watch.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/pc035860/angular-scroll-watch.git"
12 | },
13 | "keywords": [
14 | "angularjs",
15 | "scroll"
16 | ],
17 | "author": {
18 | "name": "Chih-Hsuan Fan",
19 | "email": "pc035860@gmail.com"
20 | },
21 | "readmeFilename": "README.md",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/pc035860/angular-scroll-watch/issues"
25 | },
26 | "homepage": "https://github.com/pc035860/angular-scroll-watch",
27 | "dependencies": {
28 | "angular": "^1.2"
29 | },
30 | "devDependencies": {
31 | "gulp": "^3.8.6",
32 | "gulp-util": "^3.0.0",
33 | "gulp-connect": "^2.0.6",
34 | "gulp-livereload": "^2.1.0",
35 | "jshint-stylish": "^0.4.0",
36 | "gulp-jshint": "^1.8.4",
37 | "gulp-uglify": "^0.3.1",
38 | "gulp-changed": "^1.0.0",
39 | "gulp-rename": "^1.2.0",
40 | "gulp-ng-annotate": "^0.3.0",
41 | "gulp-header": "^1.0.5",
42 | "gulp-less": "^1.3.5",
43 | "gulp-cached": "^1.0.1"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/angular-scroll-watch.js:
--------------------------------------------------------------------------------
1 | /* jshint node:true */
2 | /* global define */
3 | (function (root, factory) {
4 | if (typeof exports === "object" || (typeof module === "object" && module.exports)) {
5 | module.exports = factory(require("angular"));
6 | } else if (typeof define === "function" && define.amd) {
7 | define(["angular"], factory);
8 | } else {
9 | root.returnExports = factory(root.angular);
10 | }
11 | }(this, function (angular) {
12 |
13 | var MODULE_NAME = 'pc035860.scrollWatch';
14 |
15 | var DIR_STYLE = 'swStyle',
16 | DIR_CLASS = 'swClass',
17 | DIR_BROADCAST = 'swBroadcast',
18 | DIR_STAGE = 'swStage';
19 |
20 | var STAGE_NAME_DEFAULT = 'pc035860';
21 |
22 | var CACHE_ID_STAGE_POOL = 'scrollWatch.stages';
23 |
24 | angular.module(MODULE_NAME, [])
25 |
26 | .factory('scrollWatchStageFactory', function (
27 | $window, $document, $parse, $log, $rootScope, $animate
28 | ) {
29 | // ref: http://davidwalsh.name/function-debounce
30 | var debounce = function (func, wait, immediate) {
31 | var timeout;
32 | return function() {
33 | var context = this, args = arguments;
34 | $window.clearTimeout(timeout);
35 | timeout = $window.setTimeout(function() {
36 | timeout = null;
37 | if (!immediate) func.apply(context, args);
38 | }, wait);
39 | if (immediate && !timeout) func.apply(context, args);
40 | };
41 | };
42 |
43 | var requestAnimFrame = (function () {
44 | return $window.requestAnimationFrame ||
45 | $window.webkitRequestAnimationFrame ||
46 | $window.mozRequestAnimationFrame ||
47 | $window.oRequestAnimationFrame ||
48 | $window.msRequestAnimationFrame ||
49 | function(/* function */ callback, /* DOMElement */ element){
50 | $window.setTimeout(callback, 1000 / 60);
51 | };
52 | })();
53 |
54 | var $win = angular.element($window);
55 |
56 | /**
57 | * Stage class
58 | */
59 | var Stage = function (name, $elm) {
60 | this.init(name, $elm);
61 | };
62 |
63 | var p = Stage.prototype;
64 |
65 | p.name = null;
66 | p.element = null;
67 | p.configs = null;
68 | p._configId = 0;
69 | p._binded = false;
70 |
71 | p.init = function (name, $elm) {
72 | this.name = name;
73 | this.element = $elm || null;
74 |
75 | this.scrollHandler = this._digest.bind(this);
76 | this._digestDebounced = debounce(this._digest, 50);
77 |
78 | this._digestDebounced();
79 | };
80 |
81 | p.setElement = function ($elm) {
82 | this.element = $elm;
83 |
84 | if (this.configs !== null && !this._binded) {
85 | this._bind(this.element);
86 | }
87 |
88 | this._digestDebounced();
89 | };
90 |
91 | p.clearElement = function () {
92 | if (this._binded) {
93 | this._unbind(this.element);
94 | }
95 | this.element = null;
96 | };
97 |
98 | p.addConfig = function (config) {
99 | angular.forEach(['target', 'from', 'to'], function (key) {
100 | if (angular.isUndefined(config[key])) {
101 | throw new Error('`'+ key +'` should be provided');
102 | }
103 | });
104 |
105 | if (this.configs === null) {
106 | this.configs = {};
107 |
108 | if (this.element !== null) {
109 | this._bind(this.element);
110 | }
111 | }
112 |
113 | this._configId++;
114 |
115 | if (config.styleExpr) {
116 | config.styleGetter = $parse(config.styleExpr);
117 | }
118 | if (config.classExpr) {
119 | config.classGetter = $parse(config.classExpr);
120 | }
121 | if (config.brdcstExpr) {
122 | var buf = config.scope.$eval(config.brdcstExpr);
123 |
124 | if (buf.$rootScope) {
125 | config.brdcstScope = $rootScope;
126 | delete buf.$rootScope;
127 | }
128 | else {
129 | config.brdcstScope = config.scope;
130 | }
131 |
132 | if (buf.$emit) {
133 | config.brdcstIsEmit = true;
134 | delete buf.$emit;
135 | }
136 | else {
137 | config.brdcstIsEmit = false;
138 | }
139 |
140 | config.brdcstList = [];
141 | angular.forEach(buf, function (expr, event) {
142 | var pack = {
143 | event: event
144 | };
145 |
146 | if (!angular.isString(expr)) {
147 | pack.always = true;
148 | }
149 | else {
150 | pack.condition = $parse(expr);
151 | pack.wasActive = null;
152 | }
153 |
154 | config.brdcstList.push(pack);
155 | });
156 | }
157 |
158 | this.configs[this._configId] = config;
159 |
160 | this._digestDebounced();
161 |
162 | return this._configId;
163 | };
164 |
165 | p.removeConfig = function (configId) {
166 | if (this.configs && this.configs[configId]) {
167 | delete this.configs[configId];
168 |
169 | if (objectSize(this.configs) === 0) {
170 | this.configs = null;
171 |
172 | if (this.element !== null) {
173 | this._unbind(this.element);
174 | }
175 | }
176 | }
177 | };
178 |
179 | p.digest = function (configId) {
180 | this._digest(null, configId);
181 | };
182 |
183 | p.destroy = function () {
184 | this.clearElement();
185 | this.configs = null;
186 | this.scrollHandler = null;
187 | this._digestDebounced = null;
188 | };
189 |
190 | p.couldDestroy = function () {
191 | return this.element === null && this.configs === null;
192 | };
193 |
194 | p._isDefault = function () {
195 | return this.element[0] === $window;
196 | };
197 |
198 | p._getElementMetrics = function ($elm) {
199 | var rect, metrics, scrollTop, elm, stageTop;
200 |
201 | elm = $elm[0];
202 | rect = elm.getBoundingClientRect();
203 | scrollTop = this._scrollTop();
204 |
205 | metrics = {
206 | offsetTop: rect.top + scrollTop
207 | };
208 |
209 | if (this._isDefault()) {
210 | stageTop = metrics.offsetTop;
211 | }
212 | else {
213 | stageTop = this._traverseStageTop(elm);
214 | }
215 |
216 | if (angular.isDefined(stageTop) && stageTop !== null) {
217 | metrics.stageTop = stageTop;
218 | }
219 |
220 | return metrics;
221 | };
222 |
223 | p._traverseStageTop = function (elm) {
224 | var stageElm = this.element[0],
225 | top = 0, cursor, progress;
226 |
227 | var updateProgress = function (cursor, progress) {
228 | if (!progress) {
229 | progress = {};
230 | }
231 | progress.parentNode = cursor.offsetParent;
232 | progress.offsetTop = cursor.offsetTop;
233 | progress.hitStage = progress.parentNode === stageElm;
234 | return progress;
235 | };
236 |
237 | var c = 0;
238 |
239 | cursor = elm;
240 | progress = updateProgress(cursor);
241 |
242 | do {
243 | cursor = cursor.parentNode || cursor;
244 |
245 | if (progress.parentNode === cursor) {
246 | top += progress.offsetTop;
247 |
248 | if (progress.hitStage) {
249 | return top;
250 | }
251 |
252 | progress = updateProgress(cursor, progress);
253 | }
254 | else if (cursor === stageElm) {
255 | return top + progress.offsetTop - stageElm.offsetTop;
256 | }
257 |
258 | if (++c >= 10) {
259 | break;
260 | }
261 | } while (cursor.tagName !== 'BODY' || elm === cursor);
262 |
263 | return null;
264 | };
265 |
266 | p._contentHeight = function () {
267 | if (this._isDefault()) {
268 | var doc = $document[0].documentElement,
269 | body = $document[0].body;
270 |
271 | return Math.max(
272 | body.scrollHeight, doc.scrollHeight,
273 | body.offsetHeight, doc.offsetHeight,
274 | doc.clientHeight
275 | );
276 | }
277 | return this.element[0].scrollHeight;
278 | };
279 |
280 | p._containerHeight = function () {
281 | if (this._isDefault()) {
282 | var h1 = $document[0].documentElement.clientHeight,
283 | h2 = $window.innerHeight;
284 | if (h1 > h2) {
285 | return h2;
286 | }
287 | return h1;
288 | }
289 | return this.element[0].offsetHeight;
290 | };
291 |
292 | p._scrollTop = function () {
293 | if (this._isDefault()) {
294 | return $window.pageYOffset;
295 | }
296 | return this.element[0].scrollTop;
297 | };
298 |
299 | p._digest = (function () {
300 | var reBpCond = /((?:>|<)?=?)\s*?((?:-(?!p))|(?:p(?!-)))?(\d+)/;
301 |
302 | var _handleStyle,
303 |
304 | _handleClass, _addClasses, _removeClasses,
305 | _digestClassCounts, _updateClasses,
306 |
307 | _handleBrdcst, _apply;
308 |
309 | /**
310 | * Style related functions
311 | */
312 | _handleStyle = function (locals, config) {
313 | config.target.css(config.styleGetter(config.scope, locals));
314 | };
315 |
316 | /**
317 | * Class related functions
318 | */
319 | _addClasses = function (config, classes) {
320 | var attr = config.attr;
321 | var newClasses = _digestClassCounts(config, classes, 1);
322 | attr.$addClass(newClasses);
323 | };
324 | _removeClasses = function (config, classes) {
325 | var attr = config.attr;
326 | var newClasses = _digestClassCounts(config, classes, -1);
327 | attr.$removeClass(newClasses);
328 | };
329 | _digestClassCounts = function (config, classes, count) {
330 | var element = config.target;
331 | var classCounts = element.data('$classCounts') || {};
332 | var classesToUpdate = [];
333 | angular.forEach(classes, function (className) {
334 | if (count > 0 || classCounts[className]) {
335 | classCounts[className] = (classCounts[className] || 0) + count;
336 | if (classCounts[className] === +(count > 0)) {
337 | classesToUpdate.push(className);
338 | }
339 | }
340 | });
341 | element.data('$classCounts', classCounts);
342 | return classesToUpdate.join(' ');
343 | };
344 | _updateClasses = function (config, oldClasses, newClasses) {
345 | var element = config.target;
346 | var toAdd = arrayDifference(newClasses, oldClasses);
347 | var toRemove = arrayDifference(oldClasses, newClasses);
348 | toRemove = _digestClassCounts(config, toRemove, -1);
349 | toAdd = _digestClassCounts(config, toAdd, 1);
350 |
351 | if (toAdd.length === 0) {
352 | $animate.removeClass(element, toRemove);
353 | } else if (toRemove.length === 0) {
354 | $animate.addClass(element, toAdd);
355 | } else {
356 | $animate.setClass(element, toAdd, toRemove);
357 | }
358 | config.scope.$digest();
359 | };
360 | _handleClass = function (locals, config) {
361 | var newVal = config.classGetter(config.scope, locals),
362 | oldVal = config._oldClassVal;
363 | var newClasses = arrayClasses(newVal || []);
364 | if (!oldVal) {
365 | _addClasses(config, newClasses);
366 | }
367 | else if (!angular.equals(newVal, oldVal)) {
368 | var oldClasses = arrayClasses(oldVal);
369 | _updateClasses(config, oldClasses, newClasses);
370 | }
371 | config._oldClassVal = shallowCopy(newVal);
372 | };
373 |
374 | /**
375 | * Broadcast condition -> event
376 | */
377 | _apply = function (scope, fn) {
378 | var phase = scope.$root.$$phase;
379 | if(phase == '$apply' || phase == '$digest') {
380 | if(fn && (typeof(fn) === 'function')) {
381 | fn();
382 | }
383 | } else {
384 | scope.$apply(fn);
385 | }
386 | };
387 | _handleBrdcst = function (locals, config) {
388 | angular.forEach(config.brdcstList, function (v) {
389 | var active, funcName;
390 |
391 | funcName = config.brdcstIsEmit ? '$emit' : '$broadcast';
392 |
393 | if (v.always) {
394 | config.brdcstScope[funcName](v.event, null, locals);
395 | }
396 | else if (v.condition) {
397 | active = v.condition(config.scope, locals);
398 | if (v.wasActive === null || active !== v.wasActive) {
399 | _apply(config.brdcstScope, function () {
400 | config.brdcstScope[funcName](v.event, active, locals);
401 | });
402 | }
403 | v.wasActive = active;
404 | }
405 | });
406 | };
407 |
408 | function _update(configId) {
409 | var positive, negative, numReverse, processConfig;
410 |
411 | var containerHeight = this._containerHeight(),
412 | contentHeight = this._contentHeight(),
413 | maxScrollTop = contentHeight - containerHeight,
414 | scrollTop = this._scrollTop();
415 |
416 | var self = this;
417 |
418 | positive = function (negative) {
419 | return maxScrollTop + negative;
420 | };
421 | negative = function (positive) {
422 | return positive - maxScrollTop;
423 | };
424 | numReverse = function (num) {
425 | return (num > 0) ? negative(num) : positive(num);
426 | };
427 |
428 | processConfig = function (config) {
429 | var from, to, locals, progress, elmMetrics;
430 |
431 | from = config.from < 0 ? positive(config.from) : config.from;
432 | to = config.to < 0 ? positive(config.to) : config.to;
433 |
434 | /**
435 | * Create local context
436 | */
437 | if (scrollTop < from) {
438 | progress = 0;
439 | locals = {
440 | $positive: from,
441 | $negative: negative(from)
442 | };
443 | }
444 | else if (scrollTop > to) {
445 | progress = 1;
446 | locals = {
447 | $positive: to,
448 | $negative: negative(to)
449 | };
450 | }
451 | else if (scrollTop >= from && scrollTop <= to) {
452 | progress = (scrollTop - from) / (to - from);
453 | locals = {
454 | $positive: scrollTop,
455 | $negative: negative(scrollTop)
456 | };
457 | }
458 |
459 | locals.$progress = progress;
460 | locals.$percentage = progress * 100;
461 |
462 | if (!config._lastProgress || config._lastProgress === progress) {
463 | locals.$direction = 0;
464 | }
465 | else if (config._lastProgress > progress) {
466 | locals.$direction = -1;
467 | }
468 | else if (config._lastProgress < progress) {
469 | locals.$direction = 1;
470 | }
471 |
472 | locals.$height = config.target[0].offsetHeight;
473 | angular.forEach(
474 | self._getElementMetrics(config.target),
475 | function (v, k) {
476 | locals['$' + k] = v;
477 | });
478 |
479 | /**
480 | * Applying
481 | */
482 | // to style
483 | if (config.styleGetter) {
484 | _handleStyle(locals, config);
485 | }
486 |
487 | // to class
488 | if (config.classGetter) {
489 | _handleClass(locals, config);
490 | }
491 |
492 | // trigger breakpoints
493 | if (config.brdcstList) {
494 | _handleBrdcst(locals, config);
495 | }
496 |
497 | config._lastProgress = progress;
498 | };
499 |
500 | if (angular.isUndefined(configId)) {
501 | angular.forEach(this.configs, processConfig);
502 | }
503 | else if (this.configs[configId]) {
504 | processConfig(this.configs[configId]);
505 | }
506 | }
507 |
508 | return function ($event, configId) {
509 | if (this.element === null) {
510 | return;
511 | }
512 |
513 | if (this._digesting && angular.isUndefined(configId)) {
514 | return;
515 | }
516 |
517 | var self = this;
518 |
519 | this._digesting = true;
520 |
521 | requestAnimFrame(function () {
522 | _update.call(self, configId);
523 |
524 | self._digesting = false;
525 | });
526 | };
527 | }());
528 |
529 | p._bind = function ($elm) {
530 | this._binded = true;
531 |
532 | if (this._isDefault()) {
533 | $win
534 | .on('scroll', this.scrollHandler)
535 | .on('resize', this.scrollHandler);
536 | }
537 | else {
538 | $win.on('resize', this.scrollHandler);
539 | $elm.on('scroll', this.scrollHandler);
540 | }
541 | };
542 |
543 | p._unbind = function ($elm) {
544 | this._binded = false;
545 |
546 | if (this._isDefault()) {
547 | $win
548 | .off('scroll', this.scrollHandler)
549 | .off('resize', this.scrollHandler);
550 | }
551 | else {
552 | $win.off('resize', this.scrollHandler);
553 | $elm.off('scroll', this.scrollHandler);
554 | }
555 | };
556 |
557 | return function scrollWatchStageFactory(name, $elm) {
558 | return new Stage(name, $elm);
559 | };
560 | })
561 |
562 | .service('scrollWatchService',
563 | function scrollWatchService(
564 | scrollWatchStageFactory, $window, $log, $cacheFactory
565 | ) {
566 | var defaultStage = scrollWatchStageFactory(
567 | STAGE_NAME_DEFAULT,
568 | angular.element($window)
569 | );
570 |
571 | this.stages = $cacheFactory(CACHE_ID_STAGE_POOL);
572 |
573 | this.stages.put(STAGE_NAME_DEFAULT, defaultStage);
574 |
575 | this.addStage = function (stageName, $elm) {
576 | var stage = this.stages.get(stageName);
577 |
578 | if (stage) {
579 | stage.setElement($elm);
580 | return;
581 | }
582 |
583 | stage = scrollWatchStageFactory(stageName, $elm);
584 | this.stages.put(stageName, stage);
585 | };
586 |
587 | this.removeStage = function (stageName) {
588 | var stage = this.stages.get(stageName);
589 |
590 | if (stage) {
591 | stage.clearElement();
592 | this._checkStageDestroy(stage);
593 | }
594 | };
595 |
596 | this.addConfig = function (config) {
597 | var stageName = config.stage,
598 | stage = this.stages.get(stageName);
599 |
600 | if (!stage) {
601 | // Create a stage without element
602 | stage = scrollWatchStageFactory(stageName);
603 | this.stages.put(stageName, stage);
604 | }
605 |
606 | return [stageName, stage.addConfig(config)];
607 | };
608 |
609 | this.removeConfig = function (handle) {
610 | var configId = handle[1],
611 | stage = this._getStage(handle);
612 |
613 | if (stage) {
614 | stage.removeConfig(configId);
615 | this._checkStageDestroy(stage);
616 | }
617 | };
618 |
619 | this.digest = function (handle) {
620 | var configId = handle[1],
621 | stage = this._getStage(handle);
622 |
623 | if (stage) {
624 | stage.digest(configId);
625 | }
626 | };
627 |
628 | this._checkStageDestroy = function (stage) {
629 | if (stage.couldDestroy()) {
630 | stage.destroy();
631 | this.stages.remove(stage.name);
632 | }
633 | };
634 |
635 | this._getStage = function (handle) {
636 | var stageName = handle[0];
637 | return this.stages.get(stageName);
638 | };
639 | })
640 |
641 | .directive('scrollWatch', function (scrollWatchService, $parse) {
642 | return {
643 | restrict: 'A',
644 | link: function postLink(scope, iElm, iAttrs) {
645 | var configHandle, deregisterDigestSync;
646 |
647 | if (iAttrs[DIR_STYLE] || iAttrs[DIR_CLASS] || iAttrs[DIR_BROADCAST]) {
648 | scope.$watch(iAttrs.scrollWatch, scrollWatchChange, true);
649 |
650 | iElm.on('$destroy', function () {
651 | if (configHandle) {
652 | scrollWatchService.removeConfig(configHandle);
653 | }
654 | });
655 | }
656 |
657 | function scrollWatchChange(config) {
658 | if (config && angular.isObject(config)) {
659 | // Make sure it won't modify the scope variable
660 | config = angular.copy(config);
661 |
662 | if (configHandle) {
663 | scrollWatchService.removeConfig(configHandle);
664 | (deregisterDigestSync || angular.noop)();
665 | }
666 |
667 | config.target = iElm;
668 | config.scope = scope;
669 | config.stage = config.stage || STAGE_NAME_DEFAULT;
670 |
671 | if (iAttrs[DIR_STYLE]) {
672 | config.styleExpr = iAttrs[DIR_STYLE];
673 | }
674 |
675 | if (iAttrs[DIR_CLASS]) {
676 | config.classExpr = iAttrs[DIR_CLASS];
677 | config.attr = iAttrs;
678 | }
679 |
680 | if (iAttrs[DIR_BROADCAST]) {
681 | config.brdcstExpr = iAttrs[DIR_BROADCAST];
682 | }
683 |
684 | if (config.digestSync) {
685 | deregisterDigestSync = scope.$watch(digestSync);
686 | }
687 |
688 | configHandle = scrollWatchService.addConfig(config);
689 | }
690 | }
691 |
692 | function digestSync () {
693 | if (configHandle) {
694 | scrollWatchService.digest(configHandle);
695 | }
696 | }
697 | }
698 | };
699 | })
700 |
701 | .directive('swStage', function (scrollWatchService) {
702 | return {
703 | restrict: 'A',
704 | link: function postLink(scope, iElm, iAttrs) {
705 | var stageName;
706 |
707 | iAttrs.$observe(DIR_STAGE, function (val) {
708 | if (val) {
709 | if (stageName) {
710 | scrollWatchService.removeStage(stageName);
711 | }
712 |
713 | stageName = val;
714 | scrollWatchService.addStage(stageName, iElm);
715 | }
716 | });
717 |
718 | iElm.on('$destroy', function () {
719 | if (stageName) {
720 | scrollWatchService.removeStage(stageName);
721 | }
722 | });
723 | }
724 | };
725 | });
726 |
727 | function objectSize(obj) {
728 | var c = 0;
729 | angular.forEach(obj, function () {
730 | c++;
731 | });
732 | return c;
733 | }
734 |
735 | function arrayDifference(tokens1, tokens2) {
736 | var values = [];
737 |
738 | outer:
739 | for(var i = 0; i < tokens1.length; i++) {
740 | var token = tokens1[i];
741 | for(var j = 0; j < tokens2.length; j++) {
742 | if(token == tokens2[j]) continue outer;
743 | }
744 | values.push(token);
745 | }
746 | return values;
747 | }
748 |
749 | function arrayClasses (classVal) {
750 | if (angular.isArray(classVal)) {
751 | return classVal;
752 | } else if (angular.isString(classVal)) {
753 | return classVal.split(' ');
754 | } else if (angular.isObject(classVal)) {
755 | var classes = [], i = 0;
756 | angular.forEach(classVal, function(v, k) {
757 | if (v) {
758 | classes = classes.concat(k.split(' '));
759 | }
760 | });
761 | return classes;
762 | }
763 | return classVal;
764 | }
765 |
766 | function shallowCopy(src, dst) {
767 | if (angular.isArray(src)) {
768 | dst = dst || [];
769 |
770 | for ( var i = 0; i < src.length; i++) {
771 | dst[i] = src[i];
772 | }
773 | } else if (angular.isObject(src)) {
774 | dst = dst || {};
775 |
776 | for (var key in src) {
777 | if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
778 | dst[key] = src[key];
779 | }
780 | }
781 | }
782 |
783 | return dst || src;
784 | }
785 |
786 | return MODULE_NAME;
787 | }));
788 |
--------------------------------------------------------------------------------