├── .gitignore
├── .editorconfig
├── demo
├── app.css
├── app.js
└── index.html
├── .eslintrc.js
├── dist
├── ng-resize.min.js
└── ng-resize.js
├── LICENSE
├── package.json
├── gulpfile.js
├── README.md
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | logs/
2 | node_modules/
3 | tmp/
4 | pages/
5 | build/
6 | .DS_Store
7 | .idea
8 | .log
9 | .vscode
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{package.json,package-lock.json}]
12 | indent_size = 2
13 |
14 | [*.yml]
15 | indent_size = 2
16 |
--------------------------------------------------------------------------------
/demo/app.css:
--------------------------------------------------------------------------------
1 | html, body{
2 | height: 100%;
3 | }
4 |
5 | .size-item{
6 | text-align: center;
7 | background-color: #c09;
8 | width: 100%;
9 | display: block;
10 | color: white;
11 | text-transform: capitalize;
12 | padding: 30% 0;
13 | }
14 |
15 | [resize-test]{
16 | height: 100%;
17 | }
18 |
19 | [resize-test] .row{
20 | height: 100%;
21 | }
22 |
--------------------------------------------------------------------------------
/demo/app.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('app', ['ngResize']);
2 |
3 | app.directive('resizeTest', ['resize', function(resize) {
4 | return {
5 | restrict: 'A',
6 | controller: function($scope) {
7 |
8 | $scope.$on('resize', function($event, data) {
9 | $scope.size = data;
10 | });
11 |
12 | },
13 | link: function($scope, $elem, $attr) {
14 |
15 | }
16 | };
17 | }]);
18 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "node": true
4 | },
5 | "extends": "eslint:recommended",
6 | "rules": {
7 | "indent": [
8 | "error",
9 | 4
10 | ],
11 | "linebreak-style": [
12 | "error",
13 | "unix"
14 | ],
15 | "quotes": [
16 | "error",
17 | "single"
18 | ],
19 | "semi": [
20 | "error",
21 | "always"
22 | ],
23 | "no-console": [
24 | "warn"
25 | ],
26 | "no-undef": [
27 | "warn"
28 | ],
29 | "no-unused-vars": [
30 | "warn"
31 | ]
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/dist/ng-resize.min.js:
--------------------------------------------------------------------------------
1 | !function(t,i){var n=i.module("ngResize",[]);n.provider("resize",function(){this.throttle=32,this.initBind=1,this.$get=["$rootScope","$window","$interval",function(t,n,e){function r(t){h.throttle=t}function o(){return h.throttle}function u(i){i=i||t,i.$broadcast("resize",{width:n.innerWidth,height:n.innerHeight})}function c(){f||(g.on("resize",function(){a||(d=e(function(){a&&(a=0,e.cancel(d),h.trigger())},h.throttle)),a=1}),f=1,g.triggerHandler("resize"))}function s(){f&&(g.off("resize"),f=0)}var h=this,f=0,d=0,a=0,g=i.element(n);this.getThrottle=o,this.setThrottle=r,this.trigger=u,this.bind=c,this.unbind=s,h.initBind&&h.bind()}]}),n.directive("ngResize",["$parse","$timeout","resize",function(t,i,n){return{compile:function(n,e){var r=t(e.ngResize);return function(t,n,e){t.$on("resize",function(n,e){i(function(){t.$apply(function(){r(t,{$event:n,data:e})})})})}}}}])}(window,window.angular);
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | window width:
{{size.width}}
15 |
16 |
17 | window height:
{{size.height}}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 danmasta
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-resize",
3 | "version": "2.0.0",
4 | "author": "Daniel Smith ",
5 | "description": "Manage resize events in Angular applications",
6 | "license": "MIT",
7 | "keywords": [
8 | "lightweight",
9 | "ui",
10 | "resize",
11 | "angular",
12 | "javascript"
13 | ],
14 | "main": "index.js",
15 | "scripts": {
16 | "test": "echo Error: no test specified"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "https://github.com/danmasta/ng-resize.git"
21 | },
22 | "dependencies": {},
23 | "devDependencies": {
24 | "eslint-config-standard": "^11.0.0",
25 | "eslint-plugin-import": "^2.11.0",
26 | "eslint-plugin-node": "^6.0.1",
27 | "eslint-plugin-promise": "^3.7.0",
28 | "eslint-plugin-standard": "^3.1.0",
29 | "express": "^4.15.2",
30 | "gulp": "^3.9.1",
31 | "gulp-concat": "^2.6.1",
32 | "gulp-gh-pages": "^0.5.4",
33 | "gulp-livereload": "^3.8.1",
34 | "gulp-ng-annotate": "^2.0.0",
35 | "gulp-uglify": "^2.1.2"
36 | },
37 | "engines": {
38 | "node": ">=0.10",
39 | "npm": ">=2"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var gulp = require('gulp');
3 | var express = require('express');
4 | var livereload = require('gulp-livereload');
5 | var concat = require('gulp-concat');
6 | var deploy = require('gulp-gh-pages');
7 | var uglify = require('gulp-uglify');
8 | var annotate = require('gulp-ng-annotate');
9 |
10 | gulp.task('js', function(){
11 | return gulp.src('./index.js')
12 | .pipe(annotate())
13 | .pipe(concat('ng-resize.js'))
14 | .pipe(gulp.dest('dist'));
15 | });
16 |
17 | gulp.task('js:min', function(){
18 | return gulp.src('./index.js')
19 | .pipe(annotate())
20 | .pipe(uglify())
21 | .pipe(concat('ng-resize.min.js'))
22 | .pipe(gulp.dest('dist'));
23 | });
24 |
25 | gulp.task('build', ['js', 'js:min']);
26 |
27 | gulp.task('deploy', ['build'], function(){
28 | return gulp.src(['dist/**/*', 'demo/**/*']).pipe(deploy({ cacheDir:'pages' }));
29 | });
30 |
31 | gulp.task('server', ['build'], function(done){
32 |
33 | var app = express();
34 |
35 | app.use(express.static('demo'));
36 | app.use(express.static('dist'));
37 |
38 | console.log('[development] server listening on: 8080');
39 |
40 | app.listen(8080, done);
41 |
42 | });
43 |
44 | gulp.task('watch', ['server'], function(){
45 |
46 | livereload.listen();
47 |
48 | gulp.watch('./index.js', ['js', 'js:min']);
49 |
50 | gulp.watch(['demo/**/*', 'dist/**/*'], function(file){
51 | livereload.changed(file.path);
52 | });
53 |
54 | });
55 |
56 | gulp.task('default', ['watch']);
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ngResize
2 |
3 | Angular module for managing resize events in your applications. Some of goals of this project worth noting include:
4 |
5 | * Lightweight, flexible and easy to use
6 | * Bind resize event handler one time for entire app
7 | * Throttle window resize events
8 |
9 | ## Usage
10 | ngResize is composed of a `provider`, a `service`, and a `directive`. The service can be injected into other modules and used to programatically bind `resize` events in angular applications. The `provider` can be injected into your app's configuration phase to set things like throttle time.
11 |
12 | Set `ngResize` as a dependency in your module:
13 |
14 | ```javascript
15 | var app = angular.module('YourApp', ['ngResize']);
16 | ```
17 |
18 | ### Provider
19 | ```javascript
20 | app.config(function(resizeProvider) {
21 |
22 | // set throttle time
23 | resizeProvider.throttle = 100;
24 |
25 | // don't bind resize events on service initialization
26 | resizeProvider.initBind = false;
27 |
28 | });
29 | ```
30 |
31 | #### Properties
32 | name | description
33 | ---- | ----
34 | `throttle` | Throttle time for resize events, default is `32` (30 fps)
35 | `initBind` | Boolean to determine if we should bind resize event when service object is created, default is `true`
36 |
37 | ### Service
38 | ```javascript
39 | app.directive('someDirective', function(resize) {
40 | return {
41 | controller: function($scope) {
42 |
43 | },
44 | link: function($scope, $elem, $attr, ctrl) {
45 |
46 | // on resize event, set dimensions
47 | // $event, and data arguments are available
48 | $scope.$on('resize', function($event, data) {
49 | $scope.width = data.width;
50 | $scope.height = data.height;
51 | });
52 |
53 | }
54 | };
55 | });
56 | ```
57 | *The event listener callback accepts two arguments: `$event`, and `data`*
58 |
59 | #### Methods
60 | name | description
61 | ---- | ----
62 | `getThrottle()` | Returns current throttle time
63 | `setThrottle(integer)` | Sets current throttle time, applies to entire app
64 | `trigger([$scope])` | `$broadcast` a `resize` event from specified `$scope` or `$rootScope`
65 | `bind()` | Bind resize event to `$window`, only useful if `initBind = false` or if event has been previously unbound
66 | `unbind()` | Unbinds `resize` even from `$window`
67 |
68 | ### Directive
69 | Something worth noting is that when the `resize` event is triggered, `$timeout` is used to debounce the expression to the end of the current `$digest`. This is to try and ensure that any costly calculations you might be doing won't interfere with the current `$digest` cycle. This approach was taken because resize events are often not critical functionality points, but necessary to maintain ui/ux stability. The goal is to provide efficient, useful access to `resize` events without crippling the ui.
70 |
71 | ```html
72 |
73 | ```
74 | *Two arguments are available to directive expressions: `$event`, and `data`*
75 |
76 | ## Roadmap
77 | A few things I'm interested in pursuing with this project in the future are:
78 |
79 | * option to disable `$rootScope` `$broadcast`
80 | * ability to subscribe and unsubscribe `$scopes` from resize `$broadcast`
81 | * ability to bind `resize` events to `$elements`
82 | * manage detaching of `$scopes` and `$elements` when `$destroyed`
83 | * set unique throttle time for each `$scope` or `$element`
84 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | (function(window, angular) {
2 |
3 | var ngResize = angular.module('ngResize', []);
4 |
5 | ngResize.provider('resize', function resizeProvider() {
6 |
7 | // default throttle time 30fps
8 | this.throttle = 32;
9 |
10 | // bind to window resize event when service created
11 | this.initBind = 1;
12 |
13 | // service object
14 | this.$get = function($rootScope, $window, $interval) {
15 |
16 | var resize = this;
17 | var bound = 0;
18 | var timer = 0;
19 | var resized = 0;
20 | var $w = angular.element($window);
21 |
22 | // api to set throttle amount
23 | function setThrottle(time) {
24 | resize.throttle = time;
25 | }
26 |
27 | // api to get current throttle amount
28 | function getThrottle() {
29 | return resize.throttle;
30 | }
31 |
32 | // trigger a resize event on provided $scope or $rootScope
33 | function trigger($scope) {
34 |
35 | $scope = $scope || $rootScope;
36 |
37 | $scope.$broadcast('resize', {
38 | width: $window.innerWidth,
39 | height: $window.innerHeight
40 | });
41 |
42 | }
43 |
44 | // bind to window resize event, will only ever be bound
45 | // one time for entire app
46 | function bind() {
47 |
48 | if (!bound) {
49 |
50 | $w.on('resize', function() {
51 |
52 | if (!resized) {
53 | timer = $interval(function() {
54 | if (resized) {
55 | resized = 0;
56 | $interval.cancel(timer);
57 | resize.trigger();
58 | }
59 | }, resize.throttle);
60 | }
61 |
62 | resized = 1;
63 |
64 | });
65 |
66 | bound = 1;
67 |
68 | $w.triggerHandler('resize');
69 |
70 | }
71 |
72 | }
73 |
74 | // unbind window resize event
75 | function unbind() {
76 |
77 | if (bound) {
78 | $w.off('resize');
79 | bound = 0;
80 | }
81 |
82 | }
83 |
84 | this.getThrottle = getThrottle;
85 | this.setThrottle = setThrottle;
86 | this.trigger = trigger;
87 | this.bind = bind;
88 | this.unbind = unbind;
89 |
90 | // bind window resize event when service created
91 | if (resize.initBind) {
92 | resize.bind();
93 | }
94 |
95 | };
96 |
97 | });
98 |
99 | ngResize.directive('ngResize', function($parse, $timeout, resize) {
100 |
101 | return {
102 |
103 | compile: function compile(elem, attr) {
104 |
105 | var fn = $parse(attr['ngResize']);
106 |
107 | return function resizeDirective($scope, $elem, $attr) {
108 | $scope.$on('resize', function($event, data) {
109 | $timeout(function() {
110 | $scope.$apply(function() {
111 | fn($scope, { $event: $event, data: data });
112 | });
113 | });
114 | });
115 | };
116 |
117 | }
118 |
119 | };
120 |
121 | });
122 |
123 | })(window, window.angular);
124 |
--------------------------------------------------------------------------------
/dist/ng-resize.js:
--------------------------------------------------------------------------------
1 | (function(window, angular) {
2 |
3 | var ngResize = angular.module('ngResize', []);
4 |
5 | ngResize.provider('resize', function resizeProvider() {
6 |
7 | // default throttle time 30fps
8 | this.throttle = 32;
9 |
10 | // bind to window resize event when service created
11 | this.initBind = 1;
12 |
13 | // service object
14 | this.$get = ["$rootScope", "$window", "$interval", function($rootScope, $window, $interval) {
15 |
16 | var resize = this;
17 | var bound = 0;
18 | var timer = 0;
19 | var resized = 0;
20 | var $w = angular.element($window);
21 |
22 | // api to set throttle amount
23 | function setThrottle(time) {
24 | resize.throttle = time;
25 | }
26 |
27 | // api to get current throttle amount
28 | function getThrottle() {
29 | return resize.throttle;
30 | }
31 |
32 | // trigger a resize event on provided $scope or $rootScope
33 | function trigger($scope) {
34 |
35 | $scope = $scope || $rootScope;
36 |
37 | $scope.$broadcast('resize', {
38 | width: $window.innerWidth,
39 | height: $window.innerHeight
40 | });
41 |
42 | }
43 |
44 | // bind to window resize event, will only ever be bound
45 | // one time for entire app
46 | function bind() {
47 |
48 | if (!bound) {
49 |
50 | $w.on('resize', function() {
51 |
52 | if (!resized) {
53 | timer = $interval(function() {
54 | if (resized) {
55 | resized = 0;
56 | $interval.cancel(timer);
57 | resize.trigger();
58 | }
59 | }, resize.throttle);
60 | }
61 |
62 | resized = 1;
63 |
64 | });
65 |
66 | bound = 1;
67 |
68 | $w.triggerHandler('resize');
69 |
70 | }
71 |
72 | }
73 |
74 | // unbind window resize event
75 | function unbind() {
76 |
77 | if (bound) {
78 | $w.off('resize');
79 | bound = 0;
80 | }
81 |
82 | }
83 |
84 | this.getThrottle = getThrottle;
85 | this.setThrottle = setThrottle;
86 | this.trigger = trigger;
87 | this.bind = bind;
88 | this.unbind = unbind;
89 |
90 | // bind window resize event when service created
91 | if (resize.initBind) {
92 | resize.bind();
93 | }
94 |
95 | }];
96 |
97 | });
98 |
99 | ngResize.directive('ngResize', ["$parse", "$timeout", "resize", function($parse, $timeout, resize) {
100 |
101 | return {
102 |
103 | compile: function compile(elem, attr) {
104 |
105 | var fn = $parse(attr['ngResize']);
106 |
107 | return function resizeDirective($scope, $elem, $attr) {
108 | $scope.$on('resize', function($event, data) {
109 | $timeout(function() {
110 | $scope.$apply(function() {
111 | fn($scope, { $event: $event, data: data });
112 | });
113 | });
114 | });
115 | };
116 |
117 | }
118 |
119 | };
120 |
121 | }]);
122 |
123 | })(window, window.angular);
124 |
--------------------------------------------------------------------------------