├── .bowerrc
├── liteServerConfig.js
├── docs
└── img
│ └── demo.png
├── .gitignore
├── demo
├── demo.css
├── demo.js
└── index.html
├── bower.json
├── webpack.config.dev.js
├── webpack.config.prod.js
├── LICENSE
├── package.json
├── dist
├── angular-number-picker.min.js
└── angular-number-picker.js
├── README.md
├── src
└── angular-number-picker.js
└── .eslintrc
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "demo/bower"
3 | }
--------------------------------------------------------------------------------
/liteServerConfig.js:
--------------------------------------------------------------------------------
1 | module.exports = {port: 8000, server: {baseDir: './demo'}};
2 |
--------------------------------------------------------------------------------
/docs/img/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leftstick/angular-number-picker/HEAD/docs/img/demo.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #npm
2 | node_modules/
3 |
4 |
5 | #demo
6 | demo/angular-number-picker.js
7 | demo/angular-number-picker.js.map
8 | demo/bower/
9 |
10 | #osx
11 | .DS_Store
--------------------------------------------------------------------------------
/demo/demo.css:
--------------------------------------------------------------------------------
1 | .input-group{
2 | width: 210px;
3 | margin-left: auto;
4 | margin-right: auto;
5 | }
6 |
7 | span[disabled]
8 | {
9 | pointer-events: none;
10 | cursor: default;
11 | background-color: #eee;
12 | opacity: 1;
13 | }
14 |
15 | .input-group-addon.active{
16 | color: #fff;
17 | background-color: #007aff;
18 | }
19 |
20 | .picker-unit-left{
21 | margin-right: 10px;
22 | }
23 |
24 | .picker-unit-right{
25 | margin-left: 10px;
26 | }
27 |
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 |
2 | var demo = angular.module('demo', [window.ngNumberPicker]);
3 |
4 | demo.controller('DemoController', [
5 | '$scope',
6 | function($scope) {
7 |
8 | $scope.input = {num: 2};
9 |
10 | $scope.getNumber = function() {
11 | alert('The number is: [' + $scope.input.num + ']');
12 | };
13 |
14 | $scope.onChange = function() {
15 | console.log('number changed', $scope.input.num);
16 | };
17 |
18 | }
19 | ]);
20 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-number-picker",
3 | "version": "2.2.0",
4 | "homepage": "https://github.com/leftstick/angular-number-picker",
5 | "description": "A directive used for picking number by using up/down button, instead of typing",
6 | "keywords": [
7 | "angular",
8 | "number",
9 | "picker"
10 | ],
11 | "files": [
12 | "dist/angular-number-picker.js",
13 | "dist/angular-number-picker.min.js",
14 | "src/angular-number-picker.js"
15 | ],
16 | "authors": [
17 | "Howard.Zuo"
18 | ],
19 | "license": "MIT",
20 | "devDependencies": {
21 | "angular": "~1.5.5",
22 | "bootstrap": "~3.3.6"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/webpack.config.dev.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | entry: {
5 | index: './src/angular-number-picker.js'
6 | },
7 | output: {
8 | path: path.resolve(__dirname, 'demo'),
9 | filename: 'angular-number-picker.js',
10 | libraryTarget: 'umd'
11 | },
12 | debug: true,
13 | devtool: 'source-map',
14 | module: {
15 | loaders: [
16 | {
17 | test: /\.js$/,
18 | loader: 'babel?{"presets":["es2015"]}',
19 | exclude: /(node_modules)/
20 | }
21 | ]
22 | },
23 | externals: {
24 | angular: 'angular'
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 | var UnminifiedWebpackPlugin = require('unminified-webpack-plugin');
4 |
5 | module.exports = {
6 | entry: {
7 | index: './src/angular-number-picker.js'
8 | },
9 | output: {
10 | path: path.resolve(__dirname, 'dist'),
11 | filename: 'angular-number-picker.min.js',
12 | libraryTarget: 'umd'
13 | },
14 | module: {
15 | loaders: [
16 | {
17 | test: /\.js$/,
18 | loader: 'babel?{"presets":["es2015"]}',
19 | exclude: /(node_modules)/
20 | }
21 | ]
22 | },
23 | externals: {
24 | angular: 'angular'
25 | },
26 | plugins: [
27 | new webpack.optimize.UglifyJsPlugin({
28 | compress: {
29 | warnings: false
30 | }
31 | }),
32 | new UnminifiedWebpackPlugin()
33 | ]
34 | };
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Howard.Zuo
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": "angular-number-picker",
3 | "version": "2.2.0",
4 | "main": "dist/angular-number-picker.js",
5 | "files": [
6 | "dist/angular-number-picker.js",
7 | "dist/angular-number-picker.min.js",
8 | "src/angular-number-picker.js"
9 | ],
10 | "scripts": {
11 | "watch": "webpack -w --config webpack.config.dev.js",
12 | "start": "concurrently \"npm run watch\" \"lite-server -c liteServerConfig.js\"",
13 | "dist": "rm -rf dist; webpack --config webpack.config.prod.js"
14 | },
15 | "description": "A directive used for picking number by using up/down button, instead of typing",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/leftstick/angular-number-picker.git"
19 | },
20 | "keywords": [
21 | "angular",
22 | "number",
23 | "picker"
24 | ],
25 | "author": "Howard.Zuo",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/leftstick/angular-number-picker/issues"
29 | },
30 | "homepage": "https://github.com/leftstick/angular-number-picker",
31 | "devDependencies": {
32 | "babel-core": "^6.8.0",
33 | "babel-loader": "^6.2.4",
34 | "babel-preset-es2015": "^6.6.0",
35 | "concurrently": "^2.0.0",
36 | "lite-server": "^2.2.0",
37 | "unminified-webpack-plugin": "^1.0.0",
38 | "webpack": "^1.13.0"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEMO
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Demo
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/dist/angular-number-picker.min.js:
--------------------------------------------------------------------------------
1 | !function(n,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("angular"));else if("function"==typeof define&&define.amd)define(["angular"],e);else{var t=e("object"==typeof exports?require("angular"):n.angular);for(var r in t)("object"==typeof exports?exports:n)[r]=t[r]}}(this,function(n){return function(n){function e(r){if(t[r])return t[r].exports;var i=t[r]={exports:{},id:r,loaded:!1};return n[r].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var t={};return e.m=n,e.c=t,e.p="",e(0)}([function(n,e,t){"use strict";function r(n){if(n&&n.__esModule)return n;var e={};if(null!=n)for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(e[t]=n[t]);return e.default=n,e}Object.defineProperty(e,"__esModule",{value:!0}),e.ngNumberPicker=void 0;var i=t(1),o=r(i),a=function(n){return null===n||void 0===n},u=function(){"function"!=typeof Object.assign&&(Object.assign=function(n){if(a(n))throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(n),t=1;t0?o.element(n.touches[0].target):o.element(n.target)},a=function(n){return i(n).attr("type")},c=function(n){for(var e in n){var r=n[e];n[e]=t(r)}},l=function(n,t){return{restrict:"E",transclude:!0,scope:{value:"=",singular:"@",plural:"@",unitPosition:"@",min:"@",max:"@",step:"@",change:"&"},link:function(o,u){var l=Object.assign({},e,{min:o.min,max:o.max,step:o.step});c(l),r(l.min),r(l.max),r(l.step),l.min>o.value&&(o.value=l.min),o.$watch("value",function(n,e){o.canDown=n>l.min,o.canUp=n=l.max)return;o.value+=l.step,o.value>l.max&&(o.value=l.max)}else if("down"===e){if(o.value<=l.min)return;o.value-=l.step,o.value-+'}};return o.module(n,[]).directive("hNumber",["$timeout","$interval",l]),n}()},function(e,t){e.exports=n}])});
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-number-picker #
2 | =====================
3 |
4 | ![][bower-url]
5 | [![NPM version][npm-image]][npm-url]
6 | ![][david-url]
7 | ![][dt-url]
8 | ![][license-url]
9 |
10 |
11 | A directive used for picking number by using -/+ button, instead of typing the number directly.
12 |
13 | This is an `angular` directive designed in `mobile-first` concept. Which means you would have better user experience while in mobile development.
14 |
15 | > While running on mobile device, you would increase/decrease the number continuously by long tap the -/+ button.
16 |
17 | 
18 |
19 | Try it: [plunker](http://plnkr.co/edit/b2p7Vb?p=preview)
20 |
21 |
22 | ## Requirement ##
23 |
24 | - [angularjs](http://angularjs.org/) (1.4.3+)
25 |
26 | ## UI dependency(optional) ##
27 |
28 | - [bootstrap](http://getbootstrap.com) (3.3.5+)
29 |
30 | ## Installation ##
31 |
32 | ### via bower ###
33 |
34 | ```JavaScript
35 | bower install angular-number-picker --save
36 | ```
37 |
38 | ### via npm ###
39 |
40 | ```JavaScript
41 | npm install angular-number-picker --save
42 | ```
43 |
44 | ### via script ###
45 |
46 | ```html
47 |
48 |
49 | ```
50 |
51 | ## Import ##
52 |
53 | ### via ES2015 ###
54 |
55 | ```javascript
56 | import {ngNumberPicker} from 'angular-number-picker';
57 | ```
58 |
59 | ### via CommonJS ###
60 |
61 | ```javascript
62 | var ngNumberPicker = require('angular-number-picker').ngNumberPicker;
63 | ```
64 |
65 | ### via script ###
66 |
67 | ```html
68 |
71 | ```
72 |
73 | ## Basic Usage ##
74 |
75 | **Add `ngNumberPicker` module as your angular app's dependency**
76 |
77 | ```javascript
78 | var demo = angular.module('demo', [ngNumberPicker]);
79 | ```
80 |
81 | >`ngNumberPicker` is the variable you get from above "Import" stage
82 |
83 | **Use `h-number` tag in your html**
84 |
85 | ```HTML
86 |
87 |
88 |
89 | ```
90 |
91 | **You can use transclusion, too**
92 |
93 | ```HTML
94 |
95 |
96 |
97 |
98 |
99 | ```
100 |
101 | **Writing `DemoController`**
102 |
103 | ```javascript
104 | demo.controller('DemoController', ['$scope', function($scope) {
105 | $scope.input = {
106 | num: 0
107 | };
108 |
109 | $scope.getNumber = function() {
110 | alert('The number is: [' + $scope.input.num + ']');
111 | };
112 |
113 | $scope.onChange = function(){
114 | console.log('The number is Changed ', $scope.input.num);
115 | };
116 | }]);
117 | ```
118 |
119 | ## `h-number` configuration ##
120 |
121 | | Attribute | Type | Required | Description |
122 | | :------------- |:-------------| :-----:| :-----|
123 | | value | [expression] | Yes | Expression to evaluate as the input number |
124 | | min | Number | No | The minimal point to limit the operation. 0 by default |
125 | | max | Number | No | The maximum point to limit the operation. 100 by default |
126 | | step | Number | No | The step value for the operation. 1 by default|
127 | | singular | String | No | Label to be included after value when value is 1|
128 | | plural | String | No | Label to be included after value when value is not 1|
129 | | unit-position | String | No | where to place the singular/plural. Available options: `left`, `right`. `right` by default. |
130 | | change | Function | No | Function to be called while number is changed|
131 |
132 | ## build-in class ##
133 |
134 | ### `input-group` ###
135 |
136 | The wrapper class for the `h-number` element
137 |
138 | ### `input-group-addon` ###
139 |
140 | The wrapper class for `+-` operator
141 |
142 | ### `form-control` ###
143 |
144 | The wrapper class for the number area at the center
145 |
146 | ### `active` ###
147 |
148 | The `active` class will be added to the `input-group-addon` button, while touching them. So it's possible to implement your own behavior.
149 |
150 | ### `picker-unit-left` ###
151 |
152 | The `picker-unit-left` class will be added to the left `unit` span
153 |
154 | ### `picker-unit-right` ###
155 |
156 | The `picker-unit-right` class will be added to the right `unit` span
157 |
158 |
159 | > It's easy to implement those classes to achieve your own UI
160 |
161 |
162 | ## run demo locally ##
163 |
164 | ### Install npm dependency ###
165 |
166 | ```bash
167 | npm install
168 | ```
169 |
170 | ### Install bower dependency ###
171 |
172 | ```bash
173 | bower install
174 | ```
175 |
176 | ### run demo ###
177 | ```Shell
178 | npm start
179 | ```
180 |
181 | >I will launch a debug server at [http://localhost:8000/](http://localhost:8000/)
182 |
183 |
184 | ## LICENSE ##
185 |
186 | [MIT License](https://raw.githubusercontent.com/leftstick/angular-number-picker/master/LICENSE)
187 |
188 |
189 | [expression]: https://docs.angularjs.org/guide/expression
190 | [bower-url]: https://img.shields.io/bower/v/angular-number-picker.svg
191 | [npm-url]: https://npmjs.org/package/angular-number-picker
192 | [npm-image]: https://badge.fury.io/js/angular-number-picker.png
193 | [david-url]: https://david-dm.org/leftstick/angular-number-picker.png
194 | [dt-url]:https://img.shields.io/npm/dt/angular-number-picker.svg
195 | [license-url]:https://img.shields.io/npm/l/angular-number-picker.svg
196 |
--------------------------------------------------------------------------------
/src/angular-number-picker.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Defines `hNumberPicker` directive which can only be used as element.
4 | *
5 | * It allows end-user to choose number, instead of typing
6 | *
7 | * usage:
8 | *
9 | *
10 | *
11 | * @author Howard.Zuo
12 | * @date May 16th, 2016
13 | *
14 | */
15 |
16 | import * as ng from 'angular';
17 |
18 | const isNull = obj => obj === null || obj === undefined;
19 |
20 | const polyfill = function() {
21 | if (typeof Object.assign !== 'function') {
22 | Object.assign = function(target) {
23 |
24 | // We must check against these specific cases.
25 | if (isNull(target)) {
26 | throw new TypeError('Cannot convert undefined or null to object');
27 | }
28 |
29 | var output = Object(target);
30 | for (var index = 1; index < arguments.length; index++) {
31 | var source = arguments[index];
32 | if (!isNull(source)) {
33 | for (var nextKey in source) {
34 | if (source.hasOwnProperty(nextKey)) {
35 | output[nextKey] = source[nextKey];
36 | }
37 | }
38 | }
39 | }
40 | return output;
41 | };
42 | }
43 | };
44 |
45 | export const ngNumberPicker = (function() {
46 |
47 | polyfill();
48 |
49 | let name = 'ngNumberPicker';
50 |
51 | var defaults = {
52 | min: 0,
53 | max: 100,
54 | step: 1,
55 | timeout: 600
56 | };
57 |
58 | var toNumber = function(value) {
59 | return Number(value);
60 | };
61 |
62 | var checkNumber = function(value) {
63 | if (!ng.isNumber(value)) {
64 | throw new Error('value [' + value + '] is not a valid number');
65 | }
66 | };
67 |
68 | var getTarget = function(e) {
69 | if (e.touches && e.touches.length > 0) {
70 | return ng.element(e.touches[0].target);
71 | }
72 | return ng.element(e.target);
73 | };
74 |
75 | var getType = function(e) {
76 | return getTarget(e).attr('type');
77 | };
78 |
79 | var transform = function(opts) {
80 | for (var key in opts) {
81 | var value = opts[key];
82 | opts[key] = toNumber(value);
83 | }
84 | };
85 |
86 | var directive = function($timeout, $interval) {
87 |
88 | return {
89 | restrict: 'E',
90 | transclude: true,
91 | scope: {
92 | value: '=',
93 | singular: '@',
94 | plural: '@',
95 | unitPosition: '@',
96 | min: '@',
97 | max: '@',
98 | step: '@',
99 | change: '&'
100 | },
101 | link: function($scope, element) {
102 |
103 | var opts = Object.assign({}, defaults, {
104 | min: $scope.min,
105 | max: $scope.max,
106 | step: $scope.step
107 | });
108 |
109 | transform(opts);
110 |
111 | checkNumber(opts.min);
112 | checkNumber(opts.max);
113 | checkNumber(opts.step);
114 |
115 |
116 | if (opts.min > $scope.value) {
117 | $scope.value = opts.min;
118 | }
119 |
120 | $scope.$watch('value', function(newValue, oldValue) {
121 | $scope.canDown = newValue > opts.min;
122 | $scope.canUp = newValue < opts.max;
123 | $scope.unit = newValue === 1 ? $scope.singular : $scope.plural;
124 |
125 | if (newValue !== oldValue) {
126 | $scope.change();
127 | }
128 | });
129 |
130 | var changeNumber = function($event) {
131 | var type = getType($event);
132 |
133 | //cast existing value to number, so += will really increment decimal number
134 | $scope.value = Number($scope.value);
135 |
136 | if (type === 'up') {
137 | if ($scope.value >= opts.max) {
138 | return;
139 | }
140 | $scope.value += opts.step;
141 | if ($scope.value > opts.max) {
142 | $scope.value = opts.max;
143 | }
144 | } else if (type === 'down') {
145 | if ($scope.value <= opts.min) {
146 | return;
147 | }
148 | $scope.value -= opts.step;
149 | if ($scope.value < opts.min) {
150 | $scope.value = opts.min;
151 | }
152 | }
153 | };
154 |
155 | var isPressing;
156 | var timeoutPro;
157 | var intervalPro;
158 | var start;
159 | var end;
160 | var addon = element.find('span');
161 |
162 | addon.on('click', function(e) {
163 | changeNumber(e);
164 | $scope.$apply();
165 | e.stopPropagation();
166 | });
167 |
168 | addon.on('touchstart', function(e) {
169 | if (isPressing) {
170 | return;
171 | }
172 | isPressing = true;
173 | getTarget(e).addClass('active');
174 | start = new Date().getTime();
175 | timeoutPro = $timeout(function() {
176 | intervalPro = $interval(function() {
177 | changeNumber(e);
178 | }, 200);
179 | }, opts.timeout);
180 | e.preventDefault();
181 | });
182 |
183 | addon.on('touchend', function(e) {
184 | end = new Date().getTime();
185 | if (intervalPro) {
186 | $interval.cancel(intervalPro);
187 | intervalPro = undefined;
188 | }
189 | if (timeoutPro) {
190 | $timeout.cancel(timeoutPro);
191 | timeoutPro = undefined;
192 | }
193 | if ((end - start) < opts.timeout) {
194 | changeNumber(e);
195 | $scope.$apply();
196 | }
197 | getTarget(e).removeClass('active');
198 | e.stopPropagation();
199 | isPressing = false;
200 | });
201 |
202 | $scope.$on('$destroy', function() {
203 | addon.off('touchstart touchend click');
204 | });
205 |
206 | },
207 | template: '-+
'
208 | };
209 | };
210 |
211 | ng.module(name, [])
212 | .directive('hNumber', ['$timeout', '$interval', directive]);
213 |
214 | return name;
215 | }());
216 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions":{
3 | "ecmaVersion": 6,
4 | "sourceType": "module",
5 | "ecmaFeatures": {
6 | "globalReturn": true,
7 | "impliedStrict": false,
8 | "jsx": false,
9 | "experimentalObjectRestSpread": true
10 | }
11 | },
12 | "env": {
13 | "shared-node-browser": true,
14 | "browser": true,
15 | "commonjs": true,
16 | "node": true,
17 | "es6": true,
18 | "mocha": true,
19 | "jquery": true
20 | },
21 | "rules": {
22 | "comma-dangle": [2, "never"],
23 | "no-cond-assign": [2, "except-parens"],
24 | "no-console": 0,
25 | "no-constant-condition": 1,
26 | "no-control-regex": 2,
27 | "no-debugger": 2,
28 | "no-dupe-args": 2,
29 | "no-dupe-keys": 2,
30 | "no-duplicate-case": 2,
31 | "no-empty-character-class": 1,
32 | "no-empty": 1,
33 | "no-ex-assign": 2,
34 | "no-extra-boolean-cast": 1,
35 | "no-extra-parens": [1, "functions"],
36 | "no-extra-semi": 2,
37 | "no-func-assign": 2,
38 | "no-inner-declarations": [1, "functions"],
39 | "no-invalid-regexp": 2,
40 | "no-irregular-whitespace": 1,
41 | "no-negated-in-lhs": 2,
42 | "no-obj-calls": 2,
43 | "no-regex-spaces": 1,
44 | "no-sparse-arrays": 2,
45 | "no-unexpected-multiline": 2,
46 | "no-unreachable": 2,
47 | "use-isnan": 2,
48 | "valid-jsdoc": 0,
49 | "valid-typeof": 2,
50 | "accessor-pairs": [1, { "getWithoutSet": true, "setWithoutGet": true }],
51 | "array-callback-return": 1,
52 | "block-scoped-var": 0,
53 | "complexity": [1, 7],
54 | "consistent-return": 0,
55 | "curly": 1,
56 | "default-case": 2,
57 | "dot-location": [1, "property"],
58 | "dot-notation": [1, { "allowKeywords": true}],
59 | "eqeqeq": 2,
60 | "guard-for-in": 0,
61 | "no-alert": 2,
62 | "no-caller": 2,
63 | "no-case-declarations": 2,
64 | "no-div-regex": 1,
65 | "no-else-return": 1,
66 | "no-empty-function": 0,
67 | "no-empty-pattern": 2,
68 | "no-eq-null": 2,
69 | "no-eval": 2,
70 | "no-extend-native": 1,
71 | "no-extra-bind": 1,
72 | "no-extra-label": 1,
73 | "no-fallthrough": 2,
74 | "no-floating-decimal": 2,
75 | "no-implicit-coercion": 0,
76 | "no-implicit-globals": 0,
77 | "no-implied-eval": 2,
78 | "no-invalid-this": 0,
79 | "no-iterator": 1,
80 | "no-labels": [2, {"allowLoop": false, "allowSwitch": false}],
81 | "no-lone-blocks": 2,
82 | "no-loop-func": 2,
83 | "no-magic-numbers": 0,
84 | "no-multi-spaces": 1,
85 | "no-multi-str": 2,
86 | "no-native-reassign": 2,
87 | "no-new-func": 2,
88 | "no-new-wrappers": 2,
89 | "no-new": 1,
90 | "no-octal-escape": 1,
91 | "no-octal": 1,
92 | "no-param-reassign": [2, {"props": false}],
93 | "no-process-env": 0,
94 | "no-proto": 2,
95 | "no-redeclare": [2, { "builtinGlobals": true }],
96 | "no-return-assign": [2, "except-parens"],
97 | "no-script-url": 2,
98 | "no-self-assign": 2,
99 | "no-self-compare": 2,
100 | "no-sequences": 2,
101 | "no-throw-literal": 2,
102 | "no-unmodified-loop-condition": 1,
103 | "no-unused-expressions": [2, { "allowShortCircuit": true, "allowTernary": false }],
104 | "no-unused-labels": 1,
105 | "no-useless-call": 1,
106 | "no-useless-concat": 1,
107 | "no-void": 2,
108 | "no-warning-comments": [1, { "terms": ["todo", "fix"], "location": "anywhere" }],
109 | "no-with": 2,
110 | "radix": [2, "as-needed"],
111 | "vars-on-top": 0,
112 | "wrap-iife": [2, "outside"],
113 | "yoda": [1, "never", { "onlyEquality": true }],
114 | "strict": [1, "safe"],
115 | "init-declarations": 0,
116 | "no-catch-shadow": 2,
117 | "no-delete-var": 2,
118 | "no-label-var": 2,
119 | "no-shadow-restricted-names": 2,
120 | "no-shadow": [2, {"builtinGlobals": false, "hoist": "functions"}],
121 | "no-undef-init": 1,
122 | "no-undef": [2, { "typeof": false }],
123 | "no-undefined": 1,
124 | "no-unused-vars": [1, { "vars": "all", "args": "none" }],
125 | "no-use-before-define": [1, {"functions": true, "classes": true}],
126 | "array-bracket-spacing": [1, "never"],
127 | "block-spacing": [1, "always"],
128 | "brace-style": [1, "1tbs", { "allowSingleLine": true }],
129 | "camelcase": [1, {"properties": "never"}],
130 | "comma-spacing": [2, {"before": false, "after": true}],
131 | "comma-style": [1, "last"],
132 | "computed-property-spacing": [1, "never"],
133 | "consistent-this": [1, "_this", "self", "ctx"],
134 | "eol-last": [1, "unix"],
135 | "func-names": 0,
136 | "func-style": [1, "expression", { "allowArrowFunctions": true }],
137 | "id-length": [2, {"min": 1, "max": 35, "properties": "never"}],
138 | "id-match": 0,
139 | "id-blacklist": 0,
140 | "indent": [1, 4, {"VariableDeclarator": 1, "SwitchCase": 1}],
141 | "jsx-quotes": 0,
142 | "key-spacing": [1, {"beforeColon": false, "afterColon": true}],
143 | "keyword-spacing": [1, {"before": true, "after": true}],
144 | "linebreak-style": [1, "unix"],
145 | "lines-around-comment": [1, { "beforeBlockComment": true, "afterBlockComment": false, "beforeLineComment": true, "afterLineComment": false, "allowBlockStart": true, "allowBlockEnd": true, "allowObjectStart": true, "allowArrayStart": false, "allowArrayEnd": false }],
146 | "max-depth": [1, 5],
147 | "max-len": [1, {"code": 120, "comments": 120, "tabWidth": 4, "ignoreUrls": true}],
148 | "max-nested-callbacks": [1, 5],
149 | "max-params": [1, 10],
150 | "max-statements": [1, 12, {"ignoreTopLevelFunctions": true}],
151 | "new-cap": [1, {"newIsCap": true, "capIsNew": true, "properties": false}],
152 | "new-parens": 1,
153 | "newline-after-var": 0,
154 | "newline-per-chained-call": 0,
155 | "no-array-constructor": 1,
156 | "no-bitwise": 0,
157 | "no-continue": 0,
158 | "no-inline-comments": 0,
159 | "no-lonely-if": 1,
160 | "no-mixed-spaces-and-tabs": 1,
161 | "no-multiple-empty-lines": [1, {"max": 2}],
162 | "no-negated-condition": 0,
163 | "no-nested-ternary": 1,
164 | "no-new-object": 1,
165 | "no-plusplus": 0,
166 | "no-restricted-syntax": [1, "WithStatement"],
167 | "no-whitespace-before-property": 1,
168 | "no-spaced-func": 1,
169 | "no-ternary": 0,
170 | "no-trailing-spaces": [1, { "skipBlankLines": true }],
171 | "no-underscore-dangle": 0,
172 | "no-unneeded-ternary": 1,
173 | "object-curly-spacing": [1, "never"],
174 | "one-var": 0,
175 | "one-var-declaration-per-line": 0,
176 | "operator-assignment": 0,
177 | "operator-linebreak": 0,
178 | "padded-blocks": 0,
179 | "quote-props": [1, "as-needed"],
180 | "quotes": [1, "single"],
181 | "require-jsdoc": 0,
182 | "semi-spacing": [2, { "before": false, "after": true }],
183 | "semi": [1, "always"],
184 | "sort-vars": 0,
185 | "sort-imports": 0,
186 | "space-before-blocks": [1, { "functions": "always", "keywords": "always", "classes": "always" }],
187 | "space-before-function-paren": [1, {"anonymous": "never", "named": "never"}],
188 | "space-in-parens": [1, "never"],
189 | "space-infix-ops": 1,
190 | "space-unary-ops": [1, { "words": true, "nonwords": false }],
191 | "spaced-comment": 0,
192 | "wrap-regex": 0
193 | },
194 | "globals": {
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/dist/angular-number-picker.js:
--------------------------------------------------------------------------------
1 | (function webpackUniversalModuleDefinition(root, factory) {
2 | if(typeof exports === 'object' && typeof module === 'object')
3 | module.exports = factory(require("angular"));
4 | else if(typeof define === 'function' && define.amd)
5 | define(["angular"], factory);
6 | else {
7 | var a = typeof exports === 'object' ? factory(require("angular")) : factory(root["angular"]);
8 | for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
9 | }
10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
11 | return /******/ (function(modules) { // webpackBootstrap
12 | /******/ // The module cache
13 | /******/ var installedModules = {};
14 | /******/
15 | /******/ // The require function
16 | /******/ function __webpack_require__(moduleId) {
17 | /******/
18 | /******/ // Check if module is in cache
19 | /******/ if(installedModules[moduleId])
20 | /******/ return installedModules[moduleId].exports;
21 | /******/
22 | /******/ // Create a new module (and put it into the cache)
23 | /******/ var module = installedModules[moduleId] = {
24 | /******/ exports: {},
25 | /******/ id: moduleId,
26 | /******/ loaded: false
27 | /******/ };
28 | /******/
29 | /******/ // Execute the module function
30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
31 | /******/
32 | /******/ // Flag the module as loaded
33 | /******/ module.loaded = true;
34 | /******/
35 | /******/ // Return the exports of the module
36 | /******/ return module.exports;
37 | /******/ }
38 | /******/
39 | /******/
40 | /******/ // expose the modules object (__webpack_modules__)
41 | /******/ __webpack_require__.m = modules;
42 | /******/
43 | /******/ // expose the module cache
44 | /******/ __webpack_require__.c = installedModules;
45 | /******/
46 | /******/ // __webpack_public_path__
47 | /******/ __webpack_require__.p = "";
48 | /******/
49 | /******/ // Load entry module and return exports
50 | /******/ return __webpack_require__(0);
51 | /******/ })
52 | /************************************************************************/
53 | /******/ ([
54 | /* 0 */
55 | /***/ function(module, exports, __webpack_require__) {
56 |
57 | 'use strict';
58 |
59 | Object.defineProperty(exports, "__esModule", {
60 | value: true
61 | });
62 | exports.ngNumberPicker = undefined;
63 |
64 | var _angular = __webpack_require__(1);
65 |
66 | var ng = _interopRequireWildcard(_angular);
67 |
68 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
69 |
70 | var isNull = function isNull(obj) {
71 | return obj === null || obj === undefined;
72 | }; /**
73 | *
74 | * Defines `hNumberPicker` directive which can only be used as element.
75 | *
76 | * It allows end-user to choose number, instead of typing
77 | *
78 | * usage:
79 | *
80 | *
81 | *
82 | * @author Howard.Zuo
83 | * @date May 16th, 2016
84 | *
85 | */
86 |
87 | var polyfill = function polyfill() {
88 | if (typeof Object.assign !== 'function') {
89 | Object.assign = function (target) {
90 |
91 | // We must check against these specific cases.
92 | if (isNull(target)) {
93 | throw new TypeError('Cannot convert undefined or null to object');
94 | }
95 |
96 | var output = Object(target);
97 | for (var index = 1; index < arguments.length; index++) {
98 | var source = arguments[index];
99 | if (!isNull(source)) {
100 | for (var nextKey in source) {
101 | if (source.hasOwnProperty(nextKey)) {
102 | output[nextKey] = source[nextKey];
103 | }
104 | }
105 | }
106 | }
107 | return output;
108 | };
109 | }
110 | };
111 |
112 | var ngNumberPicker = exports.ngNumberPicker = function () {
113 |
114 | polyfill();
115 |
116 | var name = 'ngNumberPicker';
117 |
118 | var defaults = {
119 | min: 0,
120 | max: 100,
121 | step: 1,
122 | timeout: 600
123 | };
124 |
125 | var toNumber = function toNumber(value) {
126 | return Number(value);
127 | };
128 |
129 | var checkNumber = function checkNumber(value) {
130 | if (!ng.isNumber(value)) {
131 | throw new Error('value [' + value + '] is not a valid number');
132 | }
133 | };
134 |
135 | var getTarget = function getTarget(e) {
136 | if (e.touches && e.touches.length > 0) {
137 | return ng.element(e.touches[0].target);
138 | }
139 | return ng.element(e.target);
140 | };
141 |
142 | var getType = function getType(e) {
143 | return getTarget(e).attr('type');
144 | };
145 |
146 | var transform = function transform(opts) {
147 | for (var key in opts) {
148 | var value = opts[key];
149 | opts[key] = toNumber(value);
150 | }
151 | };
152 |
153 | var directive = function directive($timeout, $interval) {
154 |
155 | return {
156 | restrict: 'E',
157 | transclude: true,
158 | scope: {
159 | value: '=',
160 | singular: '@',
161 | plural: '@',
162 | unitPosition: '@',
163 | min: '@',
164 | max: '@',
165 | step: '@',
166 | change: '&'
167 | },
168 | link: function link($scope, element) {
169 |
170 | var opts = Object.assign({}, defaults, {
171 | min: $scope.min,
172 | max: $scope.max,
173 | step: $scope.step
174 | });
175 |
176 | transform(opts);
177 |
178 | checkNumber(opts.min);
179 | checkNumber(opts.max);
180 | checkNumber(opts.step);
181 |
182 | if (opts.min > $scope.value) {
183 | $scope.value = opts.min;
184 | }
185 |
186 | $scope.$watch('value', function (newValue, oldValue) {
187 | $scope.canDown = newValue > opts.min;
188 | $scope.canUp = newValue < opts.max;
189 | $scope.unit = newValue === 1 ? $scope.singular : $scope.plural;
190 |
191 | if (newValue !== oldValue) {
192 | $scope.change();
193 | }
194 | });
195 |
196 | var changeNumber = function changeNumber($event) {
197 | var type = getType($event);
198 |
199 | //cast existing value to number, so += will really increment decimal number
200 | $scope.value = Number($scope.value);
201 |
202 | if (type === 'up') {
203 | if ($scope.value >= opts.max) {
204 | return;
205 | }
206 | $scope.value += opts.step;
207 | if ($scope.value > opts.max) {
208 | $scope.value = opts.max;
209 | }
210 | } else if (type === 'down') {
211 | if ($scope.value <= opts.min) {
212 | return;
213 | }
214 | $scope.value -= opts.step;
215 | if ($scope.value < opts.min) {
216 | $scope.value = opts.min;
217 | }
218 | }
219 | };
220 |
221 | var isPressing;
222 | var timeoutPro;
223 | var intervalPro;
224 | var start;
225 | var end;
226 | var addon = element.find('span');
227 |
228 | addon.on('click', function (e) {
229 | changeNumber(e);
230 | $scope.$apply();
231 | e.stopPropagation();
232 | });
233 |
234 | addon.on('touchstart', function (e) {
235 | if (isPressing) {
236 | return;
237 | }
238 | isPressing = true;
239 | getTarget(e).addClass('active');
240 | start = new Date().getTime();
241 | timeoutPro = $timeout(function () {
242 | intervalPro = $interval(function () {
243 | changeNumber(e);
244 | }, 200);
245 | }, opts.timeout);
246 | e.preventDefault();
247 | });
248 |
249 | addon.on('touchend', function (e) {
250 | end = new Date().getTime();
251 | if (intervalPro) {
252 | $interval.cancel(intervalPro);
253 | intervalPro = undefined;
254 | }
255 | if (timeoutPro) {
256 | $timeout.cancel(timeoutPro);
257 | timeoutPro = undefined;
258 | }
259 | if (end - start < opts.timeout) {
260 | changeNumber(e);
261 | $scope.$apply();
262 | }
263 | getTarget(e).removeClass('active');
264 | e.stopPropagation();
265 | isPressing = false;
266 | });
267 |
268 | $scope.$on('$destroy', function () {
269 | addon.off('touchstart touchend click');
270 | });
271 | },
272 | template: '-+
'
273 | };
274 | };
275 |
276 | ng.module(name, []).directive('hNumber', ['$timeout', '$interval', directive]);
277 |
278 | return name;
279 | }();
280 |
281 | /***/ },
282 | /* 1 */
283 | /***/ function(module, exports) {
284 |
285 | module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
286 |
287 | /***/ }
288 | /******/ ])
289 | });
290 | ;
--------------------------------------------------------------------------------