├── .yo-rc.json
├── tests
├── index.js
└── Formatter.spec.js
├── demo
├── FormatterDemo.less
├── index.js
└── FormatterDemo.js
├── src
├── index.js
└── Formatter.js
├── .gitignore
├── .npmignore
├── HISTORY.md
├── index.html
├── .eslintrc.json
├── .travis.yml
├── package.json
└── README.md
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-uxcore": {}
3 | }
--------------------------------------------------------------------------------
/tests/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * only require other specs here
3 | */
4 |
5 | const req = require.context('.', false, /\.spec\.js(x)?$/);
6 | req.keys().forEach(req);
7 |
--------------------------------------------------------------------------------
/demo/FormatterDemo.less:
--------------------------------------------------------------------------------
1 | /**
2 | * Formatter Component Demo Style for Uxcore
3 | * @author guanghong.wsj
4 | *
5 | * Copyright 2014-2015, Uxcore Team, Alinw.
6 | * All rights reserved.
7 | */
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Formatter Component for uxcore
3 | * @author guanghong.wsj
4 | *
5 | * Copyright 2014-2015, Uxcore Team, Alinw.
6 | * All rights reserved.
7 | */
8 |
9 | module.exports = require('./Formatter');
10 |
--------------------------------------------------------------------------------
/demo/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Formatter Component Demo for uxcore
3 | * @author guanghong.wsj
4 | *
5 | * Copyright 2014-2015, Uxcore Team, Alinw.
6 | * All rights reserved.
7 | */
8 |
9 | const Demo = require('./FormatterDemo');
10 | window.Formatter = Demo;
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.log
3 | .idea/
4 | .ipr
5 | .iws
6 | *~
7 | ~*
8 | *.diff
9 | *.patch
10 | *.bak
11 | .DS_Store
12 | Thumbs.db
13 | .project
14 | .*proj
15 | .svn/
16 | *.swp
17 | *.swo
18 | *.pyc
19 | *.pyo
20 | .build
21 | node_modules
22 | _site
23 | sea-modules
24 | spm_modules
25 | .cache
26 | .happypack
27 | dist
28 | build
29 | assets/**/*.css
30 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components/
2 | *.cfg
3 | node_modules/
4 | nohup.out
5 | *.iml
6 | .idea/
7 | .ipr
8 | .iws
9 | *~
10 | ~*
11 | *.diff
12 | *.log
13 | *.patch
14 | *.bak
15 | .DS_Store
16 | Thumbs.db
17 | .project
18 | .*proj
19 | .svn/
20 | *.swp
21 | out/
22 | .build
23 | .happypack
24 | node_modules
25 | _site
26 | sea-modules
27 | spm_modules
28 | .cache
29 | dist
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | # 0.1.8
2 | * `CHANGED` undefined/null/'' return ''
3 | * because they are all invalid value for date.
4 |
5 | # 0.1.7
6 | * `CHANGED` null check
7 |
8 | # 0.1.6
9 | * `CHANGED` fit React@15
10 | * `CHANGED` delete 'package-lock.json' file
11 | # 0.1.3
12 |
13 | * `CHANGED` eslint
14 | * `CHANGED` add tests
15 | * `CHANGED` use default delimeter only delimeter is undefined
16 |
17 | # 0.1.2
18 |
19 | `CHANGED` remove es6 syntax
20 |
21 | # 0.1.1
22 |
23 | `CHANGED` more rational money formatter
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | uxcore-formatter
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "parser": "babel-eslint",
4 | "plugins": [
5 | "react"
6 | ],
7 | "env": {
8 | "browser": true,
9 | "mocha": true
10 | },
11 | "rules": {
12 | "import/no-extraneous-dependencies": "off",
13 | "react/jsx-no-bind": "off",
14 | "no-underscore-dangle": "off",
15 | "jsx-a11y/label-has-for": "off",
16 | "no-plusplus": [
17 | "error",
18 | {
19 | "allowForLoopAfterthoughts": true
20 | }
21 | ],
22 | "react/no-unused-prop-types": "off",
23 | "react/forbid-prop-types": "off",
24 | "jsx-a11y/no-static-element-interactions": "off",
25 | "arrow-body-style": "off"
26 | }
27 | }
--------------------------------------------------------------------------------
/demo/FormatterDemo.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Formatter Component Demo for uxcore
3 | * @author guanghong.wsj
4 | *
5 | * Copyright 2014-2015, Uxcore Team, Alinw.
6 | * All rights reserved.
7 | */
8 |
9 | const Formatter = require('../src');
10 | const log = window.console.log;
11 |
12 | log(Formatter.date(new Date(), 'YYYY-MM-DD HH:mm:ss')); // 2015-10-12 14:22:16
13 | log(Formatter.money('6566456.65466545')); // "6 566 456.65466545"
14 | log(Formatter.money('6566456.65466545', ',')); // "6,566,456.65466545"
15 | log(Formatter.money('6566456', ',')); // "6,566,456"
16 | log(Formatter.money('6566456', ',', 4)); // "6,566,456.0000"
17 | log(Formatter.money('6566456', ',', 2)); // "6,566,456.00"
18 | log(Formatter.money('6566456.65466545', ',', 4)); // "6,566,456.6547"
19 | log(Formatter.money('6566456.65466545', ',', 2)); // "6,566,456.65"
20 | module.exports = Formatter;
21 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | sudo: false
4 |
5 | addons:
6 | apt:
7 | packages:
8 | - xvfb
9 |
10 | notification:
11 | email:
12 | - wsj7552715@hotmail.com
13 |
14 | node_js:
15 | - 6.9.0
16 |
17 | before_install:
18 | - |
19 | if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qve '(\.md$)|(\.html$)'
20 | then
21 | echo "Only docs were updated, stopping build process."
22 | exit
23 | fi
24 | phantomjs --version
25 | install:
26 | - export DISPLAY=':99.0'
27 | - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
28 | - npm install
29 |
30 |
31 | script:
32 | - |
33 | if [ "$TEST_TYPE" = test ]; then
34 | npm test
35 | else
36 | npm run $TEST_TYPE
37 | fi
38 | env:
39 | matrix:
40 | - TEST_TYPE=test
41 | - TEST_TYPE=coverage
42 | - TEST_TYPE=saucelabs
43 |
44 | matrix:
45 | allow_failures:
46 | - env: "TEST_TYPE=saucelabs"
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uxcore-formatter",
3 | "version": "0.1.8",
4 | "description": "a formatter library for uxcore",
5 | "repository": "https://github.com/uxcore/uxcore-formatter.git",
6 | "author": "eternalsky",
7 | "main": "build/index.js",
8 | "scripts": {
9 | "start": "uxcore-tools run start",
10 | "server": "uxcore-tools run server",
11 | "lint": "uxcore-tools run lint",
12 | "build": "uxcore-tools run build",
13 | "test": "uxcore-tools run test",
14 | "coverage": "uxcore-tools run coverage",
15 | "pub": "uxcore-tools run pub",
16 | "dep": "uxcore-tools run dep",
17 | "tnpm-dep": "uxcore-tools run tnpm-dep",
18 | "chrome": "uxcore-tools run chrome",
19 | "browsers": "uxcore-tools run browsers",
20 | "saucelabs": "uxcore-tools run saucelabs",
21 | "update": "uxcore-tools run update",
22 | "tnpm-update": "uxcore-tools run tnpm-update"
23 | },
24 | "bugs": {
25 | "url": "http://github.com/uxcore/uxcore-formatter/issues"
26 | },
27 | "keywords": [
28 | "react",
29 | "react-component",
30 | "uxcore-formatter",
31 | "Formatter",
32 | ""
33 | ],
34 | "devDependencies": {
35 | "console-polyfill": "^0.2.2",
36 | "enzyme": "^3.0.0",
37 | "enzyme-adapter-react-15": "^1.0.0",
38 | "es5-shim": "^4.5.8",
39 | "expect.js": "~0.3.1",
40 | "kuma-base": "1.x",
41 | "react": "15.x",
42 | "react-dom": "15.x",
43 | "react-test-renderer": "15.x",
44 | "uxcore-kuma": "*",
45 | "uxcore-tools": "0.2.x"
46 | },
47 | "dependencies": {
48 | "object-assign": "^2.0.0",
49 | "prop-types": "15.x"
50 | },
51 | "contributors": [],
52 | "license": "MIT"
53 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | ## uxcore-formatter [](https://david-dm.org/uxcore/uxcore-formatter) [](https://david-dm.org/uxcore/uxcore-formatter#info=devDependencies)
4 |
5 |
6 | Formatter 是一些处理字符串的工具函数的集合,他的设计原则是第一个参数为一个 string,返回值为一个 string,后面的参数皆为可选,即有默认值。
7 |
8 | #### setup develop environment
9 |
10 | ```sh
11 | $ git clone https://github.com/uxcore/uxcore-formatter
12 | $ cd uxcore-formatter
13 | $ npm install
14 | $ npm start
15 | ```
16 |
17 | ## Usage
18 | ```
19 | var Formatter = require("uxcore-formatter");
20 | console.log(Formatter.date(new Date(), 'YYYY-MM-DD');
21 | ```
22 |
23 | ## API
24 | > 目前提供的函数包括:
25 |
26 | ### Date
27 | ```javascript
28 | Formatter.date(new Date(), 'YYYY-MM-DD HH:mm:ss'); // 2015-10-12 14:22:16
29 | ```
30 |
31 | ### money
32 |
33 | ```javascript
34 | Formatter.money("6566456.65466545") // "6 566 456.65466545"
35 | Formatter.money("6566456.65466545", ",") // "6,566,456.65466545"
36 | Formatter.money("6566456", ",") // "6,566,456"
37 | Formatter.money("6566456", ",", 4) // "6,566,456.0000"
38 | Formatter.money("6566456", ",", 2) // "6,566,456.00"
39 | Formatter.money("6566456.65466545", ",", 4) // "6,566,456.6547"
40 | Formatter.money("6566456.65466545", ",", 2) // "6,566,456.65"
41 | ```
42 |
43 | ### cnmobile
44 | ```javascript
45 | Formatter.cnmobile('+8615652988282', ' '); // +86 1565 2988 282
46 | ```
47 |
48 | ### card
49 | ```javascript
50 | Formatter.card('1565298828212233', ' '); // 1565 2988 2821 2233
51 | ```
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/Formatter.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console: "off" */
2 | /**
3 | * Formatter Component for uxcore
4 | * @author eternalsky
5 | *
6 | * Copyright 2014-2015, Uxcore Team, Alinw.
7 | * All rights reserved.
8 | */
9 |
10 | const Formatter = {};
11 |
12 | Formatter.date = (str, pattern) => {
13 | // new Date(null,false) 会返回最初日期。
14 | if (str === null || str === false || str === undefined || str === '') {
15 | console.warn('Formatter: invalid date');
16 | return '';
17 | }
18 | const date = new Date(str);
19 | if (Object.prototype.toString.call(date) === '[object Date]') {
20 | if (isNaN(date.getTime())) {
21 | // invalid
22 | console.warn('Formatter: invalid date');
23 | return '';
24 | }
25 | let actualPattern = pattern || 'YYYY-MM-DD';
26 | const o = {
27 | 'M+': date.getMonth() + 1, // 月份
28 | 'D+': date.getDate(), // 日
29 | 'd+': date.getDate(), // 日
30 | 'H+': date.getHours(), // 小时
31 | 'h+': date.getHours(), // 小时
32 | 'm+': date.getMinutes(), // 分
33 | 's+': date.getSeconds(), // 秒
34 | 'Q+': Math.floor((date.getMonth() + 3) / 3), // 季度
35 | 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
36 | S: date.getMilliseconds(), // 毫秒
37 | };
38 | if (/(y+)/i.test(actualPattern)) {
39 | actualPattern = actualPattern.replace(
40 | RegExp.$1,
41 | (`${date.getFullYear()}`).substr(4 - RegExp.$1.length)
42 | );
43 | }
44 | // for (const k in o) {
45 | // if (new RegExp(`(${k})`).test(actualPattern)) {
46 | // actualPattern = actualPattern.replace(RegExp.$1,
47 | // (RegExp.$1.length === 1) ? (o[k]) : ((`00${o[k]}`).substr((`${o[k]}`).length))
48 | // );
49 | // }
50 | // }
51 | Object.keys(o).forEach((k) => {
52 | if (new RegExp(`(${k})`).test(actualPattern)) {
53 | actualPattern = actualPattern.replace(RegExp.$1,
54 | (RegExp.$1.length === 1) ? (o[k]) : ((`00${o[k]}`).substr((`${o[k]}`).length))
55 | );
56 | }
57 | });
58 | return actualPattern;
59 | }
60 | return '';
61 | };
62 |
63 | Formatter.money = (str, delimiter = ' ', fixedNum) => {
64 | const actualStr = fixedNum ? parseFloat(str).toFixed(fixedNum).toString() : str;
65 | if (actualStr.indexOf('.') !== -1) {
66 | return actualStr.replace(/(\d)(?=(?:\d{3})+(\.))/g, (match, $1) => $1 + delimiter)
67 | .replace(/(\d{3})(?![$|\.|\(|\s])/g, (match, $1) => $1);
68 | }
69 | return actualStr.replace(/(\d)(?=(?:\d{3})+$)/g, (match, $1) => $1 + delimiter);
70 | };
71 |
72 | Formatter.cnmobile = (str, delimiter = ' ') => {
73 | return str.replace(/^(\+?0?86)(?!$)/,
74 | `$1${delimiter}`
75 | ).replace(/(\d{4})(?!$)/g, `$1${delimiter}`);
76 | };
77 |
78 | Formatter.card = (str, delimiter = ' ') => {
79 | return str.replace(/(\d{4})(?!$)/g, `$1${delimiter}`);
80 | };
81 |
82 | export default Formatter;
83 |
--------------------------------------------------------------------------------
/tests/Formatter.spec.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect.js';
2 | import Formatter from '../src';
3 |
4 | String.prototype.padStart = function (targetLength, padString) {
5 | padString = padString || ' ';
6 | if (this.length >= targetLength) {
7 | return this;
8 | }
9 | const gap = targetLength - this.length;
10 | const times = Math.floor(gap / padString.length);
11 | let result = '';
12 | for (let i = 0; i < times; i++) {
13 | result += padString;
14 | }
15 | return result + padString.slice(0, gap % padString.length) + this;
16 | };
17 |
18 | describe('Formatter.date', () => {
19 | const date = new Date();
20 | it('returns empty string when date is invalid', () => {
21 | expect(Formatter.date('test!@#$%^', 'YYYY-MM-DD')).to.be('');
22 | });
23 |
24 | it('returns empty string when date is null', () => {
25 | expect(Formatter.date(null, 'YYYY-MM-DD')).to.be('');
26 | expect(Formatter.date(undefined, 'YYYY-MM-DD')).to.be('');
27 | expect(Formatter.date(false, 'YYYY-MM-DD')).to.be('');
28 | expect(Formatter.date('', 'YYYY-MM-DD')).to.be('');
29 | });
30 |
31 | it('works fine', () => {
32 | expect(Formatter.date(date, 'YYYY-MM-DD')).to.be(`${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(2, '0')}-${`${date.getDate()}`.padStart(2, '0')}`);
33 | });
34 |
35 | it('works without pattern', () => {
36 | expect(Formatter.date(date)).to.be(`${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(2, '0')}-${`${date.getDate()}`.padStart(2, '0')}`);
37 | });
38 |
39 | it('works with custom pattern', () => {
40 | expect(Formatter.date(date, 'MM-DD')).to.be(`${date.getMonth() < 9 ? `0${date.getMonth() + 1}` : date.getMonth() + 1}-${date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()}`);
41 | expect(Formatter.date(date, 'DD')).to.be(`${date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()}`);
42 | expect(Formatter.date(date, 'MM-dd')).to.be(`${date.getMonth() < 9 ? `0${date.getMonth() + 1}` : date.getMonth() + 1}-${date.getDate() < 10 ? `0${date.getDate()}` : date.getDate()}`);
43 | expect(Formatter.date(date, 'QQ')).to.be(`${Math.floor(date.getMonth() / 3) + 1}`.padStart(2, '0'));
44 | expect(Formatter.date(date, 'qq')).to.be(`${Math.floor(date.getMonth() / 3) + 1}`.padStart(2, '0'));
45 | expect(Formatter.date(date, 'hh:mm:ss S')).to.be(`${`${date.getHours()}`.padStart(2, '0')}:${`${date.getMinutes()}`.padStart(2, '0')}:${`${date.getSeconds()}`.padStart(2, '0')} ${`${date.getMilliseconds()}`.padStart(3, '0')}`);
46 | });
47 | });
48 |
49 | describe('Formatter.money', () => {
50 | it('works fine', () => {
51 | expect(Formatter.money('100', ' ')).to.be('100');
52 | expect(Formatter.money('1000000000', ' ')).to.be('1 000 000 000');
53 | expect(Formatter.money('1000000000.999999', ' ')).to.be('1 000 000 000.999999');
54 | });
55 |
56 | it('works without delimiter', () => {
57 | expect(Formatter.money('100')).to.be('100');
58 | expect(Formatter.money('1000000000')).to.be('1 000 000 000');
59 | expect(Formatter.money('1000000000.999999')).to.be('1 000 000 000.999999');
60 | });
61 |
62 | it('works with custom delimiter', () => {
63 | expect(Formatter.money('100', ',')).to.be('100');
64 | expect(Formatter.money('1000000000', ',')).to.be('1,000,000,000');
65 | expect(Formatter.money('1000000000.999999', ',')).to.be('1,000,000,000.999999');
66 | expect(Formatter.money('1000000000', '')).to.be('1000000000');
67 | });
68 |
69 | it('works with fixed number', () => {
70 | expect(Formatter.money('100', ',', 0)).to.be('100');
71 | expect(Formatter.money('100', ',', 2)).to.be('100.00');
72 | expect(Formatter.money('1000000000.8888', ',', 2)).to.be('1,000,000,000.89');
73 | expect(Formatter.money('1000000000.99', ',', 5)).to.be('1,000,000,000.99000');
74 | });
75 | });
76 |
77 | describe('Formatter.cnmobile', () => {
78 | it('works fine', () => {
79 | expect(Formatter.cnmobile('13888888888', ' ')).to.be('1388 8888 888');
80 | expect(Formatter.cnmobile('+8613888888888', ' ')).to.be('+86 1388 8888 888');
81 | expect(Formatter.cnmobile('08613888888888', ' ')).to.be('086 1388 8888 888');
82 | });
83 |
84 | it('works without delimiter', () => {
85 | expect(Formatter.cnmobile('13888888888')).to.be('1388 8888 888');
86 | expect(Formatter.cnmobile('+8613888888888')).to.be('+86 1388 8888 888');
87 | expect(Formatter.cnmobile('08613888888888')).to.be('086 1388 8888 888');
88 | });
89 |
90 | it('works with custom delimiter', () => {
91 | expect(Formatter.cnmobile('13888888888', ',')).to.be('1388,8888,888');
92 | expect(Formatter.cnmobile('+8613888888888', ',')).to.be('+86,1388,8888,888');
93 | expect(Formatter.cnmobile('08613888888888', ',')).to.be('086,1388,8888,888');
94 | });
95 | });
96 |
97 | describe('Formatter.card', () => {
98 | it('works fine', () => {
99 | expect(Formatter.card('1234', ' ')).to.be('1234');
100 | expect(Formatter.card('12345678', ' ')).to.be('1234 5678');
101 | expect(Formatter.card('123456789012', ' ')).to.be('1234 5678 9012');
102 | expect(Formatter.card('1234567890123456', ' ')).to.be('1234 5678 9012 3456');
103 | expect(Formatter.card('1234567890123456789', ' ')).to.be('1234 5678 9012 3456 789');
104 | });
105 |
106 | it('works without delimiter', () => {
107 | expect(Formatter.card('1234')).to.be('1234');
108 | expect(Formatter.card('12345678')).to.be('1234 5678');
109 | expect(Formatter.card('123456789012')).to.be('1234 5678 9012');
110 | expect(Formatter.card('1234567890123456')).to.be('1234 5678 9012 3456');
111 | expect(Formatter.card('1234567890123456789')).to.be('1234 5678 9012 3456 789');
112 | });
113 |
114 | it('works with custom delimiter', () => {
115 | expect(Formatter.card('12345678', ',')).to.be('1234,5678');
116 | expect(Formatter.card('123456789012', ',')).to.be('1234,5678,9012');
117 | expect(Formatter.card('1234567890123456', ',')).to.be('1234,5678,9012,3456');
118 | expect(Formatter.card('1234567890123456789', ',')).to.be('1234,5678,9012,3456,789');
119 | });
120 | });
121 |
--------------------------------------------------------------------------------