├── .babelrc ├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist ├── vue2-filters.js └── vue2-filters.min.js ├── package.json ├── src ├── array │ ├── filterBy.js │ ├── find.js │ ├── index.js │ ├── limitBy.js │ └── orderBy.js ├── index.js ├── other │ ├── bytes.js │ ├── currency.js │ ├── index.js │ ├── number.js │ ├── ordinal.js │ ├── percent.js │ └── pluralize.js ├── string │ ├── capitalize.js │ ├── index.js │ ├── lowercase.js │ ├── placeholder.js │ ├── repeat.js │ ├── reverse.js │ ├── truncate.js │ ├── uppercase.js │ └── wrap.js └── util │ └── index.js ├── test ├── filters.spec.js └── karma.conf.js ├── types └── index.d.ts └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ] 5 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://www.paypal.me/arhey","https://www.buymeacoffee.com/arhey"] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | index.html 4 | package-lock.json 5 | examples/ 6 | .DS_Store 7 | .vs 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 7 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-present, Aleksandr Statciuk 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue2-filters [![Build Status](https://app.travis-ci.com/freearhey/vue2-filters.svg?branch=master)](https://app.travis-ci.com/freearhey/vue2-filters) 2 | 3 | A collection Vue.js filters. 4 | 5 | ## Installation 6 | 7 | ### Direct include 8 | 9 | Simply include `vue2-filters` after Vue and it will install itself automatically: 10 | 11 | ```html 12 | 13 | 14 | ``` 15 | 16 | To use one of the predefined methods (such as `limitBy`, `filterBy`, `find`, or `orderBy`) in your component, you also need to add `Vue2Filters.mixin` to mixin list: 17 | 18 | ```html 19 | 26 | ``` 27 | 28 | ### CDN [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/vue2-filters/badge?style=rounded)](https://www.jsdelivr.com/package/npm/vue2-filters) 29 | 30 | ```html 31 | 32 | 33 | ``` 34 | 35 | To use one of the predefined methods (such as `limitBy`, `filterBy`, `find`, or `orderBy`) in your component, you also need to add `Vue2Filters.mixin` to mixin list: 36 | 37 | ```html 38 | 45 | ``` 46 | 47 | ### NPM [![npm](https://img.shields.io/npm/dm/vue2-filters.svg)](https://www.npmjs.com/package/vue2-filters) 48 | 49 | ``` 50 | npm install vue2-filters 51 | ``` 52 | 53 | When used with a module system, you must explicitly install the filters via `Vue.use()`: 54 | 55 | ```js 56 | import Vue from 'vue' 57 | import Vue2Filters from 'vue2-filters' 58 | 59 | Vue.use(Vue2Filters) 60 | ``` 61 | 62 | You don't need to do this when using global script tags. 63 | 64 | To use one of the predefined methods (such as `limitBy`, `filterBy`, `find`, or `orderBy`) in your component, you also need to add `Vue2Filters.mixin` to mixin list: 65 | 66 | ```js 67 | import Vue2Filters from 'vue2-filters' 68 | 69 | export default { 70 | ... 71 | mixins: [Vue2Filters.mixin], 72 | ... 73 | } 74 | ``` 75 | 76 | ### Nuxt.js 77 | 78 | ``` 79 | npm install vue2-filters 80 | ``` 81 | 82 | When create file `plugins/vue2-filters.js`: 83 | 84 | ```js 85 | import Vue from 'vue' 86 | import Vue2Filters from 'vue2-filters' 87 | 88 | Vue.use(Vue2Filters) 89 | ``` 90 | 91 | Then, add the file inside the `plugins` key of `nuxt.config.js`: 92 | 93 | ```js 94 | module.exports = { 95 | //... 96 | plugins: [ 97 | '~/plugins/vue2-filters' 98 | ], 99 | //... 100 | } 101 | ``` 102 | 103 | To use one of the predefined methods (such as `limitBy`, `filterBy`, `find`, or `orderBy`) in your component, you also need to add `Vue2Filters.mixin` to mixin list: 104 | 105 | ```js 106 | import Vue2Filters from 'vue2-filters' 107 | 108 | export default { 109 | ... 110 | mixins: [Vue2Filters.mixin], 111 | ... 112 | } 113 | ``` 114 | 115 | ## Available Filters 116 | 117 | - [capitalize](#capitalize) 118 | - [uppercase](#uppercase) 119 | - [lowercase](#lowercase) 120 | - [placeholder](#placeholder) 121 | - [truncate](#truncate) 122 | - [repeat](#repeat) 123 | - [reverse](#reverse) 124 | - [wrap](#wrap) 125 | - [number](#number) 126 | - [bytes](#bytes) 127 | - [percent](#percent) 128 | - [currency](#currency) 129 | - [pluralize](#pluralize) 130 | - [ordinal](#ordinal) 131 | - [limitBy](#limitBy) 132 | - [filterBy](#filterBy) 133 | - [find](#find) 134 | - [orderBy](#orderBy) 135 | 136 | ## Usage 137 | 138 | #### capitalize 139 | 140 | + Arguments: 141 | * `{Object} [options] - default: {}` 142 | 143 | + Options: 144 | * `{Boolean} [onlyFirstLetter] - default: false` 145 | 146 | + Example: 147 | 148 | ```js 149 | {{ msg | capitalize }} // 'abc' => 'Abc' 150 | ``` 151 | Capitalize only first letter of sentence: 152 | 153 | ```js 154 | {{ msg | capitalize({ onlyFirstLetter: true }) }} // 'lorem ipsum dolor' => 'Lorem ipsum dolor' 155 | ``` 156 | 157 | 158 | #### uppercase 159 | 160 | + Example: 161 | 162 | ```js 163 | {{ msg | uppercase }} // 'abc' => 'ABC' 164 | ``` 165 | 166 | #### lowercase 167 | 168 | + Example: 169 | 170 | ```js 171 | {{ msg | lowercase }} // 'ABC' => 'abc' 172 | ``` 173 | 174 | #### placeholder 175 | 176 | + Arguments: 177 | * `{String} [placeholder]` 178 | 179 | + Example: 180 | 181 | ```js 182 | {{ msg | placeholder('Text if msg is missing') }} // '' => 'Text if msg is missing' 183 | ``` 184 | 185 | #### truncate 186 | 187 | + Arguments: 188 | * `{Number} [length] - default: 15` 189 | 190 | + Example: 191 | 192 | ```js 193 | {{ msg | truncate(10) }} // 'lorem ipsum dolor' => 'lorem ipsu...' 194 | ``` 195 | 196 | #### repeat 197 | 198 | + Arguments: 199 | * `{Number} [amount] - default: 1` 200 | 201 | + Example: 202 | 203 | ```js 204 | {{ msg | repeat(3) }} // 'a' => 'aaa' 205 | ``` 206 | 207 | #### reverse 208 | 209 | + Example: 210 | 211 | ```js 212 | {{ msg | reverse }} // 'abc' => 'cba' 213 | ``` 214 | 215 | #### wrap 216 | 217 | + Arguments: 218 | * `{String} [string]` 219 | 220 | + Example: 221 | 222 | ```js 223 | {{ msg | wrap('###') }} // 'ipsum' => '###ipsum###' 224 | ``` 225 | 226 | #### number 227 | 228 | + Arguments: 229 | * `{String} [format] - default: ''` 230 | * `{Object} [options] - default: {}` 231 | 232 | + Options: 233 | * `{String} [thousandsSeparator] - default: ','` 234 | * `{String} [decimalSeparator] - default: '.'` 235 | 236 | + Examples: 237 | 238 | ```js 239 | {{ 123456 | number('0,0') }} // => 123,456 240 | ``` 241 | 242 | Change the number of digits after the decimal point: 243 | 244 | ```js 245 | {{ 12345.67 | number('0.0000') }} // => 12345.6700 246 | ``` 247 | 248 | Add a plus or minus sign to the beginning: 249 | 250 | ```js 251 | {{ 123456 | number('+0') }} // => +123456 252 | {{ 123456 | number('-0') }} // => -123456 253 | ``` 254 | 255 | Show number in thousand (K) or in millions (M): 256 | 257 | ```js 258 | {{ 123456 | number('0a') }} // => 123K 259 | {{ 123456 | number('0 a') }} // => 123 K 260 | {{ 123456789 | number('0a') }} // => 123M 261 | ``` 262 | 263 | Use a different thousands separator: 264 | 265 | ```js 266 | {{ 1234567 | number('0,0', { thousandsSeparator: ' ' }) }} // => 1 234 567 267 | ``` 268 | Use a different decimal separator: 269 | 270 | ```js 271 | {{ 12345.67 | number('0.00', { decimalSeparator: '|' }) }} // => 12,345|67 272 | ``` 273 | 274 | #### bytes 275 | 276 | + Arguments: 277 | * `{Number} [decimalDigits] - default: 2` 278 | 279 | + Examples: 280 | 281 | ```js 282 | {{ 1 | bytes }} // => 1 byte 283 | {{ 20 | bytes }} // => 20 bytes 284 | {{ 2000 | bytes }} // => 1.95 kB 285 | {{ 2000000 | bytes }} // => 1.91 MB 286 | {{ 2000000000 | bytes }} // => 1.86 GB 287 | {{ 2000000000000 | bytes }} // => 1.82 TB 288 | ``` 289 | 290 | Change the number of digits after the decimal point: 291 | 292 | ```js 293 | {{ 2000000000 | bytes(4) }} // => 1.8626 GB 294 | ``` 295 | 296 | #### percent 297 | 298 | + Arguments: 299 | * `{Number} [decimalDigits] - default: 0` 300 | * `{Number} [multiplier] - default: 100` 301 | * `{Object} [options] - default: {}` 302 | 303 | + Options: 304 | * `{String} [decimalSeparator] - default: '.'` 305 | 306 | + Examples: 307 | 308 | ```js 309 | {{ 0.01 | percent }} // => 1% 310 | {{ 0.1 | percent }} // => 10% 311 | {{ 1 | percent }} // => 100% 312 | {{ 100 | percent }} // => 10000% 313 | {{ 0.97 | percent }} // => 97% 314 | ``` 315 | 316 | Change the number of digits after the decimal point: 317 | 318 | ```js 319 | {{ 0.974878234 | percent(3) }} // => 97.488% 320 | ``` 321 | 322 | Change the multiplier: 323 | 324 | ```js 325 | {{ 0.974878234 | percent(3, 150) }} // => 146.232% 326 | ``` 327 | 328 | Use a different decimal separator: 329 | 330 | ```js 331 | {{ 0.07 | percent(2, 100, { decimalSeparator: '|' }) }} // => 7|00% 332 | ``` 333 | 334 | #### currency 335 | 336 | + Arguments: 337 | * `{String} [symbol] - default: '$'` 338 | * `{Number} [decimalDigits] - default: 2` 339 | * `{Object} [options] - default: {}` 340 | 341 | + Options: 342 | * `{String} [thousandsSeparator] - default: ','` 343 | * `{String} [decimalSeparator] - default: '.'` 344 | * `{Boolean} [symbolOnLeft] - default: true` 345 | * `{Boolean} [spaceBetweenAmountAndSymbol] - default: false` 346 | * `{Boolean} [showPlusSign] - default: false` 347 | 348 | + Example: 349 | 350 | ```js 351 | {{ amount | currency }} // 12345 => $12,345.00 352 | ``` 353 | Use a different symbol: 354 | 355 | ```js 356 | {{ amount | currency('£') }} // 12345 => £12,345.00 357 | ``` 358 | Use a different number decimal places: 359 | 360 | ```js 361 | {{ amount | currency('₽', 0) }} // 12345 => ₽12,345 362 | ``` 363 | Use a different thousands separator: 364 | 365 | ```js 366 | {{ amount | currency('$', 0, { thousandsSeparator: '.' }) }} // 12345 => $12.345 367 | ``` 368 | Use a different decimal separator: 369 | 370 | ```js 371 | {{ amount | currency('$', 2, { decimalSeparator: ',' }) }} // 12345 => $12,345,00 372 | ``` 373 | Use symbol on right: 374 | 375 | ```js 376 | {{ amount | currency('$', 0, { symbolOnLeft: false }) }} // 12345 => 12,345$ 377 | ``` 378 | Add space between amount and symbol: 379 | 380 | ```js 381 | {{ amount | currency('$', 0, { spaceBetweenAmountAndSymbol: true }) }} // 12345 => $ 12,345 382 | ``` 383 | 384 | Show the plus sign if the value is greater than zero: 385 | 386 | ```js 387 | {{ amount | currency('$', 0, { showPlusSign: true }) }} // 12345 => +$12,345 388 | ``` 389 | Use multiple options: 390 | 391 | ```js 392 | {{ amount | currency('kr', 2, { symbolOnLeft: false, spaceBetweenAmountAndSymbol: true }) }} // 12345 => 12,345.00 kr 393 | ``` 394 | 395 | #### pluralize 396 | 397 | + Arguments: 398 | * `{String|Array} single or Array(single, double, triple, ...)` 399 | * `{Object} [options] - default: {}` 400 | 401 | + Options: 402 | * `{Boolean} [includeNumber] - default: false` 403 | 404 | + Example: 405 | 406 | ```js 407 | {{ count }} {{ count | pluralize('item') }} 408 | 409 | // 1 => '1 item' 410 | // 2 => '2 items' 411 | ``` 412 | 413 | Use an array of words: 414 | 415 | ```js 416 | {{ count }} {{ count | pluralize(['fry', 'fries']) }} 417 | 418 | // 1 => '1 fry' 419 | // 2 => '2 fries' 420 | // 3 => '3 fries' 421 | ``` 422 | 423 | Include number to output: 424 | 425 | ```js 426 | {{ count | pluralize('test', { includeNumber: true }) }} 427 | 428 | // 1 => '1 test' 429 | // 2 => '2 tests' 430 | ``` 431 | 432 | #### ordinal 433 | 434 | + Arguments: 435 | * `{Object} [options] - default: {}` 436 | 437 | + Options: 438 | * `{Boolean} [includeNumber] - default: false` 439 | 440 | + Example: 441 | 442 | ```js 443 | {{ date | ordinal }} 444 | 445 | // 1 => 'st' 446 | // 2 => 'nd' 447 | // 3 => 'rd' 448 | // 4 => 'th' 449 | // 5 => 'th' 450 | ``` 451 | 452 | Include number to output: 453 | 454 | ```js 455 | {{ date | ordinal({ includeNumber: true }) }} 456 | 457 | // 1 => '1st' 458 | // 2 => '2nd' 459 | ``` 460 | 461 | #### limitBy 462 | 463 | + Arguments: 464 | * `{Number|Array} [items]` 465 | * `{Number} [limit]` 466 | * `{Number} [offset]` 467 | 468 | + Example: 469 | 470 | ```html 471 | 472 |
{{ item }}
473 | 474 |
{{ item }}
475 | 476 |
{{ n }}
477 | ``` 478 | 479 | #### filterBy 480 | 481 | + Arguments: 482 | * `{Array} [items]` 483 | * `{String} [query]` 484 | * `{String} [searchKey]` 485 | 486 | + Example: 487 | 488 | ```html 489 | 490 |
491 | 492 |
493 | 494 |
495 | 496 |
497 | ``` 498 | 499 | #### find 500 | 501 | + Arguments: 502 | * `{Array} [items]` 503 | * `{String} [query]` 504 | * `{String} [searchKey]` 505 | 506 | + Example: 507 | 508 | ```html 509 | 510 |
511 | 512 |
513 | ``` 514 | 515 | #### orderBy 516 | 517 | + Arguments: 518 | * `{Array} [items]` 519 | * `{String} [sortKey]` 520 | * `{Number} [order] - default: 1` 521 | 522 | + Example: 523 | 524 | Sort users by name: 525 | 526 | ```html 527 |
    528 |
  • 529 | {{ user.name }} 530 |
  • 531 |
532 | ``` 533 | In descending order: 534 | 535 | ```html 536 |
    537 |
  • 538 | {{ user.name }} 539 |
  • 540 |
541 | ``` 542 | Sort primitive values: 543 | 544 | ```html 545 |
    546 |
  • 547 | {{ name }} 548 |
  • 549 |
550 | ``` 551 | 552 | ## Global Configuration 553 | 554 | If you need to override filter options globally you can do so by passing an object into `Vue.use()` function as the second argument: 555 | 556 | ```js 557 | import Vue from 'vue' 558 | import Vue2Filters from 'vue2-filters' 559 | 560 | var Vue2FiltersConfig = { 561 | capitalize: { 562 | onlyFirstLetter: false 563 | }, 564 | number: { 565 | format: '0', 566 | thousandsSeparator: ',', 567 | decimalSeparator: '.' 568 | }, 569 | bytes: { 570 | decimalDigits: 2 571 | }, 572 | percent: { 573 | decimalDigits: 2, 574 | multiplier: 100, 575 | decimalSeparator: '.' 576 | }, 577 | currency: { 578 | symbol: '$', 579 | decimalDigits: 2, 580 | thousandsSeparator: ',', 581 | decimalSeparator: '.', 582 | symbolOnLeft: true, 583 | spaceBetweenAmountAndSymbol: false, 584 | showPlusSign: false 585 | }, 586 | pluralize: { 587 | includeNumber: false 588 | }, 589 | ordinal: { 590 | includeNumber: false 591 | } 592 | } 593 | 594 | Vue.use(Vue2Filters, Vue2FiltersConfig) 595 | ``` 596 | 597 | ## Programmatic Usage 598 | 599 | Aside from using filters inside templates you can do this programmatically using default filters object: 600 | 601 | ```js 602 | this.$options.filters.filterName(value) 603 | ``` 604 | 605 | For example, here's how you can use the `currency`filter: 606 | 607 | ```js 608 | this.$options.filters.currency(100) // => $100.00 609 | ``` 610 | 611 | As for such filters as `limitBy`, `filterBy`, `find`, or `orderBy`, they can be used as usual methods: 612 | 613 | ```js 614 | this.limitBy([1,2,3,4,5], 2) // => [1,2] 615 | ``` 616 | 617 | ## Upgrade Guide 618 | 619 | ### Upgrade to 0.6.0 from 0.5.* 620 | 621 | #### The `pluralize` filter 622 | 623 | The `pluralize` filter arguments order has been changed. In the new version to specify several variants of words you can do this by passing an array as first argument, like so: 624 | 625 | ```js 626 | {{ count | pluralize(['item', 'items']) }} 627 | ```` 628 | 629 | In addition, the function of translate a regular number to its ordinal representation was removed from the `pluralize` filter. Now there is a separate `ordinal` filter for this: 630 | 631 | ```js 632 | {{ count | ordinal }} 633 | ``` 634 | 635 | ### Upgrade to 0.5.0 from 0.4.* 636 | 637 | #### The `capitalize` filter 638 | 639 | To match the definition of the word "capitalize", the default filter behavior has been changed. The filter now capitalizes the first letter in each word in the sentence (like CSS property `text-transform`). 640 | 641 | If you want capitalize only first letter of sentence, you just need to add the `onlyFirstLetter` parameter to the filter, like so: 642 | 643 | ```js 644 | {{ msg | capitalize({ onlyFirstLetter: true }) }} 645 | ``` 646 | 647 | ### Upgrade to 0.4.0 from 0.3.* 648 | 649 | In the new version it was decided to refuse from global registration of mixins, as it could lead to errors when using this package with other packages. Therefore, you need to manually add `Vue2Filters.mixin` into the mixin list of your components if you use at least one of the predefined methods (such as `limitBy`, `filterBy`, `find` or `orderBy`): 650 | 651 | ```js 652 | export default { 653 | ... 654 | mixins: [Vue2Filters.mixin], 655 | ... 656 | } 657 | ``` 658 | 659 | You can read more about the reasons for this change [here](https://github.com/freearhey/vue2-filters/issues/52) 660 | 661 | ## Contribution 662 | 663 | If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/freearhey/vue2-filters/issues) or a [pull request](https://github.com/freearhey/vue2-filters/pulls). 664 | 665 | ## License 666 | 667 | [MIT](http://opensource.org/licenses/MIT) 668 | -------------------------------------------------------------------------------- /dist/vue2-filters.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else { 7 | var a = factory(); 8 | for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; 9 | } 10 | })(typeof self !== 'undefined' ? self : this, function() { 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 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 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.l = 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 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 50 | /******/ } 51 | /******/ }; 52 | /******/ 53 | /******/ // define __esModule on exports 54 | /******/ __webpack_require__.r = function(exports) { 55 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 56 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 57 | /******/ } 58 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 59 | /******/ }; 60 | /******/ 61 | /******/ // create a fake namespace object 62 | /******/ // mode & 1: value is a module id, require it 63 | /******/ // mode & 2: merge all properties of value into the ns 64 | /******/ // mode & 4: return value when already ns object 65 | /******/ // mode & 8|1: behave like require 66 | /******/ __webpack_require__.t = function(value, mode) { 67 | /******/ if(mode & 1) value = __webpack_require__(value); 68 | /******/ if(mode & 8) return value; 69 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 70 | /******/ var ns = Object.create(null); 71 | /******/ __webpack_require__.r(ns); 72 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 73 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 74 | /******/ return ns; 75 | /******/ }; 76 | /******/ 77 | /******/ // getDefaultExport function for compatibility with non-harmony modules 78 | /******/ __webpack_require__.n = function(module) { 79 | /******/ var getter = module && module.__esModule ? 80 | /******/ function getDefault() { return module['default']; } : 81 | /******/ function getModuleExports() { return module; }; 82 | /******/ __webpack_require__.d(getter, 'a', getter); 83 | /******/ return getter; 84 | /******/ }; 85 | /******/ 86 | /******/ // Object.prototype.hasOwnProperty.call 87 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 88 | /******/ 89 | /******/ // __webpack_public_path__ 90 | /******/ __webpack_require__.p = ""; 91 | /******/ 92 | /******/ 93 | /******/ // Load entry module and return exports 94 | /******/ return __webpack_require__(__webpack_require__.s = 0); 95 | /******/ }) 96 | /************************************************************************/ 97 | /******/ ([ 98 | /* 0 */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | var string_namespaceObject = {}; 104 | __webpack_require__.r(string_namespaceObject); 105 | __webpack_require__.d(string_namespaceObject, "capitalize", function() { return string_capitalize; }); 106 | __webpack_require__.d(string_namespaceObject, "uppercase", function() { return string_uppercase; }); 107 | __webpack_require__.d(string_namespaceObject, "lowercase", function() { return string_lowercase; }); 108 | __webpack_require__.d(string_namespaceObject, "placeholder", function() { return string_placeholder; }); 109 | __webpack_require__.d(string_namespaceObject, "truncate", function() { return string_truncate; }); 110 | __webpack_require__.d(string_namespaceObject, "repeat", function() { return string_repeat; }); 111 | __webpack_require__.d(string_namespaceObject, "wrap", function() { return string_wrap; }); 112 | __webpack_require__.d(string_namespaceObject, "reverse", function() { return string_reverse; }); 113 | var array_namespaceObject = {}; 114 | __webpack_require__.r(array_namespaceObject); 115 | __webpack_require__.d(array_namespaceObject, "limitBy", function() { return array_limitBy; }); 116 | __webpack_require__.d(array_namespaceObject, "filterBy", function() { return array_filterBy; }); 117 | __webpack_require__.d(array_namespaceObject, "orderBy", function() { return array_orderBy; }); 118 | __webpack_require__.d(array_namespaceObject, "find", function() { return array_find; }); 119 | var other_namespaceObject = {}; 120 | __webpack_require__.r(other_namespaceObject); 121 | __webpack_require__.d(other_namespaceObject, "currency", function() { return other_currency; }); 122 | __webpack_require__.d(other_namespaceObject, "bytes", function() { return other_bytes; }); 123 | __webpack_require__.d(other_namespaceObject, "pluralize", function() { return other_pluralize; }); 124 | __webpack_require__.d(other_namespaceObject, "ordinal", function() { return other_ordinal; }); 125 | __webpack_require__.d(other_namespaceObject, "number", function() { return other_number; }); 126 | __webpack_require__.d(other_namespaceObject, "percent", function() { return other_percent; }); 127 | 128 | // CONCATENATED MODULE: ./src/util/index.js 129 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } 130 | 131 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } 132 | 133 | function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } 134 | 135 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } 136 | 137 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 138 | 139 | var ArrayProto = Array.prototype, 140 | ObjProto = Object.prototype; 141 | var slice = ArrayProto.slice, 142 | util_toString = ObjProto.toString; 143 | var util = {}; 144 | 145 | util.isArray = function (obj) { 146 | return Array.isArray(obj); 147 | }; 148 | 149 | var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; 150 | 151 | util.isArrayLike = function (obj) { 152 | if (_typeof(obj) !== 'object' || !obj) { 153 | return false; 154 | } 155 | 156 | var length = obj.length; 157 | return typeof length === 'number' && length % 1 === 0 && length >= 0 && length <= MAX_ARRAY_INDEX; 158 | }; 159 | 160 | util.isObject = function (obj) { 161 | var type = _typeof(obj); 162 | 163 | return type === 'function' || type === 'object' && !!obj; 164 | }; 165 | 166 | util.each = function (obj, callback) { 167 | var i, len; 168 | 169 | if (util.isArray(obj)) { 170 | for (i = 0, len = obj.length; i < len; i++) { 171 | if (callback(obj[i], i, obj) === false) { 172 | break; 173 | } 174 | } 175 | } else { 176 | for (i in obj) { 177 | if (callback(obj[i], i, obj) === false) { 178 | break; 179 | } 180 | } 181 | } 182 | 183 | return obj; 184 | }; 185 | 186 | util.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function (name) { 187 | util['is' + name] = function (obj) { 188 | return util_toString.call(obj) === '[object ' + name + ']'; 189 | }; 190 | }); 191 | 192 | util.toArray = function (list, start) { 193 | start = start || 0; 194 | var i = list.length - start; 195 | var ret = new Array(i); 196 | 197 | while (i--) { 198 | ret[i] = list[i + start]; 199 | } 200 | 201 | return ret; 202 | }; 203 | 204 | util.toNumber = function (value) { 205 | if (typeof value !== 'string') { 206 | return value; 207 | } else { 208 | var parsed = Number(value); 209 | return isNaN(parsed) ? value : parsed; 210 | } 211 | }; 212 | 213 | util.convertRangeToArray = function (range) { 214 | return _toConsumableArray(Array(range + 1).keys()).slice(1); 215 | }; 216 | 217 | util.convertArray = function (value) { 218 | if (util.isArray(value)) { 219 | return value; 220 | } else if (util.isPlainObject(value)) { 221 | // convert plain object to array. 222 | var keys = Object.keys(value); 223 | var i = keys.length; 224 | var res = new Array(i); 225 | var key; 226 | 227 | while (i--) { 228 | key = keys[i]; 229 | res[i] = { 230 | $key: key, 231 | $value: value[key] 232 | }; 233 | } 234 | 235 | return res; 236 | } else { 237 | return value || []; 238 | } 239 | }; 240 | 241 | function multiIndex(obj, is) { 242 | // obj,['1','2','3'] -> ((obj['1'])['2'])['3'] 243 | return is.length ? multiIndex(obj[is[0]], is.slice(1)) : obj; 244 | } 245 | 246 | util.getPath = function (obj, is) { 247 | // obj,'1.2.3' -> multiIndex(obj,['1','2','3']) 248 | return multiIndex(obj, is.split('.')); 249 | }; 250 | /** 251 | * Strict object type check. Only returns true 252 | * for plain JavaScript objects. 253 | * 254 | * @param {*} obj 255 | * @return {Boolean} 256 | */ 257 | 258 | 259 | var util_toString = Object.prototype.toString; 260 | var OBJECT_STRING = '[object Object]'; 261 | 262 | util.isPlainObject = function (obj) { 263 | return util_toString.call(obj) === OBJECT_STRING; 264 | }; 265 | 266 | util.exist = function (value) { 267 | return value !== null && typeof value !== 'undefined'; 268 | }; 269 | 270 | /* harmony default export */ var src_util = (util); 271 | // CONCATENATED MODULE: ./src/string/capitalize.js 272 | /** 273 | * Converts a string into Capitalize 274 | * 275 | * 'abc' => 'Abc' 276 | * 277 | * @param {Object} options 278 | */ 279 | function capitalize(value, options) { 280 | var globalOptions = this && this.capitalize ? this.capitalize : {}; 281 | options = options || globalOptions; 282 | var onlyFirstLetter = options.onlyFirstLetter != null ? options.onlyFirstLetter : false; 283 | if (!value && value !== 0) return ''; 284 | 285 | if (onlyFirstLetter === true) { 286 | return value.toString().charAt(0).toUpperCase() + value.toString().slice(1); 287 | } else { 288 | value = value.toString().toLowerCase().split(' '); 289 | return value.map(function (item) { 290 | return item.charAt(0).toUpperCase() + item.slice(1); 291 | }).join(' '); 292 | } 293 | } 294 | 295 | /* harmony default export */ var string_capitalize = (capitalize); 296 | // CONCATENATED MODULE: ./src/string/uppercase.js 297 | /** 298 | * Converts a string to UPPERCASE 299 | * 300 | * 'abc' => 'ABC' 301 | */ 302 | function uppercase(value) { 303 | return value || value === 0 ? value.toString().toUpperCase() : ''; 304 | } 305 | 306 | /* harmony default export */ var string_uppercase = (uppercase); 307 | // CONCATENATED MODULE: ./src/string/lowercase.js 308 | /** 309 | * Converts a string to lowercase 310 | * 311 | * 'AbC' => 'abc' 312 | */ 313 | function lowercase(value) { 314 | return value || value === 0 ? value.toString().toLowerCase() : ''; 315 | } 316 | 317 | /* harmony default export */ var string_lowercase = (lowercase); 318 | // CONCATENATED MODULE: ./src/string/placeholder.js 319 | /** 320 | * If the value is missing outputs the placeholder text 321 | * 322 | * '' => {placeholder} 323 | * 'foo' => 'foo' 324 | */ 325 | function placeholder(input, property) { 326 | return input === undefined || input === '' || input === null ? property : input; 327 | } 328 | 329 | /* harmony default export */ var string_placeholder = (placeholder); 330 | // CONCATENATED MODULE: ./src/string/truncate.js 331 | /** 332 | * Truncate at the given || default length 333 | * 334 | * 'lorem ipsum dolor' => 'lorem ipsum dol...' 335 | */ 336 | function truncate(value, length) { 337 | length = length || 15; 338 | if (!value || typeof value !== 'string') return ''; 339 | if (value.length <= length) return value; 340 | return value.substring(0, length) + '...'; 341 | } 342 | 343 | /* harmony default export */ var string_truncate = (truncate); 344 | // CONCATENATED MODULE: ./src/string/repeat.js 345 | /** 346 | * Repeats a given value an x amount of times 347 | * 348 | * @author Bastiaan Jansen 349 | * @param {string | number} value to repeat 350 | * @param {number} amount 351 | * @returns repeated string 352 | */ 353 | var repeat = function repeat(value) { 354 | var amount = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; 355 | return amount ? value.toString().repeat(amount) : ''; 356 | }; 357 | 358 | /* harmony default export */ var string_repeat = (repeat); 359 | // CONCATENATED MODULE: ./src/string/wrap.js 360 | /** 361 | * Wraps a string or number with a string 362 | * 363 | * @author Bastiaan Jansen 364 | * @param {string | number} value to wrap 365 | * @param {string | number} wrap wrap string 366 | * @returns wrapped string 367 | */ 368 | var wrap = function wrap(value, _wrap) { 369 | return [_wrap, value, _wrap].join(""); 370 | }; 371 | 372 | /* harmony default export */ var string_wrap = (wrap); 373 | // CONCATENATED MODULE: ./src/string/reverse.js 374 | /** 375 | * Reverses a string 376 | * 377 | * @author Bastiaan Jansen 378 | * @param {string} value 379 | * @returns reversed string 380 | */ 381 | var reverse = function reverse(value) { 382 | return Array.from(value).reverse().join(""); 383 | }; 384 | 385 | /* harmony default export */ var string_reverse = (reverse); 386 | // CONCATENATED MODULE: ./src/string/index.js 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | // CONCATENATED MODULE: ./src/array/limitBy.js 397 | 398 | /** 399 | * Limit filter for arrays 400 | * 401 | * @param {Number|Array} arr (If Number, decimal expected) 402 | * @param {Number} n 403 | * @param {Number} offset (Decimal expected) 404 | */ 405 | 406 | function limitBy(arr, n, offset) { 407 | arr = src_util.isArray(arr) ? arr : src_util.convertRangeToArray(arr); 408 | offset = offset ? parseInt(offset, 10) : 0; 409 | n = src_util.toNumber(n); 410 | return typeof n === 'number' ? arr.slice(offset, offset + n) : arr; 411 | } 412 | 413 | /* harmony default export */ var array_limitBy = (limitBy); 414 | // CONCATENATED MODULE: ./src/array/filterBy.js 415 | 416 | /** 417 | * Filter filter for arrays 418 | * 419 | * @param {Array} arr 420 | * @param {String} prop 421 | * @param {String|Number} search 422 | */ 423 | 424 | function filterBy(arr, search) { 425 | var arr = src_util.convertArray(arr); 426 | 427 | if (search == null) { 428 | return arr; 429 | } 430 | 431 | if (typeof search === 'function') { 432 | return arr.filter(search); 433 | } // cast to lowercase string 434 | 435 | 436 | search = ('' + search).toLowerCase(); 437 | var n = 2; // extract and flatten keys 438 | 439 | var keys = Array.prototype.concat.apply([], src_util.toArray(arguments, n)); 440 | var res = []; 441 | var item, key, val, j; 442 | 443 | for (var i = 0, l = arr.length; i < l; i++) { 444 | item = arr[i]; 445 | val = item && item.$value || item; 446 | j = keys.length; 447 | 448 | if (j) { 449 | while (j--) { 450 | key = keys[j]; 451 | 452 | if (key === '$key' && contains(item.$key, search) || contains(src_util.getPath(val, key), search)) { 453 | res.push(item); 454 | break; 455 | } 456 | } 457 | } else if (contains(item, search)) { 458 | res.push(item); 459 | } 460 | } 461 | 462 | return res; 463 | } 464 | 465 | function contains(val, search) { 466 | var i; 467 | 468 | if (src_util.isPlainObject(val)) { 469 | var keys = Object.keys(val); 470 | i = keys.length; 471 | 472 | while (i--) { 473 | if (contains(val[keys[i]], search)) { 474 | return true; 475 | } 476 | } 477 | } else if (src_util.isArray(val)) { 478 | i = val.length; 479 | 480 | while (i--) { 481 | if (contains(val[i], search)) { 482 | return true; 483 | } 484 | } 485 | } else if (val != null) { 486 | return val.toString().toLowerCase().indexOf(search) > -1; 487 | } 488 | } 489 | 490 | /* harmony default export */ var array_filterBy = (filterBy); 491 | // CONCATENATED MODULE: ./src/array/orderBy.js 492 | 493 | /** 494 | * Filter filter for arrays 495 | * 496 | * @param {String|Array|Function} ...sortKeys 497 | * @param {Number} [order] 498 | */ 499 | 500 | function orderBy(arr) { 501 | var _comparator = null; 502 | var sortKeys; 503 | arr = src_util.convertArray(arr); // determine order (last argument) 504 | 505 | var args = src_util.toArray(arguments, 1); 506 | var order = args[args.length - 1]; 507 | 508 | if (typeof order === 'number') { 509 | order = order < 0 ? -1 : 1; 510 | args = args.length > 1 ? args.slice(0, -1) : args; 511 | } else { 512 | order = 1; 513 | } // determine sortKeys & comparator 514 | 515 | 516 | var firstArg = args[0]; 517 | 518 | if (!firstArg) { 519 | return arr; 520 | } else if (typeof firstArg === 'function') { 521 | // custom comparator 522 | _comparator = function comparator(a, b) { 523 | return firstArg(a, b) * order; 524 | }; 525 | } else { 526 | // string keys. flatten first 527 | sortKeys = Array.prototype.concat.apply([], args); 528 | 529 | _comparator = function comparator(a, b, i) { 530 | i = i || 0; 531 | return i >= sortKeys.length - 1 ? baseCompare(a, b, i) : baseCompare(a, b, i) || _comparator(a, b, i + 1); 532 | }; 533 | } 534 | 535 | function baseCompare(a, b, sortKeyIndex) { 536 | var sortKey = sortKeys[sortKeyIndex]; 537 | 538 | if (sortKey) { 539 | if (sortKey !== '$key') { 540 | if (src_util.isObject(a) && '$value' in a) a = a.$value; 541 | if (src_util.isObject(b) && '$value' in b) b = b.$value; 542 | } 543 | 544 | a = src_util.isObject(a) ? src_util.getPath(a, sortKey) : a; 545 | b = src_util.isObject(b) ? src_util.getPath(b, sortKey) : b; 546 | a = typeof a === 'string' ? a.toLowerCase() : a; 547 | b = typeof b === 'string' ? b.toLowerCase() : b; 548 | } 549 | 550 | return a === b ? 0 : a > b ? order : -order; 551 | } // sort on a copy to avoid mutating original array 552 | 553 | 554 | return arr.slice().sort(_comparator); 555 | } 556 | 557 | /* harmony default export */ var array_orderBy = (orderBy); 558 | // CONCATENATED MODULE: ./src/array/find.js 559 | 560 | /** 561 | * Get first matching element from a filtered array 562 | * 563 | * @param {Array} arr 564 | * @param {String|Number} search 565 | * @returns {mixed} 566 | */ 567 | 568 | function find(arr, search) { 569 | var array = array_filterBy.apply(this, arguments); 570 | array.splice(1); 571 | return array; 572 | } 573 | 574 | /* harmony default export */ var array_find = (find); 575 | // CONCATENATED MODULE: ./src/array/index.js 576 | 577 | 578 | 579 | 580 | 581 | // CONCATENATED MODULE: ./src/other/currency.js 582 | 583 | /** 584 | * 585 | * 12345 => $12,345.00 586 | * 587 | * @param {String} symbol 588 | * @param {Number} decimals Decimal places 589 | * @param {Object} options 590 | */ 591 | 592 | function currency(value, symbol, decimals, options) { 593 | var globalOptions = this && this.currency ? this.currency : {}; 594 | symbol = src_util.exist(symbol) ? symbol : globalOptions.symbol; 595 | decimals = src_util.exist(decimals) ? decimals : globalOptions.decimalDigits; 596 | options = options || globalOptions; 597 | var thousandsSeparator, symbolOnLeft, spaceBetweenAmountAndSymbol, showPlusSign; 598 | var digitsRE = /(\d{3})(?=\d)/g; 599 | value = parseFloat(value); 600 | if (!isFinite(value) || !value && value !== 0) return ''; 601 | symbol = typeof symbol !== 'undefined' ? symbol : '$'; 602 | decimals = typeof decimals !== 'undefined' ? decimals : 2; 603 | thousandsSeparator = options.thousandsSeparator != null ? options.thousandsSeparator : ','; 604 | symbolOnLeft = options.symbolOnLeft != null ? options.symbolOnLeft : true; 605 | spaceBetweenAmountAndSymbol = options.spaceBetweenAmountAndSymbol != null ? options.spaceBetweenAmountAndSymbol : false; 606 | showPlusSign = options.showPlusSign != null ? options.showPlusSign : false; 607 | var number = Math.abs(value); 608 | var stringified = toFixed(number, decimals); 609 | stringified = options.decimalSeparator ? stringified.replace('.', options.decimalSeparator) : stringified; 610 | 611 | var _int = decimals ? stringified.slice(0, -1 - decimals) : stringified; 612 | 613 | var i = _int.length % 3; 614 | var head = i > 0 ? _int.slice(0, i) + (_int.length > 3 ? thousandsSeparator : '') : ''; 615 | 616 | var _float = decimals ? stringified.slice(-1 - decimals) : ''; 617 | 618 | symbol = spaceBetweenAmountAndSymbol ? symbolOnLeft ? symbol + ' ' : ' ' + symbol : symbol; 619 | symbol = symbolOnLeft ? symbol + head + _int.slice(i).replace(digitsRE, '$1' + thousandsSeparator) + _float : head + _int.slice(i).replace(digitsRE, '$1' + thousandsSeparator) + _float + symbol; 620 | var sign = value < 0 ? '-' : ''; 621 | var plusSign = value > 0 && showPlusSign ? '+' : ''; 622 | return plusSign + sign + symbol; 623 | } 624 | 625 | function toFixed(num, precision) { 626 | return (+(Math.round(+(num + 'e' + precision)) + 'e' + -precision)).toFixed(precision); 627 | } 628 | 629 | /* harmony default export */ var other_currency = (currency); 630 | // CONCATENATED MODULE: ./src/other/bytes.js 631 | 632 | /** 633 | * 1 => '8 byte' 634 | * 8 => '8 bytes' 635 | * 1024 => '1.00 kB' 636 | * 2000000 => '1.90 MB' 637 | * 2000000000 => '1.86 GB' 638 | * 2000000000000 => '1.82 TB' 639 | * 640 | * @param {Number} value 641 | * @param {Number} decimals Decimal places (default: 2) 642 | */ 643 | 644 | function bytes(value, decimals) { 645 | var globalOptions = this && this.bytes ? this.bytes : {}; 646 | decimals = src_util.exist(decimals) ? decimals : globalOptions.decimalDigits; 647 | decimals = typeof decimals !== 'undefined' ? decimals : 2; 648 | value = value === null || isNaN(value) ? 0 : value; 649 | 650 | if (value >= Math.pow(1024, 4)) { 651 | // TB 652 | return "".concat((value / Math.pow(1024, 4)).toFixed(decimals), " TB"); 653 | } else if (value >= Math.pow(1024, 3)) { 654 | // GB 655 | return "".concat((value / Math.pow(1024, 3)).toFixed(decimals), " GB"); 656 | } else if (value >= Math.pow(1024, 2)) { 657 | // MB 658 | return "".concat((value / Math.pow(1024, 2)).toFixed(decimals), " MB"); 659 | } else if (value >= 1024) { 660 | // kb 661 | return "".concat((value / 1024).toFixed(decimals), " kB"); 662 | } // byte 663 | 664 | 665 | return value === 1 ? "".concat(value, " byte") : "".concat(value, " bytes"); 666 | } 667 | 668 | /* harmony default export */ var other_bytes = (bytes); 669 | // CONCATENATED MODULE: ./src/other/pluralize.js 670 | 671 | /** 672 | * 'item' => 'items' 673 | * 674 | * @param {String|Array} word 675 | * @param {Object} options 676 | * 677 | */ 678 | 679 | function pluralize(value, word, options) { 680 | var globalOptions = this && this.pluralize ? this.pluralize : {}; 681 | options = options || globalOptions; 682 | var output = ''; 683 | var includeNumber = options.includeNumber != null ? options.includeNumber : false; 684 | if (includeNumber === true) output += value + ' '; 685 | if (!value && value !== 0 || !word) return output; 686 | 687 | if (Array.isArray(word)) { 688 | output += word[value - 1] || word[word.length - 1]; 689 | } else { 690 | output += word + (value === 1 ? '' : 's'); 691 | } 692 | 693 | return output; 694 | } 695 | 696 | /* harmony default export */ var other_pluralize = (pluralize); 697 | // CONCATENATED MODULE: ./src/other/ordinal.js 698 | 699 | /** 700 | * 42 => 'nd' 701 | * 702 | * @params {Object} options 703 | * 704 | */ 705 | 706 | function ordinal(value, options) { 707 | var globalOptions = this && this.ordinal ? this.ordinal : {}; 708 | options = options || globalOptions; 709 | var output = ''; 710 | var includeNumber = options.includeNumber != null ? options.includeNumber : false; 711 | if (includeNumber === true) output += value; 712 | var j = value % 10, 713 | k = value % 100; 714 | if (j == 1 && k != 11) output += 'st';else if (j == 2 && k != 12) output += 'nd';else if (j == 3 && k != 13) output += 'rd';else output += 'th'; 715 | return output; 716 | } 717 | 718 | /* harmony default export */ var other_ordinal = (ordinal); 719 | // CONCATENATED MODULE: ./src/other/number.js 720 | 721 | /** 722 | * 123456 => '123,456' 723 | * 724 | * @params {Object} options 725 | * 726 | */ 727 | 728 | function number_number(value, format, options) { 729 | var globalOptions = this && this.number ? this.number : {}; 730 | format = src_util.exist(format) ? format : globalOptions.format; 731 | options = options || globalOptions; 732 | var config = parseFormat(format); 733 | var number = parseNumber(value); 734 | var thousandsSeparator = options.thousandsSeparator != null ? options.thousandsSeparator : ','; 735 | var decimalSeparator = options.decimalSeparator != null ? options.decimalSeparator : '.'; 736 | config.sign = config.sign || number.sign; 737 | 738 | if (config.unit) { 739 | var numberWithUnit = addUnit(number.float, config); 740 | return config.sign + numberWithUnit; 741 | } 742 | 743 | var rounded = number_toFixed(number.float, config.decimals); 744 | var output = addSeparators(rounded, config.base, thousandsSeparator, decimalSeparator); 745 | return config.sign + output; 746 | } 747 | 748 | Math.sign = function (x) { 749 | x = +x; 750 | 751 | if (x === 0 || isNaN(x)) { 752 | return x; 753 | } 754 | 755 | return x > 0 ? 1 : -1; 756 | }; 757 | 758 | function parseNumber(num) { 759 | return { 760 | float: Math.abs(parseFloat(num)), 761 | int: Math.abs(parseInt(num)), 762 | sign: Math.sign(num) < 0 ? '-' : '' 763 | }; 764 | } 765 | 766 | function parseFormat() { 767 | var string = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '0'; 768 | var regex = /([\+\-])?([0-9\,]+)?([\.0-9]+)?([a\s]+)?/; 769 | var matches = string ? string.match(regex) : ['', '', '', '', '']; 770 | var float = matches[3]; 771 | var decimals = float ? float.match(/0/g).length : 0; 772 | return { 773 | sign: matches[1] || '', 774 | base: matches[2] || '', 775 | decimals: decimals, 776 | unit: matches[4] || '' 777 | }; 778 | } 779 | 780 | function addUnit(num, config) { 781 | var rx = /\.0+$|(\.[0-9]*[1-9])0+$/; 782 | var si = [{ 783 | value: 1, 784 | symbol: '' 785 | }, { 786 | value: 1e3, 787 | symbol: 'K' 788 | }, { 789 | value: 1e6, 790 | symbol: 'M' 791 | }, { 792 | value: 1e9, 793 | symbol: 'B' 794 | }, { 795 | value: 1e12, 796 | symbol: 'T' 797 | }]; 798 | var i; 799 | 800 | for (i = si.length - 1; i > 0; i--) { 801 | if (num >= si[i].value) { 802 | break; 803 | } 804 | } 805 | 806 | num = (num / si[i].value).toFixed(config.decimals).replace(rx, '$1'); 807 | return num + config.unit.replace('a', si[i].symbol); 808 | } 809 | 810 | function addSeparators(num, base, thousandsSeparator, decimalSeparator) { 811 | var regex = /(\d+)(\d{3})/; 812 | var string = num.toString(); 813 | var x = string.split('.'); 814 | var x1 = x[0]; 815 | var x2 = x.length > 1 ? decimalSeparator + x[1] : ''; 816 | 817 | switch (base) { 818 | case '': 819 | x1 = ''; 820 | break; 821 | 822 | case '0,0': 823 | while (regex.test(x1)) { 824 | x1 = x1.replace(regex, '$1' + thousandsSeparator + '$2'); 825 | } 826 | 827 | break; 828 | } 829 | 830 | return x1 + x2; 831 | } 832 | 833 | function getFraction(num, decimals, separator) { 834 | var fraction = number_toFixed(num, decimals).toString().split('.')[1]; 835 | return fraction ? separator + fraction : ''; 836 | } 837 | 838 | function number_toFixed(num, precision) { 839 | return (+(Math.round(+(num + 'e' + precision)) + 'e' + -precision)).toFixed(precision); 840 | } 841 | 842 | /* harmony default export */ var other_number = (number_number); 843 | // CONCATENATED MODULE: ./src/other/percent.js 844 | 845 | /** 846 | * 1.2 => '120%' 847 | * -0.2 => '-20%' 848 | * 100 => '10000%' 849 | * 1 => '100%' 850 | * 0.97 => '97%' 851 | * 852 | * @param {Number} value 853 | * @param {Number} decimals Decimal places (default: 2) 854 | * @param {Number} multiplier (default: 100) 855 | * @params {Object} options 856 | */ 857 | 858 | function percent(value, decimals, multiplier, options) { 859 | var globalOptions = this && this.percent ? this.percent : {}; 860 | options = options || globalOptions; 861 | multiplier = src_util.exist(multiplier) ? multiplier : globalOptions.multiplier; 862 | multiplier = typeof multiplier !== 'undefined' ? multiplier : 100; 863 | decimals = src_util.exist(decimals) ? decimals : globalOptions.decimalDigits; 864 | decimals = typeof decimals !== 'undefined' ? decimals : 0; 865 | var decimalSeparator = options.decimalSeparator != null ? options.decimalSeparator : '.'; 866 | value = value === null || isNaN(value) ? 0 : value; 867 | return "".concat((value * multiplier).toFixed(decimals).replace('.', decimalSeparator), "%"); 868 | } 869 | 870 | /* harmony default export */ var other_percent = (percent); 871 | // CONCATENATED MODULE: ./src/other/index.js 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | // CONCATENATED MODULE: ./src/index.js 880 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 881 | 882 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 883 | 884 | 885 | 886 | 887 | 888 | var Vue2Filters = { 889 | install: function install(Vue, options) { 890 | src_util.each(string_namespaceObject, function (value, key) { 891 | Vue.filter(key, value.bind(options)); 892 | }); 893 | src_util.each(other_namespaceObject, function (value, key) { 894 | Vue.filter(key, value.bind(options)); 895 | }); 896 | }, 897 | mixin: { 898 | methods: _objectSpread({}, array_namespaceObject) 899 | } 900 | }; 901 | /* harmony default export */ var src = __webpack_exports__["default"] = (Vue2Filters); 902 | 903 | if (typeof window !== 'undefined' && window.Vue) { 904 | window.Vue.use(Vue2Filters); 905 | window.Vue2Filters = Vue2Filters; 906 | } 907 | 908 | /***/ }) 909 | /******/ ]); 910 | }); -------------------------------------------------------------------------------- /dist/vue2-filters.min.js: -------------------------------------------------------------------------------- 1 | !function(t,r){if("object"==typeof exports&&"object"==typeof module)module.exports=r();else if("function"==typeof define&&define.amd)define([],r);else{var e=r();for(var n in e)("object"==typeof exports?exports:t)[n]=e[n]}}("undefined"!=typeof self?self:this,function(){return n={},i.m=e=[function(t,r,e){"use strict";e.r(r);var i={};e.r(i),e.d(i,"capitalize",function(){return y}),e.d(i,"uppercase",function(){return d}),e.d(i,"lowercase",function(){return v}),e.d(i,"placeholder",function(){return h}),e.d(i,"truncate",function(){return g}),e.d(i,"repeat",function(){return m}),e.d(i,"wrap",function(){return S}),e.d(i,"reverse",function(){return j});var n={};e.r(n),e.d(n,"limitBy",function(){return w}),e.d(n,"filterBy",function(){return O}),e.d(n,"orderBy",function(){return x}),e.d(n,"find",function(){return M});var o={};function u(t){return function(t){if(Array.isArray(t)){for(var r=0,e=new Array(t.length);r=i.length-1?u(t,r,e):u(t,r,e)||n(t,r,e+1)}),t.slice().sort(n)};var M=function(t,r){var e=O.apply(this,arguments);return e.splice(1),e};var P=function(t,r,e,n){var i,o,u,a,c=this&&this.currency?this.currency:{};r=b.exist(r)?r:c.symbol,e=b.exist(e)?e:c.decimalDigits,n=n||c;var l=/(\d{3})(?=\d)/g;if(t=parseFloat(t),!isFinite(t)||!t&&0!==t)return"";r=void 0!==r?r:"$",e=void 0!==e?e:2,i=null!=n.thousandsSeparator?n.thousandsSeparator:",",o=null==n.symbolOnLeft||n.symbolOnLeft,u=null!=n.spaceBetweenAmountAndSymbol&&n.spaceBetweenAmountAndSymbol,a=null!=n.showPlusSign&&n.showPlusSign;var s=function(t,r){return(+(Math.round(+(t+"e"+r))+"e"+-r)).toFixed(r)}(Math.abs(t),e);s=n.decimalSeparator?s.replace(".",n.decimalSeparator):s;var f=e?s.slice(0,-1-e):s,p=f.length%3,y=0=Math.pow(1024,4)?"".concat((t/Math.pow(1024,4)).toFixed(r)," TB"):t>=Math.pow(1024,3)?"".concat((t/Math.pow(1024,3)).toFixed(r)," GB"):t>=Math.pow(1024,2)?"".concat((t/Math.pow(1024,2)).toFixed(r)," MB"):1024<=t?"".concat((t/1024).toFixed(r)," kB"):"".concat(t,1===t?" byte":" bytes")};var N=function(t,r,e){var n=this&&this.pluralize?this.pluralize:{},i="";return!0===(null!=(e=e||n).includeNumber&&e.includeNumber)&&(i+=t+" "),!t&&0!==t||!r||(Array.isArray(r)?i+=r[t-1]||r[r.length-1]:i+=r+(1===t?"":"s")),i};var F=function(t,r){var e=this&&this.ordinal?this.ordinal:{},n="";!0===(null!=(r=r||e).includeNumber&&r.includeNumber)&&(n+=t);var i=t%10,o=t%100;return n+=1==i&&11!=o?"st":2==i&&12!=o?"nd":3==i&&13!=o?"rd":"th"};function k(t,r){return(+(Math.round(+(t+"e"+r))+"e"+-r)).toFixed(r)}Math.sign=function(t){return 0===(t=+t)||isNaN(t)?t:0=n[e].value);e--);return(t=(t/n[e].value).toFixed(r.decimals).replace(/\.0+$|(\.[0-9]*[1-9])0+$/,"$1"))+r.unit.replace("a",n[e].symbol)}(o.float,i);return i.sign+c}var l=function(t,r,e,n){var i=/(\d+)(\d{3})/,o=t.toString().split("."),u=o[0],a=1 -1 65 | } 66 | } 67 | 68 | export default filterBy -------------------------------------------------------------------------------- /src/array/find.js: -------------------------------------------------------------------------------- 1 | import filterBy from './filterBy' 2 | 3 | /** 4 | * Get first matching element from a filtered array 5 | * 6 | * @param {Array} arr 7 | * @param {String|Number} search 8 | * @returns {mixed} 9 | */ 10 | function find(arr, search) 11 | { 12 | var array = filterBy.apply(this, arguments); 13 | array.splice(1); 14 | return array; 15 | } 16 | 17 | export default find; 18 | -------------------------------------------------------------------------------- /src/array/index.js: -------------------------------------------------------------------------------- 1 | import limitBy from "./limitBy"; 2 | import filterBy from "./filterBy"; 3 | import orderBy from "./orderBy"; 4 | import find from "./find"; 5 | 6 | export { limitBy, filterBy, orderBy, find }; 7 | -------------------------------------------------------------------------------- /src/array/limitBy.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * Limit filter for arrays 5 | * 6 | * @param {Number|Array} arr (If Number, decimal expected) 7 | * @param {Number} n 8 | * @param {Number} offset (Decimal expected) 9 | */ 10 | 11 | function limitBy (arr, n, offset) { 12 | arr = (util.isArray(arr)) ? arr : util.convertRangeToArray(arr) 13 | 14 | offset = offset ? parseInt(offset, 10) : 0 15 | n = util.toNumber(n) 16 | return typeof n === 'number' 17 | ? arr.slice(offset, offset + n) 18 | : arr 19 | } 20 | 21 | export default limitBy -------------------------------------------------------------------------------- /src/array/orderBy.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * Filter filter for arrays 5 | * 6 | * @param {String|Array|Function} ...sortKeys 7 | * @param {Number} [order] 8 | */ 9 | 10 | function orderBy (arr) { 11 | var comparator = null 12 | var sortKeys 13 | arr = util.convertArray(arr) 14 | 15 | // determine order (last argument) 16 | var args = util.toArray(arguments, 1) 17 | var order = args[args.length - 1] 18 | if (typeof order === 'number') { 19 | order = order < 0 ? -1 : 1 20 | args = args.length > 1 ? args.slice(0, -1) : args 21 | } else { 22 | order = 1 23 | } 24 | 25 | // determine sortKeys & comparator 26 | var firstArg = args[0] 27 | if (!firstArg) { 28 | return arr 29 | } else if (typeof firstArg === 'function') { 30 | // custom comparator 31 | comparator = function (a, b) { 32 | return firstArg(a, b) * order 33 | } 34 | } else { 35 | // string keys. flatten first 36 | sortKeys = Array.prototype.concat.apply([], args) 37 | comparator = function (a, b, i) { 38 | i = i || 0 39 | return i >= sortKeys.length - 1 40 | ? baseCompare(a, b, i) 41 | : baseCompare(a, b, i) || comparator(a, b, i + 1) 42 | } 43 | } 44 | 45 | function baseCompare (a, b, sortKeyIndex) { 46 | var sortKey = sortKeys[sortKeyIndex] 47 | if (sortKey) { 48 | if (sortKey !== '$key') { 49 | if (util.isObject(a) && '$value' in a) a = a.$value 50 | if (util.isObject(b) && '$value' in b) b = b.$value 51 | } 52 | a = util.isObject(a) ? util.getPath(a, sortKey) : a 53 | b = util.isObject(b) ? util.getPath(b, sortKey) : b 54 | a = (typeof a === 'string') ? a.toLowerCase() : a 55 | b = (typeof b === 'string') ? b.toLowerCase() : b 56 | } 57 | return a === b ? 0 : a > b ? order : -order 58 | } 59 | 60 | // sort on a copy to avoid mutating original array 61 | return arr.slice().sort(comparator) 62 | } 63 | 64 | export default orderBy -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import util from './util/index' 2 | import * as stringFilters from './string/index' 3 | import * as arrayFilters from './array/index' 4 | import * as otherFilters from './other/index' 5 | 6 | var Vue2Filters = { 7 | install: function(Vue, options) { 8 | util.each(stringFilters, function(value, key) { 9 | Vue.filter(key, value.bind(options)) 10 | }) 11 | 12 | util.each(otherFilters, function(value, key) { 13 | Vue.filter(key, value.bind(options)) 14 | }) 15 | }, 16 | mixin: { 17 | methods: { ...arrayFilters } 18 | } 19 | } 20 | 21 | export default Vue2Filters; 22 | 23 | if (typeof window !== 'undefined' && window.Vue) { 24 | window.Vue.use(Vue2Filters); 25 | window.Vue2Filters = Vue2Filters; 26 | } 27 | -------------------------------------------------------------------------------- /src/other/bytes.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 1 => '8 byte' 5 | * 8 => '8 bytes' 6 | * 1024 => '1.00 kB' 7 | * 2000000 => '1.90 MB' 8 | * 2000000000 => '1.86 GB' 9 | * 2000000000000 => '1.82 TB' 10 | * 11 | * @param {Number} value 12 | * @param {Number} decimals Decimal places (default: 2) 13 | */ 14 | function bytes(value, decimals) { 15 | const globalOptions = (this && this.bytes) ? this.bytes : {} 16 | decimals = util.exist(decimals) ? decimals : globalOptions.decimalDigits 17 | decimals = (typeof decimals !== 'undefined') ? decimals : 2 18 | value = value === null || isNaN(value) ? 0 : value 19 | 20 | if (value >= Math.pow(1024, 4)) { 21 | // TB 22 | return `${(value / Math.pow(1024, 4)).toFixed(decimals)} TB` 23 | } else if (value >= Math.pow(1024, 3)) { 24 | // GB 25 | return `${(value / Math.pow(1024, 3)).toFixed(decimals)} GB` 26 | } else if (value >= Math.pow(1024, 2)) { 27 | // MB 28 | return `${(value / Math.pow(1024, 2)).toFixed(decimals)} MB` 29 | } else if (value >= 1024) { 30 | // kb 31 | return `${(value / 1024).toFixed(decimals)} kB` 32 | } 33 | // byte 34 | return value === 1 ? `${value} byte` : `${value} bytes` 35 | } 36 | 37 | export default bytes -------------------------------------------------------------------------------- /src/other/currency.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 5 | * 12345 => $12,345.00 6 | * 7 | * @param {String} symbol 8 | * @param {Number} decimals Decimal places 9 | * @param {Object} options 10 | */ 11 | 12 | function currency (value, symbol, decimals, options) { 13 | const globalOptions = (this && this.currency) ? this.currency : {} 14 | symbol = util.exist(symbol) ? symbol : globalOptions.symbol 15 | decimals = util.exist(decimals) ? decimals : globalOptions.decimalDigits 16 | options = options || globalOptions 17 | var thousandsSeparator, symbolOnLeft, spaceBetweenAmountAndSymbol, showPlusSign 18 | var digitsRE = /(\d{3})(?=\d)/g 19 | value = parseFloat(value) 20 | if (!isFinite(value) || (!value && value !== 0)) return '' 21 | symbol = (typeof symbol !== 'undefined') ? symbol : '$' 22 | decimals = (typeof decimals !== 'undefined') ? decimals : 2 23 | thousandsSeparator = options.thousandsSeparator != null ? options.thousandsSeparator : ',' 24 | symbolOnLeft = options.symbolOnLeft != null ? options.symbolOnLeft : true 25 | spaceBetweenAmountAndSymbol = options.spaceBetweenAmountAndSymbol != null ? options.spaceBetweenAmountAndSymbol : false 26 | showPlusSign = options.showPlusSign != null ? options.showPlusSign : false 27 | var number = Math.abs(value) 28 | var stringified = toFixed(number, decimals) 29 | stringified = options.decimalSeparator 30 | ? stringified.replace('.', options.decimalSeparator) 31 | : stringified 32 | var _int = decimals 33 | ? stringified.slice(0, -1 - decimals) 34 | : stringified 35 | var i = _int.length % 3 36 | var head = i > 0 37 | ? (_int.slice(0, i) + (_int.length > 3 ? thousandsSeparator : '')) 38 | : '' 39 | var _float = decimals 40 | ? stringified.slice(-1 - decimals) 41 | : '' 42 | symbol = spaceBetweenAmountAndSymbol 43 | ? (symbolOnLeft ? symbol + ' ' : ' ' + symbol) 44 | : symbol 45 | symbol = symbolOnLeft 46 | ? symbol + head + 47 | _int.slice(i).replace(digitsRE, '$1' + thousandsSeparator) + _float 48 | : head + 49 | _int.slice(i).replace(digitsRE, '$1' + thousandsSeparator) + _float + symbol 50 | var sign = value < 0 ? '-' : '' 51 | var plusSign = (value > 0 && showPlusSign) ? '+' : '' 52 | return plusSign + sign + symbol 53 | } 54 | 55 | function toFixed(num, precision) { 56 | return (+(Math.round(+(num + 'e' + precision)) + 'e' + -precision)).toFixed(precision); 57 | } 58 | 59 | export default currency -------------------------------------------------------------------------------- /src/other/index.js: -------------------------------------------------------------------------------- 1 | import currency from './currency' 2 | import bytes from './bytes' 3 | import pluralize from './pluralize' 4 | import ordinal from './ordinal' 5 | import number from './number' 6 | import percent from './percent' 7 | 8 | export { 9 | currency, 10 | bytes, 11 | pluralize, 12 | ordinal, 13 | number, 14 | percent 15 | } 16 | -------------------------------------------------------------------------------- /src/other/number.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 123456 => '123,456' 5 | * 6 | * @params {Object} options 7 | * 8 | */ 9 | 10 | function number(value, format, options) { 11 | const globalOptions = this && this.number ? this.number : {} 12 | format = util.exist(format) ? format : globalOptions.format 13 | options = options || globalOptions 14 | const config = parseFormat(format) 15 | const number = parseNumber(value) 16 | const thousandsSeparator = options.thousandsSeparator != null ? options.thousandsSeparator : ',' 17 | const decimalSeparator = options.decimalSeparator != null ? options.decimalSeparator : '.' 18 | 19 | config.sign = config.sign || number.sign 20 | 21 | if (config.unit) { 22 | const numberWithUnit = addUnit(number.float, config) 23 | return config.sign + numberWithUnit 24 | } 25 | 26 | const rounded = toFixed(number.float, config.decimals) 27 | 28 | const output = addSeparators(rounded, config.base, thousandsSeparator, decimalSeparator) 29 | 30 | return config.sign + output 31 | } 32 | 33 | Math.sign = function (x) { 34 | x = +x 35 | if (x === 0 || isNaN(x)) { 36 | return x 37 | } 38 | return x > 0 ? 1 : -1 39 | } 40 | 41 | function parseNumber(num) { 42 | return { 43 | float: Math.abs(parseFloat(num)), 44 | int: Math.abs(parseInt(num)), 45 | sign: Math.sign(num) < 0 ? '-' : '' 46 | } 47 | } 48 | 49 | function parseFormat(string = '0') { 50 | const regex = /([\+\-])?([0-9\,]+)?([\.0-9]+)?([a\s]+)?/ 51 | const matches = string ? string.match(regex) : ['', '', '', '', ''] 52 | const float = matches[3] 53 | const decimals = float ? float.match(/0/g).length : 0 54 | 55 | return { 56 | sign: matches[1] || '', 57 | base: matches[2] || '', 58 | decimals, 59 | unit: matches[4] || '' 60 | } 61 | } 62 | 63 | function addUnit(num, config) { 64 | const rx = /\.0+$|(\.[0-9]*[1-9])0+$/ 65 | const si = [ 66 | { value: 1, symbol: '' }, 67 | { value: 1e3, symbol: 'K' }, 68 | { value: 1e6, symbol: 'M' }, 69 | { value: 1e9, symbol: 'B' }, 70 | { value: 1e12, symbol: 'T' } 71 | ] 72 | 73 | let i 74 | for (i = si.length - 1; i > 0; i--) { 75 | if (num >= si[i].value) { 76 | break 77 | } 78 | } 79 | 80 | num = (num / si[i].value).toFixed(config.decimals).replace(rx, '$1') 81 | 82 | return num + config.unit.replace('a', si[i].symbol) 83 | } 84 | 85 | function addSeparators(num, base, thousandsSeparator, decimalSeparator) { 86 | const regex = /(\d+)(\d{3})/ 87 | const string = num.toString() 88 | const x = string.split('.') 89 | let x1 = x[0] 90 | let x2 = x.length > 1 ? decimalSeparator + x[1] : '' 91 | 92 | switch (base) { 93 | case '': 94 | x1 = '' 95 | break 96 | case '0,0': 97 | while (regex.test(x1)) { 98 | x1 = x1.replace(regex, '$1' + thousandsSeparator + '$2') 99 | } 100 | break 101 | } 102 | 103 | return x1 + x2 104 | } 105 | 106 | function getFraction(num, decimals, separator) { 107 | const fraction = toFixed(num, decimals).toString().split('.')[1] 108 | 109 | return fraction ? separator + fraction : '' 110 | } 111 | 112 | function toFixed(num, precision) { 113 | return (+(Math.round(+(num + 'e' + precision)) + 'e' + -precision)).toFixed(precision) 114 | } 115 | 116 | export default number 117 | -------------------------------------------------------------------------------- /src/other/ordinal.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 42 => 'nd' 5 | * 6 | * @params {Object} options 7 | * 8 | */ 9 | 10 | function ordinal (value, options) { 11 | const globalOptions = (this && this.ordinal) ? this.ordinal : {} 12 | options = options || globalOptions 13 | var output = '' 14 | var includeNumber = options.includeNumber != null ? options.includeNumber : false 15 | if(includeNumber === true) output += value 16 | var j = value % 10, 17 | k = value % 100 18 | 19 | if (j == 1 && k != 11) output += 'st' 20 | else if (j == 2 && k != 12) output += 'nd' 21 | else if (j == 3 && k != 13) output += 'rd' 22 | else output += 'th' 23 | 24 | return output 25 | } 26 | 27 | export default ordinal -------------------------------------------------------------------------------- /src/other/percent.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 1.2 => '120%' 5 | * -0.2 => '-20%' 6 | * 100 => '10000%' 7 | * 1 => '100%' 8 | * 0.97 => '97%' 9 | * 10 | * @param {Number} value 11 | * @param {Number} decimals Decimal places (default: 2) 12 | * @param {Number} multiplier (default: 100) 13 | * @params {Object} options 14 | */ 15 | function percent(value, decimals, multiplier, options) { 16 | const globalOptions = this && this.percent ? this.percent : {} 17 | options = options || globalOptions 18 | multiplier = util.exist(multiplier) ? multiplier : globalOptions.multiplier 19 | multiplier = typeof multiplier !== 'undefined' ? multiplier : 100 20 | decimals = util.exist(decimals) ? decimals : globalOptions.decimalDigits 21 | decimals = typeof decimals !== 'undefined' ? decimals : 0 22 | 23 | const decimalSeparator = options.decimalSeparator != null ? options.decimalSeparator : '.' 24 | 25 | value = value === null || isNaN(value) ? 0 : value 26 | 27 | return `${(value * multiplier).toFixed(decimals).replace('.', decimalSeparator)}%` 28 | } 29 | 30 | export default percent 31 | -------------------------------------------------------------------------------- /src/other/pluralize.js: -------------------------------------------------------------------------------- 1 | import util from '../util/index' 2 | 3 | /** 4 | * 'item' => 'items' 5 | * 6 | * @param {String|Array} word 7 | * @param {Object} options 8 | * 9 | */ 10 | 11 | function pluralize (value, word, options) { 12 | const globalOptions = (this && this.pluralize) ? this.pluralize : {} 13 | options = options || globalOptions 14 | var output = '' 15 | var includeNumber = options.includeNumber != null ? options.includeNumber : false 16 | if(includeNumber === true) output += value + ' ' 17 | if(!value && value !== 0 || !word) return output 18 | if(Array.isArray(word)) { 19 | output += word[value - 1] || word[word.length - 1] 20 | } else { 21 | output += word + (value === 1 ? '' : 's') 22 | } 23 | 24 | return output 25 | } 26 | 27 | export default pluralize -------------------------------------------------------------------------------- /src/string/capitalize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a string into Capitalize 3 | * 4 | * 'abc' => 'Abc' 5 | * 6 | * @param {Object} options 7 | */ 8 | 9 | function capitalize (value, options) { 10 | const globalOptions = (this && this.capitalize) ? this.capitalize : {} 11 | options = options || globalOptions 12 | var onlyFirstLetter = options.onlyFirstLetter != null ? options.onlyFirstLetter : false 13 | if (!value && value !== 0) return '' 14 | if(onlyFirstLetter === true) { 15 | return value.toString().charAt(0).toUpperCase() + value.toString().slice(1) 16 | } else { 17 | value = value.toString().toLowerCase().split(' ') 18 | return value.map(function(item) { 19 | return item.charAt(0).toUpperCase() + item.slice(1) 20 | }).join(' ') 21 | } 22 | } 23 | 24 | export default capitalize 25 | -------------------------------------------------------------------------------- /src/string/index.js: -------------------------------------------------------------------------------- 1 | import capitalize from "./capitalize"; 2 | import uppercase from "./uppercase"; 3 | import lowercase from "./lowercase"; 4 | import placeholder from "./placeholder"; 5 | import truncate from "./truncate"; 6 | import repeat from "./repeat"; 7 | import wrap from "./wrap"; 8 | import reverse from "./reverse"; 9 | 10 | export { 11 | capitalize, 12 | uppercase, 13 | lowercase, 14 | placeholder, 15 | truncate, 16 | repeat, 17 | wrap, 18 | reverse, 19 | }; 20 | -------------------------------------------------------------------------------- /src/string/lowercase.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a string to lowercase 3 | * 4 | * 'AbC' => 'abc' 5 | */ 6 | 7 | function lowercase (value) { 8 | return (value || value === 0) 9 | ? value.toString().toLowerCase() 10 | : '' 11 | } 12 | 13 | export default lowercase -------------------------------------------------------------------------------- /src/string/placeholder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * If the value is missing outputs the placeholder text 3 | * 4 | * '' => {placeholder} 5 | * 'foo' => 'foo' 6 | */ 7 | 8 | function placeholder (input, property) { 9 | return ( input === undefined || input === '' || input === null ) ? property : input; 10 | } 11 | 12 | export default placeholder 13 | -------------------------------------------------------------------------------- /src/string/repeat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a given value an x amount of times 3 | * 4 | * @author Bastiaan Jansen 5 | * @param {string | number} value to repeat 6 | * @param {number} amount 7 | * @returns repeated string 8 | */ 9 | const repeat = (value, amount = 1) => { 10 | return amount ? value.toString().repeat(amount) : ''; 11 | }; 12 | 13 | export default repeat; 14 | -------------------------------------------------------------------------------- /src/string/reverse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Reverses a string 3 | * 4 | * @author Bastiaan Jansen 5 | * @param {string} value 6 | * @returns reversed string 7 | */ 8 | const reverse = (value) => { 9 | return Array.from(value).reverse().join(""); 10 | }; 11 | 12 | export default reverse; 13 | -------------------------------------------------------------------------------- /src/string/truncate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Truncate at the given || default length 3 | * 4 | * 'lorem ipsum dolor' => 'lorem ipsum dol...' 5 | */ 6 | 7 | function truncate (value, length) { 8 | length = length || 15 9 | if( !value || typeof value !== 'string' ) return '' 10 | if( value.length <= length) return value 11 | return value.substring(0, length) + '...' 12 | } 13 | 14 | export default truncate 15 | -------------------------------------------------------------------------------- /src/string/uppercase.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Converts a string to UPPERCASE 3 | * 4 | * 'abc' => 'ABC' 5 | */ 6 | 7 | function uppercase (value) { 8 | return (value || value === 0) 9 | ? value.toString().toUpperCase() 10 | : '' 11 | } 12 | 13 | export default uppercase -------------------------------------------------------------------------------- /src/string/wrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wraps a string or number with a string 3 | * 4 | * @author Bastiaan Jansen 5 | * @param {string | number} value to wrap 6 | * @param {string | number} wrap wrap string 7 | * @returns wrapped string 8 | */ 9 | const wrap = (value, wrap) => { 10 | return [wrap, value, wrap].join(""); 11 | }; 12 | 13 | export default wrap; 14 | -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | var 2 | ArrayProto = Array.prototype, 3 | ObjProto = Object.prototype; 4 | 5 | var 6 | slice = ArrayProto.slice, 7 | toString = ObjProto.toString; 8 | 9 | var util = {}; 10 | 11 | util.isArray = function(obj) { 12 | return Array.isArray(obj); 13 | }; 14 | 15 | var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; 16 | util.isArrayLike = function(obj) { 17 | if(typeof obj !== 'object' || !obj){ 18 | return false; 19 | } 20 | var length = obj.length; 21 | return typeof length === 'number' 22 | && length % 1 === 0 && length >= 0 && length <= MAX_ARRAY_INDEX; 23 | }; 24 | 25 | util.isObject = function(obj) { 26 | var type = typeof obj; 27 | return type === 'function' || type === 'object' && !!obj; 28 | }; 29 | 30 | 31 | util.each = function(obj, callback) { 32 | var i, 33 | len; 34 | if (util.isArray(obj)) { 35 | for (i = 0, len = obj.length; i < len; i++) { 36 | if (callback(obj[i], i, obj) === false) { 37 | break; 38 | } 39 | } 40 | } else { 41 | for (i in obj) { 42 | if (callback(obj[i], i, obj) === false) { 43 | break; 44 | } 45 | } 46 | } 47 | return obj; 48 | }; 49 | 50 | util.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { 51 | util['is' + name] = function(obj) { 52 | return toString.call(obj) === '[object ' + name + ']'; 53 | }; 54 | }); 55 | 56 | util.toArray = function(list, start) { 57 | start = start || 0 58 | var i = list.length - start 59 | var ret = new Array(i) 60 | while (i--) { 61 | ret[i] = list[i + start] 62 | } 63 | return ret 64 | } 65 | 66 | util.toNumber = function(value) { 67 | if (typeof value !== 'string') { 68 | return value 69 | } else { 70 | var parsed = Number(value) 71 | return isNaN(parsed) 72 | ? value 73 | : parsed 74 | } 75 | }; 76 | 77 | util.convertRangeToArray = function (range) { 78 | return [...Array(range + 1).keys()].slice(1) 79 | }; 80 | 81 | util.convertArray = function (value) { 82 | if (util.isArray(value)) { 83 | return value 84 | } else if (util.isPlainObject(value)) { 85 | // convert plain object to array. 86 | var keys = Object.keys(value) 87 | var i = keys.length 88 | var res = new Array(i) 89 | var key 90 | while (i--) { 91 | key = keys[i] 92 | res[i] = { 93 | $key: key, 94 | $value: value[key] 95 | } 96 | } 97 | return res 98 | } else { 99 | return value || [] 100 | } 101 | } 102 | 103 | function multiIndex(obj,is) { // obj,['1','2','3'] -> ((obj['1'])['2'])['3'] 104 | return is.length ? multiIndex(obj[is[0]],is.slice(1)) : obj 105 | } 106 | 107 | util.getPath = function(obj,is) { // obj,'1.2.3' -> multiIndex(obj,['1','2','3']) 108 | return multiIndex(obj,is.split('.')) 109 | } 110 | 111 | /** 112 | * Strict object type check. Only returns true 113 | * for plain JavaScript objects. 114 | * 115 | * @param {*} obj 116 | * @return {Boolean} 117 | */ 118 | 119 | var toString = Object.prototype.toString 120 | var OBJECT_STRING = '[object Object]' 121 | util.isPlainObject = function (obj) { 122 | return toString.call(obj) === OBJECT_STRING 123 | } 124 | 125 | util.exist = function(value) { 126 | return value !== null && typeof value !== 'undefined' 127 | } 128 | 129 | export default util; -------------------------------------------------------------------------------- /test/filters.spec.js: -------------------------------------------------------------------------------- 1 | var stringFilters = require('../src/string/index') 2 | var arrayFilters = require('../src/array/index') 3 | var otherFilters = require('../src/other/index') 4 | 5 | describe('Filters', function () { 6 | it('number', function () { 7 | var filter = otherFilters.number 8 | expect(filter(123456)).toBe('123456') 9 | expect(filter('123456')).toBe('123456') 10 | expect(filter(-123456)).toBe('-123456') 11 | expect(filter(123456, '+0,0')).toBe('+123,456') 12 | expect(filter(123456, '-0,0')).toBe('-123,456') 13 | expect(filter(-123456, '+0,0')).toBe('+123,456') 14 | expect(filter(123456, '+0')).toBe('+123456') 15 | expect(filter(123456, '-0')).toBe('-123456') 16 | expect(filter(12345.67, '0,0')).toBe('12,346') 17 | expect(filter(12345.67, '0.0000')).toBe('12345.6700') 18 | expect(filter(12345.67, '0,0.0000')).toBe('12,345.6700') 19 | expect(filter(12345.6789, '0,0.0000')).toBe('12,345.6789') 20 | expect(filter(12345, '0,0.0')).toBe('12,345.0') 21 | expect(filter(-12345, '0,0.0')).toBe('-12,345.0') 22 | expect(filter(12345.6789, '0.000')).toBe('12345.679') 23 | expect(filter(1024, '0a')).toBe('1K') 24 | expect(filter(1224, '0.0a')).toBe('1.2K') 25 | expect(filter(10245, '0 a')).toBe('10 K') 26 | expect(filter(10245678, '0.0a')).toBe('10.2M') 27 | expect(filter(-10245678, '.0a')).toBe('-10.2M') 28 | expect(filter(10737418240, '0.0a')).toBe('10.7B') 29 | expect(filter(-10737418240, '.0a')).toBe('-10.7B') 30 | expect(filter(2317370418240, '0.00a')).toBe('2.32T') 31 | expect(filter(-2317370418240, '.00a')).toBe('-2.32T') 32 | expect(filter(-123456.093, '0.00 a')).toBe('-123.46 K') 33 | expect(filter(-0.23, '.00')).toBe('-.23') 34 | // options 35 | expect(filter(123456, '0,0', { thousandsSeparator: '|' })).toBe('123|456') 36 | expect(filter(123456.789, '0.00', { decimalSeparator: '|' })).toBe('123456|79') 37 | expect(filter(10000.998, '0,0.00', { thousandsSeparator: '.', decimalSeparator: '|' })).toBe( 38 | '10.001|00' 39 | ) 40 | }) 41 | 42 | it('number with global options', function () { 43 | var filter = otherFilters.number.bind({ 44 | number: { 45 | thousandsSeparator: '@', 46 | decimalSeparator: '|', 47 | format: '0,0.000' 48 | } 49 | }) 50 | 51 | expect(filter(123456.789)).toBe('123@456|789') 52 | expect(filter(123456.789, '0,0.0')).toBe('123@456|8') 53 | }) 54 | 55 | it('capitalize', function () { 56 | var filter = stringFilters.capitalize 57 | var res = filter('fsefsfsef zxcvxzsaxz') 58 | var words = res.split(' ') 59 | expect(words[0].charAt(0)).toBe('F') 60 | expect(words[0].slice(1)).toBe('sefsfsef') 61 | expect(words[1].charAt(0)).toBe('Z') 62 | expect(words[1].slice(1)).toBe('xcvxzsaxz') 63 | assertNumberAndFalsy(filter) 64 | }) 65 | 66 | it('capitalize only first letter of sentence', function () { 67 | var filter = stringFilters.capitalize 68 | var res = filter('fsefsfsef zxcvxzsaxz', { onlyFirstLetter: true }) 69 | var words = res.split(' ') 70 | expect(words[0].charAt(0)).toBe('F') 71 | expect(words[0].slice(1)).toBe('sefsfsef') 72 | expect(words[1].charAt(0)).toBe('z') 73 | expect(words[1].slice(1)).toBe('xcvxzsaxz') 74 | assertNumberAndFalsy(filter) 75 | }) 76 | 77 | it('capitalize with global options', function () { 78 | var filter = stringFilters.capitalize.bind({ capitalize: { onlyFirstLetter: true } }) 79 | var res = filter('fsefsfsef zxcvxzsaxz') 80 | var words = res.split(' ') 81 | expect(words[0].charAt(0)).toBe('F') 82 | expect(words[0].slice(1)).toBe('sefsfsef') 83 | expect(words[1].charAt(0)).toBe('z') 84 | expect(words[1].slice(1)).toBe('xcvxzsaxz') 85 | assertNumberAndFalsy(filter) 86 | }) 87 | 88 | it('uppercase', function () { 89 | var filter = stringFilters.uppercase 90 | expect(filter('fsefef')).toBe('FSEFEF') 91 | assertNumberAndFalsy(filter) 92 | }) 93 | 94 | it('lowercase', function () { 95 | var filter = stringFilters.lowercase 96 | expect(filter('AWEsoME')).toBe('awesome') 97 | assertNumberAndFalsy(filter) 98 | }) 99 | 100 | it('placeholder', function () { 101 | var filter = stringFilters.placeholder 102 | expect(filter('sometext', 'placeholder text')).toBe('sometext') 103 | expect(filter(1234, 'placeholder text')).toBe(1234) 104 | expect(filter('', 'placeholder text')).toBe('placeholder text') 105 | expect(filter(undefined, 'placeholder text')).toBe('placeholder text') 106 | expect(filter(null, 'placeholder text')).toBe('placeholder text') 107 | }) 108 | 109 | it('truncate', function () { 110 | var filter = stringFilters.truncate 111 | expect(filter('lorem ipsum dolor')).toBe('lorem ipsum dol...') 112 | expect(filter('lorem ipsum dolor', 5)).toBe('lorem...') 113 | expect(filter('lorem ipsum dolor', 20)).toBe('lorem ipsum dolor') 114 | expect(filter(1234, 5)).toBe('') 115 | expect(filter('', 5)).toBe('') 116 | expect(filter(undefined, 5)).toBe('') 117 | expect(filter(null, 5)).toBe('') 118 | }) 119 | 120 | it('currency', function () { 121 | var filter = otherFilters.currency 122 | expect(filter(1234)).toBe('$1,234.00') 123 | expect(filter(1234.45)).toBe('$1,234.45') 124 | expect(filter(123443434.4343434)).toBe('$123,443,434.43') 125 | expect(filter(0.99)).toBe('$0.99') 126 | expect(filter(0.99999)).toBe('$1.00') 127 | expect(filter(0.76)).toBe('$0.76') 128 | // sign arg 129 | expect(filter(2134, '@')).toBe('@2,134.00') 130 | // no symbol 131 | expect(filter(2134, '')).toBe('2,134.00') 132 | // decimal places 133 | expect(filter(1234, '$', 0)).toBe('$1,234') 134 | // if decimal places are present, currency is required 135 | expect(filter(1234, '', 2)).toBe('1,234.00') 136 | expect(filter(123.4, '$', 3)).toBe('$123.400') 137 | expect(filter(-12345, 'VND', 0)).toBe('-VND12,345') 138 | // falsy, infinity and 0 139 | expect(filter(0)).toBe('$0.00') 140 | expect(filter(false)).toBe('') 141 | expect(filter(null)).toBe('') 142 | expect(filter(undefined)).toBe('') 143 | expect(filter(Infinity)).toBe('') 144 | // negative numbers 145 | expect(filter(-50)).toBe('-$50.00') 146 | expect(filter(-150.43)).toBe('-$150.43') 147 | expect(filter(-1500.4343434)).toBe('-$1,500.43') 148 | // options 149 | expect(filter(1234, '@', 0, { thousandsSeparator: ',' })).toBe('@1,234') 150 | expect(filter(1234, '', 2, { decimalSeparator: '|' })).toBe('1,234|00') 151 | expect(filter(1234, '$', 2, { symbolOnLeft: false })).toBe('1,234.00$') 152 | expect(filter(1234, '$', 0, { spaceBetweenAmountAndSymbol: true })).toBe('$ 1,234') 153 | expect(filter(1234, '$', 0, { symbolOnLeft: false, spaceBetweenAmountAndSymbol: true })).toBe( 154 | '1,234 $' 155 | ) 156 | expect(filter(-12345, 'VND', 0, { symbolOnLeft: true })).toBe('-VND12,345') 157 | expect(filter(12345, 'VND', 0, { showPlusSign: true })).toBe('+VND12,345') 158 | expect(filter(-12345, 'VND', 0, { showPlusSign: true })).toBe('-VND12,345') 159 | expect(filter(0, 'VND', 0, { showPlusSign: true })).toBe('VND0') 160 | // round up 161 | expect(filter(4514.275)).toBe('$4,514.28') 162 | expect(filter(9446.975)).toBe('$9,446.98') 163 | }) 164 | 165 | it('currency with global options', function () { 166 | var filter = otherFilters.currency.bind({ 167 | currency: { 168 | symbol: '@', 169 | decimalDigits: 3, 170 | thousandsSeparator: ',', 171 | decimalSeparator: '|', 172 | symbolOnLeft: false, 173 | spaceBetweenAmountAndSymbol: true, 174 | showPlusSign: true 175 | } 176 | }) 177 | 178 | expect(filter(1234)).toBe('+1,234|000 @') 179 | }) 180 | 181 | it('pluralize', function () { 182 | var filter = otherFilters.pluralize 183 | // single word 184 | var word = 'item' 185 | expect(filter(0, word)).toBe('items') 186 | expect(filter(1, word)).toBe('item') 187 | expect(filter(2, word)).toBe('items') 188 | expect(filter(21, word)).toBe('items') 189 | 190 | // multi words 191 | expect(filter(0, ['fry', 'fries'])).toBe('fries') 192 | expect(filter(1, ['fry', 'fries'])).toBe('fry') 193 | expect(filter(2, ['fry', 'fries'])).toBe('fries') 194 | 195 | expect(filter(0, ['first', 'second', 'third', 'nth'])).toBe('nth') 196 | expect(filter(1, ['first', 'second', 'third', 'nth'])).toBe('first') 197 | expect(filter(2, ['first', 'second', 'third', 'nth'])).toBe('second') 198 | expect(filter(3, ['first', 'second', 'third', 'nth'])).toBe('third') 199 | expect(filter(4, ['first', 'second', 'third', 'nth'])).toBe('nth') 200 | expect(filter(50, ['first', 'second', 'third', 'nth'])).toBe('nth') 201 | 202 | // include number 203 | expect(filter(1, word, { includeNumber: false })).toBe('item') 204 | expect(filter(1, word, { includeNumber: true })).toBe('1 item') 205 | expect(filter(1, ['fry', 'fries'], { includeNumber: true })).toBe('1 fry') 206 | }) 207 | 208 | it('pluralize with global options', function () { 209 | var filter = otherFilters.pluralize.bind({ 210 | pluralize: { includeNumber: false } 211 | }) 212 | var word = 'item' 213 | 214 | expect(filter(1, word)).toBe('item') 215 | }) 216 | 217 | it('ordinal', function () { 218 | var filter = otherFilters.ordinal 219 | 220 | expect(filter(0)).toBe('th') 221 | expect(filter(1)).toBe('st') 222 | expect(filter(2)).toBe('nd') 223 | expect(filter(3)).toBe('rd') 224 | expect(filter(4)).toBe('th') 225 | 226 | expect(filter(230)).toBe('th') 227 | expect(filter(231)).toBe('st') 228 | expect(filter(232)).toBe('nd') 229 | expect(filter(233)).toBe('rd') 230 | expect(filter(234)).toBe('th') 231 | 232 | expect(filter(4, { includeNumber: false })).toBe('th') 233 | expect(filter(0, { includeNumber: true })).toBe('0th') 234 | expect(filter(1, { includeNumber: true })).toBe('1st') 235 | }) 236 | 237 | it('ordinal with global options', function () { 238 | var filter = otherFilters.ordinal.bind({ 239 | ordinal: { includeNumber: false } 240 | }) 241 | 242 | expect(filter(4)).toBe('th') 243 | }) 244 | 245 | it('bytes', function () { 246 | var filter = otherFilters.bytes 247 | 248 | expect(filter(1)).toBe('1 byte') 249 | expect(filter(12)).toBe('12 bytes') 250 | expect(filter(2000, 0)).toBe('2 kB') 251 | expect(filter(2000, 1)).toBe('2.0 kB') 252 | expect(filter(2000)).toBe('1.95 kB') 253 | expect(filter(2000, 3)).toBe('1.953 kB') 254 | expect(filter(2000, 4)).toBe('1.9531 kB') 255 | expect(filter(2000000)).toBe('1.91 MB') 256 | expect(filter(2000000, 4)).toBe('1.9073 MB') 257 | expect(filter(2000000000)).toBe('1.86 GB') 258 | expect(filter(2000000000, 4)).toBe('1.8626 GB') 259 | expect(filter(2000000000000)).toBe('1.82 TB') 260 | expect(filter(2000000000000, 4)).toBe('1.8190 TB') 261 | 262 | // edge cases 263 | expect(filter(undefined)).toBe('0 bytes') 264 | expect(filter(null)).toBe('0 bytes') 265 | expect(filter('a random string')).toBe('0 bytes') 266 | }) 267 | 268 | it('bytes with global options', function () { 269 | var filter = otherFilters.bytes.bind({ 270 | bytes: { decimalDigits: 1 } 271 | }) 272 | 273 | expect(filter(2000)).toBe('2.0 kB') 274 | }) 275 | 276 | it('percent', function () { 277 | var filter = otherFilters.percent 278 | 279 | expect(filter(1.2)).toBe('120%') 280 | expect(filter(-0.2)).toBe('-20%') 281 | expect(filter(12)).toBe('1200%') 282 | expect(filter(100, 0)).toBe('10000%') 283 | expect(filter(1, 1)).toBe('100.0%') 284 | expect(filter(0.974878234, 3)).toBe('97.488%') 285 | expect(filter(0.0003, 1)).toBe('0.0%') 286 | 287 | // different multiplier 288 | expect(filter(0.1, 0, 150)).toBe('15%') 289 | expect(filter(0.2, 1, 150)).toBe('30.0%') 290 | expect(filter(1.2, 0, 300)).toBe('360%') 291 | expect(filter(0.974878234, 3, 150)).toBe('146.232%') 292 | 293 | // different decimalSeparator 294 | expect(filter(0.02, 2, 100, { decimalSeparator: '|' })).toBe('2|00%') 295 | expect(filter(0.974878234, 3, 150, { decimalSeparator: '|' })).toBe( 296 | '146|232%' 297 | ) 298 | expect(filter(0.2, 0, 100, { decimalSeparator: '|' })).toBe('20%') 299 | 300 | // edge cases 301 | expect(filter(undefined)).toBe('0%') 302 | expect(filter(null)).toBe('0%') 303 | expect(filter('a random string')).toBe('0%') 304 | }) 305 | 306 | it('percent with global options', function () { 307 | var filter = otherFilters.percent.bind({ 308 | percent: { decimalDigits: 1, multiplier: 150, decimalSeparator: '|' }, 309 | }) 310 | 311 | expect(filter(100)).toBe('15000|0%') 312 | }) 313 | 314 | it('limitByArray', function () { 315 | var filter = arrayFilters.limitBy 316 | var arr = [1, 2, 3] 317 | var res = filter(arr, false) 318 | expect(res).toBe(arr) 319 | res = filter(arr, 1) 320 | assertArray(res, [1]) 321 | res = filter(arr, 10) 322 | assertArray(res, [1, 2, 3]) 323 | res = filter(arr, -1) 324 | assertArray(res, [1, 2]) 325 | // with offsets, note offsets are 0 bound (as expected) 326 | res = filter(arr, 1, 1) 327 | assertArray(res, [2]) 328 | res = filter(arr, 2, 1) 329 | assertArray(res, [2, 3]) 330 | res = filter(arr, 1, 2) 331 | assertArray(res, [3]) 332 | }) 333 | 334 | it('limitByRange', function () { 335 | var filter = arrayFilters.limitBy 336 | var range = 3 337 | var res = filter(range, false) 338 | expect(res).toEqual([1, 2, 3]) 339 | res = filter(range, 1) 340 | assertArray(res, [1]) 341 | res = filter(range, 10) 342 | assertArray(res, [1, 2, 3]) 343 | res = filter(range, -1) 344 | assertArray(res, [1, 2]) 345 | // with offsets, note offsets are 0 bound (as expected) 346 | res = filter(range, 1, 1) 347 | assertArray(res, [2]) 348 | res = filter(range, 2, 1) 349 | assertArray(res, [2, 3]) 350 | res = filter(range, 1, 2) 351 | assertArray(res, [3]) 352 | }) 353 | 354 | it('filterBy', function () { 355 | var filter = arrayFilters.filterBy 356 | var arr = [ 357 | { a: 1, b: { c: 'hello' } }, 358 | { a: 2, b: 'hello' }, 359 | { a: 3, b: ['yoyo'] } 360 | ] 361 | var res 362 | // normal 363 | res = filter(arr, 'hello') 364 | assertArray(res, [arr[0], arr[1]]) 365 | // data key 366 | res = filter(arr, 'hello', 'b.c') 367 | assertArray(res, [arr[0]]) 368 | // no search key 369 | res = filter(arr, null) 370 | expect(res).toBe(arr) 371 | // number search key 372 | res = filter(arr, 2) 373 | assertArray(res, [arr[1]]) 374 | // search in sub array 375 | res = filter(arr, 'yoyo') 376 | assertArray(res, [arr[2]]) 377 | // filter by false (#928) 378 | arr = [{ a: false }, { b: true }] 379 | res = filter(arr, false) 380 | assertArray(res, [arr[0]]) 381 | // filter by a function 382 | res = filter(arr, function (val) { 383 | return val.b === true 384 | }) 385 | assertArray(res, [arr[1]]) 386 | }) 387 | 388 | it('filterBy multiple keys', function () { 389 | var filter = arrayFilters.filterBy 390 | var arr = [ 391 | { firstname: 'A', lastname: 'B' }, 392 | { firstname: 'C', lastname: 'B' }, 393 | { firstname: 'A', lastname: 'D' } 394 | ] 395 | // multiple string keys 396 | var res 397 | // array of keys 398 | res = filter(arr, 'B', ['firstname', 'lastname']) 399 | assertArray(res, [arr[0], arr[1]]) 400 | // multiple arrays of keys 401 | res = filter(arr, 'A', ['firstname', 'lastname'], []) 402 | assertArray(res, [arr[0], arr[2]]) 403 | }) 404 | 405 | it('find', function () { 406 | var find = arrayFilters.find 407 | var arr = [ 408 | { a: 1, b: { c: 'hello' } }, 409 | { a: 2, b: 'hello' }, 410 | { a: 3, b: ['yoyo'] } 411 | ] 412 | var res = find(arr, 'hello') 413 | assertArray(res, [arr[0]]) 414 | }) 415 | 416 | it('orderBy', function () { 417 | var filter = arrayFilters.orderBy 418 | var arr = [ 419 | { a: { b: 0 }, c: 'B' }, 420 | { a: { b: 2 }, c: 'c' }, 421 | { a: { b: 1 }, c: 'a' } 422 | ] 423 | var res 424 | // sort key 425 | res = filter(arr, 'a.b') 426 | assertArray(res, [arr[0], arr[2], arr[1]]) 427 | // reverse key 428 | res = filter(arr, 'a.b', -1) 429 | assertArray(res, [arr[1], arr[2], arr[0]]) 430 | // literal asc 431 | res = filter(arr, 'c', 1) 432 | assertArray(res, [arr[2], arr[0], arr[1]]) 433 | // no sort key 434 | res = filter(arr, null) 435 | expect(res).toBe(arr) 436 | res = filter(arr) 437 | expect(res).toBe(arr) 438 | }) 439 | 440 | it('orderBy on Object-converted array', function () { 441 | // object converted 442 | var filter = arrayFilters.orderBy 443 | var arr = [ 444 | { $key: 'a', $value: 3 }, 445 | { $key: 'c', $value: 1 }, 446 | { $key: 'b', $value: 2 } 447 | ] 448 | var res = filter(arr, '$key') 449 | assertArray(res, [arr[0], arr[2], arr[1]]) 450 | res = filter(arr, '$value') 451 | assertArray(res, [arr[1], arr[2], arr[0]]) 452 | // normal keys 453 | arr = [ 454 | { $key: 'a', $value: { v: 3 } }, 455 | { $key: 'c', $value: { v: 1 } }, 456 | { $key: 'b', $value: { v: 2 } } 457 | ] 458 | res = filter(arr, 'v') 459 | assertArray(res, [arr[1], arr[2], arr[0]]) 460 | }) 461 | 462 | it('orderBy primitive values', function () { 463 | var filter = arrayFilters.orderBy 464 | var arr = [9, 11, 1, 2] 465 | var res = filter(arr, true) 466 | assertArray(res, [arr[2], arr[3], arr[0], arr[1]]) 467 | }) 468 | 469 | it('orderBy array of strings', function () { 470 | var filter = arrayFilters.orderBy 471 | var arr = ['C', 'a', 'B', 'b'] 472 | var res = filter(arr, true) 473 | assertArray(res, [arr[1], arr[2], arr[3], arr[0]]) 474 | }) 475 | 476 | it('orderBy multiple fields', function () { 477 | var filter = arrayFilters.orderBy 478 | var arr = [ 479 | { a: 1, b: 1, c: 1 }, // 0 480 | { a: 0, b: 1, c: 1 }, // 1 481 | { a: 1, b: 2, c: 0 }, // 2 482 | { a: 1, b: 0, c: 0 }, // 3 483 | { a: 0, b: 0, c: 0 }, // 4 484 | { a: 0, b: 1, c: 0 } // 5 485 | ] 486 | var res 487 | // sort two keys 488 | res = filter(arr, ['a', 'b']) 489 | assertArray(res, [arr[4], arr[1], arr[5], arr[3], arr[0], arr[2]]) 490 | res = filter(arr, 'a', 'b') 491 | assertArray(res, [arr[4], arr[1], arr[5], arr[3], arr[0], arr[2]]) 492 | 493 | // sort two keys with order 494 | res = filter(arr, ['a', 'b'], 1) 495 | assertArray(res, [arr[4], arr[1], arr[5], arr[3], arr[0], arr[2]]) 496 | res = filter(arr, 'a', 'b', 1) 497 | assertArray(res, [arr[4], arr[1], arr[5], arr[3], arr[0], arr[2]]) 498 | 499 | // sort three keys 500 | res = filter(arr, ['a', 'b', 'c']) 501 | assertArray(res, [arr[4], arr[5], arr[1], arr[3], arr[0], arr[2]]) 502 | res = filter(arr, 'a', 'b', 'c') 503 | assertArray(res, [arr[4], arr[5], arr[1], arr[3], arr[0], arr[2]]) 504 | 505 | // reverse two key. Preserves order when equal: 1 then 5 506 | res = filter(arr, ['a', 'b'], -1) 507 | assertArray(res, [arr[2], arr[0], arr[3], arr[1], arr[5], arr[4]]) 508 | res = filter(arr, 'a', 'b', -1) 509 | assertArray(res, [arr[2], arr[0], arr[3], arr[1], arr[5], arr[4]]) 510 | }) 511 | 512 | it('orderBy using a compare function', function () { 513 | var filter = arrayFilters.orderBy 514 | var arr = [9, 11, 1, 2] 515 | var res = filter(arr, evenBeforeOdd) 516 | assertArray(res, [arr[3], arr[2], arr[0], arr[1]]) 517 | res = filter(arr, evenBeforeOdd, 1) 518 | assertArray(res, [arr[3], arr[2], arr[0], arr[1]]) 519 | res = filter(arr, evenBeforeOdd, -1) 520 | assertArray(res, [arr[1], arr[0], arr[2], arr[3]]) 521 | }) 522 | 523 | it("repeat", () => { 524 | const filter = stringFilters.repeat; 525 | expect(filter("a")).toBe("a"); 526 | expect(filter("a", 1)).toBe("a"); 527 | expect(filter("a", 2)).toBe("aa"); 528 | expect(filter("a", 5)).toBe("aaaaa"); 529 | expect(filter("2", 2)).toBe("22"); 530 | expect(filter(2, 2)).toBe("22"); 531 | }); 532 | 533 | it("reverse", () => { 534 | const filter = stringFilters.reverse; 535 | const value = "abcd"; 536 | expect(filter(value)).toBe("dcba"); 537 | }); 538 | 539 | it("wrap", () => { 540 | const filter = stringFilters.wrap; 541 | const value = "value"; 542 | expect(filter(value)).toBe("value"); 543 | expect(filter(value, "/")).toBe("/value/"); 544 | }); 545 | }) 546 | 547 | function evenBeforeOdd(a, b) { 548 | if (a % 2 === 0) { 549 | if (b % 2 === 0) { 550 | return a - b 551 | } else { 552 | return -1 553 | } 554 | } else if (b % 2 === 0) { 555 | return 1 556 | } else { 557 | return a - b 558 | } 559 | } 560 | 561 | function assertArray(res, expectations) { 562 | expect(res.length).toBe(expectations.length) 563 | expectations.forEach(function (exp, i) { 564 | expect(exp).toBe(res[i]) 565 | }) 566 | } 567 | 568 | function assertNumberAndFalsy(filter) { 569 | // should stringify numbers 570 | expect(filter(12345)).toBe('12345') 571 | expect(filter(0)).toBe('0') 572 | expect(filter(undefined)).toBe('') 573 | expect(filter(null)).toBe('') 574 | expect(filter(false)).toBe('') 575 | } 576 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require('puppeteer') 2 | process.env.CHROME_BIN = puppeteer.executablePath() 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | frameworks: ['jasmine'], 8 | 9 | files: [ 10 | '../test/**/*.spec.js' 11 | ], 12 | 13 | preprocessors: { 14 | '../test/**/*.spec.js': ['webpack'] 15 | }, 16 | 17 | browsers: ['ChromeHeadless'], 18 | 19 | plugins: [ 20 | 'karma-chrome-launcher', 21 | 'karma-jasmine', 22 | 'karma-webpack' 23 | ], 24 | 25 | webpack: { 26 | entry: './src/index.js', 27 | mode: 'development' 28 | } 29 | 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { PluginFunction, PluginObject } from "vue"; 2 | 3 | declare const Vue2Filters: Vue2Filters; 4 | export default Vue2Filters; 5 | export interface Vue2Filters extends PluginObject { 6 | install: PluginFunction; 7 | mixin: { 8 | methods: { 9 | limitBy: (arr: any, n: number, offset: number) => any; 10 | filterBy: (arr: any[], search: string | number, ...args: any[]) => any[]; 11 | orderBy: (arr: any, ...args: any[]) => any; 12 | find: (arr: any[], search: string | number, ...args: any[]) => any; 13 | }; 14 | }; 15 | } 16 | 17 | export interface Vue2FiltersUseOptions {} 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 3 | 4 | module.exports = { 5 | entry: { 6 | 'vue2-filters': './src/index.js', 7 | 'vue2-filters.min': './src/index.js' 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, 'dist'), 11 | filename: '[name].js', 12 | libraryTarget: "umd", 13 | globalObject: 'typeof self !== \'undefined\' ? self : this' 14 | }, 15 | optimization: { 16 | minimize: true, 17 | minimizer: [new UglifyJsPlugin({ 18 | include: /\.min\.js$/ 19 | })] 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.js$/, 25 | exclude: /node_modules/, 26 | use: { 27 | loader: 'babel-loader' 28 | } 29 | } 30 | ] 31 | } 32 | }; --------------------------------------------------------------------------------