diff --git a/.config/bundle-system.js b/.config/bundle-system.js new file mode 100755 index 0000000..9c8cc53 --- /dev/null +++ b/.config/bundle-system.js @@ -0,0 +1,107 @@ +#!/usr/bin/env node +'use strict'; + +/*eslint no-console: 0, no-sync: 0*/ + +// System.js bundler +// simple and yet reusable system.js bundler +// bundles, minifies and gzips + +const fs = require('fs'); +const del = require('del'); +const path = require('path'); +const zlib = require('zlib'); +const async = require('async'); +const Builder = require('systemjs-builder'); + +const pkg = require('../package.json'); +const name = pkg.name; +const targetFolder = path.resolve('./bundles'); + +async.waterfall([ + cleanBundlesFolder, + getSystemJsBundleConfig, + buildSystemJs({minify: false, sourceMaps: true, mangle: false}), + getSystemJsBundleConfig, + buildSystemJs({minify: true, sourceMaps: true, mangle: false}), + gzipSystemJsBundle +], err => { + if (err) { + throw err; + } +}); + +function getSystemJsBundleConfig(cb) { + const config = { + baseURL: '..', + transpiler: 'typescript', + typescriptOptions: { + module: 'cjs' + }, + map: { + typescript: path.resolve('node_modules/typescript/lib/typescript.js'), + '@angular/core': path.resolve('node_modules/@angular/core/index.js'), + '@angular/common': path.resolve('node_modules/@angular/common/index.js'), + '@angular/compiler': path.resolve('node_modules/@angular/compiler/index.js'), + '@angular/platform-browser': path.resolve('node_modules/@angular/platform-browser/index.js'), + '@angular/platform-browser-dynamic': path.resolve('node_modules/@angular/platform-browser-dynamic/'), + rxjs: path.resolve('node_modules/rxjs') + }, + paths: { + '*': '*.js' + } + }; + + config.meta = ['@angular/common','@angular/compiler','@angular/core', + '@angular/platform-browser','@angular/platform-browser-dynamic', 'rxjs'].reduce((memo, currentValue) => { + memo[path.resolve(`node_modules/${currentValue}/*`)] = {build: false}; + return memo; + }, {}); + config.meta.moment = {build: false}; + return cb(null, config); +} + +function cleanBundlesFolder(cb) { + return del(targetFolder) + .then(paths => { + console.log('Deleted files and folders:\n', paths.join('\n')); + cb(); + }); +} + +function buildSystemJs(options) { + return (config, cb) => { + const minPostFix = options && options.minify ? '.min' : ''; + const fileName = `${name}${minPostFix}.js`; + const dest = path.resolve(__dirname, targetFolder, fileName); + const builder = new Builder(); + + console.log('Bundling system.js file:', fileName, options); + builder.config(config); + return builder + .bundle([name, name].join('/'), dest, options) + .then(() => cb()) + .catch(cb); + }; +} + +function gzipSystemJsBundle(cb) { + const files = fs + .readdirSync(path.resolve(targetFolder)) + .map(file => path.resolve(targetFolder, file)) + .filter(file => fs.statSync(file).isFile()) + .filter(file => path.extname(file) !== 'gz'); + + return async.eachSeries(files, (file, gzipcb) => { + process.nextTick(() => { + console.log('Gzipping ', file); + const gzip = zlib.createGzip({level: 9}); + const inp = fs.createReadStream(file); + const out = fs.createWriteStream(`${file}.gz`); + + inp.on('end', () => gzipcb()); + inp.on('error', err => gzipcb(err)); + return inp.pipe(gzip).pipe(out); + }); + }, cb); +} diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..f8afe99 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "./node_modules/eslint-config-valorsoft/.eslintrc.json", + "env": { + "node": true + } +} diff --git a/.gitignore b/.gitignore index bc43dd8..6322466 100644 --- a/.gitignore +++ b/.gitignore @@ -10,11 +10,15 @@ npm-debug.log .idea # ignore build and dist for now -/build +/bundles +/demo-build /dist +/coverage +/ts /demo/**/*.js /demo/**/*.js.map +/demo/**/*.d.ts /components/**/*.js /components/**/*.js.map /components/**/*.d.ts diff --git a/.npmignore b/.npmignore index d36ec4a..8f189f2 100644 --- a/.npmignore +++ b/.npmignore @@ -1,9 +1,24 @@ .idea -demo gulp-tasks logs -tsd.d.ts +# typings typings +# testing +karma.conf.js +test.bundle.js +coverage + +# demo build +demo +demo-build webpack.config.js + +#typescript sources +*.ts +*.js.map +!*.d.ts +/components/**/*.ts +!/components/**/*.d.ts + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..56eb9da --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: node_js +node_js: + - "6" + +script: + - npm run flow.install:typings + - npm test + +after_success: + - ./node_modules/.bin/codecov + +addons: + # sauce labs tunel connector (read more https://docs.travis-ci.com/user/sauce-connect/ ) + sauce_connect: true + firefox: "42.0" + apt: + sources: + - ubuntu-toolchain-r-test + # required by node-gyp to build some packages + packages: + - g++-4.8 diff --git a/LICENSE b/LICENSE index bf4dedb..901dcb1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ The MIT License (MIT) -Copyright (c) 2015 Dmitriy Shekhovtsov -Copyright (c) 2015 Valor Software +Copyright (c) 2015-2016 Dmitriy Shekhovtsov +Copyright (c) 2015-2016 Valor Software Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index f1b7410..a18b3a9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # ng2-table [![npm version](https://badge.fury.io/js/ng2-table.svg)](http://badge.fury.io/js/ng2-table) Simple table extension with sorting, filtering, paging... for Angular2 apps -Follow me at [twitter](https://twitter.com/valorkin) to be notified about new releases. +Follow me [![twitter](https://img.shields.io/twitter/follow/valorkin.svg?style=social&label=%20valorkin)](https://twitter.com/valorkin) to be notified about new releases. +[![Angular 2 Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://github.com/mgechev/angular2-style-guide) +[![Build Status](https://travis-ci.org/valor-software/ng2-table.svg?branch=master)](https://travis-ci.org/valor-software/ng2-table) [![Code Climate](https://codeclimate.com/github/valor-software/ng2-table/badges/gpa.svg)](https://codeclimate.com/github/valor-software/ng2-table) [![Join the chat at https://gitter.im/valor-software/ng2-bootstrap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/valor-software/ng2-bootstrap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Dependency Status](https://david-dm.org/valor-software/ng2-table.svg)](https://david-dm.org/valor-software/ng2-table) @@ -15,18 +17,20 @@ Follow me at [twitter](https://twitter.com/valorkin) to be notified about new re - - - -## Quick start +## Installation 1. A recommended way to install ***ng2-table*** is through [npm](https://www.npmjs.com/search?q=ng2-table) package manager using the following command: - `npm i ng2-table --save` + ```bash + npm i ng2-table --save + ``` Alternatively, you can [download it in a ZIP file](https://github.com/valor-software/ng2-table/archive/master.zip). 2. More information regarding using of ***ng2-table*** is located in [demo](http://valor-software.github.io/ng2-table/) and [demo sources](https://github.com/valor-software/ng2-table/tree/master/demo). -## API +## Documentation ### Inputs (Properties) diff --git a/components/ng-table-directives.ts b/components/ng-table-directives.ts index a52b319..106db3d 100644 --- a/components/ng-table-directives.ts +++ b/components/ng-table-directives.ts @@ -1,5 +1,5 @@ -import {NgTable} from './table/ng-table.component'; -import {NgTableFiltering} from './table/ng-table-filtering.directive'; -import {NgTablePaging} from './table/ng-table-paging.directive'; -import {NgTableSorting} from './table/ng-table-sorting.directive'; -export const NG_TABLE_DIRECTIVES = [NgTable, NgTableFiltering, NgTablePaging, NgTableSorting]; +import {NgTableComponent} from './table/ng-table.component'; +import {NgTableFilteringDirective} from './table/ng-table-filtering.directive'; +import {NgTablePagingDirective} from './table/ng-table-paging.directive'; +import {NgTableSortingDirective} from './table/ng-table-sorting.directive'; +export const NG_TABLE_DIRECTIVES = [NgTableComponent, NgTableFilteringDirective, NgTablePagingDirective, NgTableSortingDirective]; diff --git a/components/table/ng-table-filtering.directive.ts b/components/table/ng-table-filtering.directive.ts index 84ef139..160da3f 100644 --- a/components/table/ng-table-filtering.directive.ts +++ b/components/table/ng-table-filtering.directive.ts @@ -1,33 +1,41 @@ -import {Directive, EventEmitter, ElementRef, Renderer} from '@angular/core'; -import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass} from '@angular/common'; +import {Directive, EventEmitter, ElementRef, Renderer, HostListener, Input, Output} from '@angular/core'; // import {setProperty} from 'angular2/ts/src/core/forms/directives/shared'; -function setProperty(renderer:Renderer, elementRef:ElementRef, propName:string, propValue:any) { +function setProperty(renderer:Renderer, elementRef:ElementRef, propName:string, propValue:any):void { renderer.setElementProperty(elementRef, propName, propValue); } -@Directive({ - selector: '[ngTableFiltering]', - inputs: ['config: ngTableFiltering'], - outputs: ['tableChanged'], - host: { - '(input)': 'onChangeFilter($event.target.value)' - } -}) -export class NgTableFiltering { - public config:any = { +@Directive({selector: '[ngTableFiltering]'}) +export class NgTableFilteringDirective { + @Input() public ngTableFiltering:any = { filterString: '', columnName: 'name' }; - public tableChanged:EventEmitter = new EventEmitter(); - constructor(private element:ElementRef, private renderer:Renderer) { - // Set default value for filter - setProperty(this.renderer, this.element, 'value', this.config.filterString); + @Output() public tableChanged:EventEmitter = new EventEmitter(); + + @Input() + public get config():any { + return this.ngTableFiltering; + } + + public set config(value:any) { + this.ngTableFiltering = value; } - onChangeFilter(event:any) { - this.config.filterString = event; - this.tableChanged.emit({filtering: this.config}); + private element:ElementRef; + private renderer:Renderer; + + @HostListener('input', ['$event.target.value']) + public onChangeFilter(event:any):void { + this.ngTableFiltering.filterString = event; + this.tableChanged.emit({filtering: this.ngTableFiltering}); + } + + public constructor(element:ElementRef, renderer:Renderer) { + this.element = element; + this.renderer = renderer; + // Set default value for filter + setProperty(this.renderer, this.element, 'value', this.ngTableFiltering.filterString); } } diff --git a/components/table/ng-table-paging.directive.ts b/components/table/ng-table-paging.directive.ts index 0b104f0..25a6ee9 100644 --- a/components/table/ng-table-paging.directive.ts +++ b/components/table/ng-table-paging.directive.ts @@ -1,21 +1,23 @@ -import {Directive, EventEmitter, ElementRef, Renderer} from '@angular/core'; -import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass} from '@angular/common'; +import {Directive, EventEmitter, Input, Output, HostListener} from '@angular/core'; -@Directive({ - selector: '[ngTablePaging]', - inputs: ['config: ngTablePaging'], - outputs: ['tableChanged'], - host: { - '(pagechanged)': 'onChangePage($event)' +@Directive({selector: '[ngTablePaging]'}) +export class NgTablePagingDirective { + @Input() public ngTablePaging:boolean = true; + @Output() public tableChanged:EventEmitter = new EventEmitter(); + + @Input() + public get config():any { + return this.ngTablePaging; + } + + public set config(value:any) { + this.ngTablePaging = value; } -}) -export class NgTablePaging { - public config:boolean = true; - public tableChanged:EventEmitter = new EventEmitter(); - onChangePage(event:any) { + @HostListener('pagechanged', ['$event']) + public onChangePage(event:any):void { // Object.assign(this.config, event); - if (this.config) { + if (this.ngTablePaging) { this.tableChanged.emit({paging: event}); } } diff --git a/components/table/ng-table-sorting.directive.ts b/components/table/ng-table-sorting.directive.ts index e3bb3ef..4bfadd4 100644 --- a/components/table/ng-table-sorting.directive.ts +++ b/components/table/ng-table-sorting.directive.ts @@ -1,25 +1,27 @@ -import {Directive, EventEmitter} from '@angular/core'; -import {FORM_DIRECTIVES, CORE_DIRECTIVES, NgClass} from '@angular/common'; +import {Directive, EventEmitter, Input, Output, HostListener} from '@angular/core'; -@Directive({ - selector: '[ngTableSorting]', - inputs: ['config: ngTableSorting', 'column'], - outputs: ['sortChanged'], - host: { - '(click)': 'onToggleSort($event, $target)' +@Directive({selector: '[ngTableSorting]'}) +export class NgTableSortingDirective { + @Input() public ngTableSorting:any; + @Input() public column:any; + @Output() public sortChanged:EventEmitter = new EventEmitter(); + + @Input() + public get config():any { + return this.ngTableSorting; + } + + public set config(value:any) { + this.ngTableSorting = value; } -}) -export class NgTableSorting { - public config:any; - public column:any; - public sortChanged:EventEmitter = new EventEmitter(); - onToggleSort(event:any) { + @HostListener('click', ['$event', '$target']) + public onToggleSort(event:any):void { if (event) { event.preventDefault(); } - if (this.config && this.column && this.column.sort !== false) { + if (this.ngTableSorting && this.column && this.column.sort !== false) { switch (this.column.sort) { case 'asc': this.column.sort = 'desc'; diff --git a/components/table/ng-table.component.spec.ts b/components/table/ng-table.component.spec.ts new file mode 100644 index 0000000..87d0c5a --- /dev/null +++ b/components/table/ng-table.component.spec.ts @@ -0,0 +1,12 @@ +import {it, expect, describe, inject, beforeEachProviders} from '@angular/core/testing'; +import {ComponentFixture} from '@angular/compiler/testing'; +import {NgTableComponent} from './ng-table.component'; + +describe('Directive: FileSelectDirective', () => { + beforeEachProviders(() => [ + NgTableComponent + ]); + it('should be fine', inject([NgTableComponent], (fixture:ComponentFixture) => { + expect(fixture).not.toBeNull(); + })); +}); diff --git a/components/table/ng-table.component.ts b/components/table/ng-table.component.ts index cc6ef76..cf1dbd5 100644 --- a/components/table/ng-table.component.ts +++ b/components/table/ng-table.component.ts @@ -1,12 +1,9 @@ -import {Component, Directive, EventEmitter, ElementRef, Renderer} from '@angular/core'; -import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass, NgFor} from '@angular/common'; - -import {NgTableSorting} from './ng-table-sorting.directive'; +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {CORE_DIRECTIVES, NgClass} from '@angular/common'; +import {NgTableSortingDirective} from './ng-table-sorting.directive'; @Component({ - selector: 'ngTable, [ngTable]', - inputs: ['rows', 'columns', 'config'], - outputs: ['tableChanged'], + selector: 'ng-table', template: ` @@ -26,20 +23,20 @@ import {NgTableSorting} from './ng-table-sorting.directive';
`, - directives: [NgTableSorting, NgClass, CORE_DIRECTIVES, FORM_DIRECTIVES] + directives: [NgTableSortingDirective, NgClass, CORE_DIRECTIVES] }) -export class NgTable { +export class NgTableComponent { // Table values - public rows:Array = []; - private _columns:Array = []; - public config:any = {}; + @Input() public rows:Array = []; + @Input() public config:any = {}; // Outputs (Events) - public tableChanged:EventEmitter = new EventEmitter(); + @Output() public tableChanged:EventEmitter = new EventEmitter(); + @Input() public set columns(values:Array) { - values.forEach((value) => { - let column = this._columns.find((col) => col.name === value.name); + values.forEach((value:any) => { + let column = this._columns.find((col:any) => col.name === value.name); if (column) { Object.assign(column, value); } @@ -49,14 +46,14 @@ export class NgTable { }); } - public get columns() { + public get columns():Array { return this._columns; } - public get configColumns() { + public get configColumns():any { let sortColumns:Array = []; - this.columns.forEach((column) => { + this.columns.forEach((column:any) => { if (column.sort) { sortColumns.push(column); } @@ -65,16 +62,18 @@ export class NgTable { return {columns: sortColumns}; } - onChangeTable(column:any) { - this._columns.forEach((col) => { - if (col.name != column.name) { + private _columns:Array = []; + + public onChangeTable(column:any):void { + this._columns.forEach((col:any) => { + if (col.name !== column.name) { col.sort = ''; } }); this.tableChanged.emit({sorting: this.configColumns}); } - getData(row:any, propertyName:string) { - return propertyName.split('.').reduce((prev, curr) => prev[curr], row); + public getData(row:any, propertyName:string):string { + return propertyName.split('.').reduce((prev:any, curr:string) => prev[curr], row); } } diff --git a/components/table/readme.md b/components/table/readme.md index e8e7575..dec5104 100644 --- a/components/table/readme.md +++ b/components/table/readme.md @@ -4,7 +4,7 @@ import {NG_TABLE_DIRECTIVES} from 'ng2-table/ng2-table'; ``` or if you want to import specified plugins (Table component is required, the others are optional): ```typescript -import {, NgTableFiltering, NgTablePaging, NgTableSorting} from 'ng2-table/ng2-table'; +import {NgTableComponent, NgTableFilteringDirective, NgTablePagingDirective, NgTableSortingDirective} from 'ng2-table/ng2-table'; ``` in this case, don't forget to include all of the imported entities to the option `directives` in your component diff --git a/demo/components/table-section.ts b/demo/components/table-section.ts index 5f088b5..b638043 100644 --- a/demo/components/table-section.ts +++ b/demo/components/table-section.ts @@ -1,7 +1,7 @@ -import {Component, } from '@angular/core'; +import {Component} from '@angular/core'; import {CORE_DIRECTIVES} from '@angular/common'; -import {TableDemo} from './table/table-demo'; +import {TableDemoComponent} from './table/table-demo'; let name = 'Table'; let src = 'https://github.com/valor-software/ng2-table/blob/master/components/table/table.ts'; @@ -54,7 +54,7 @@ let html = require('!!prismjs?lang=markup!./table/table-demo.html'); `, - directives: [TableDemo, CORE_DIRECTIVES] + directives: [TableDemoComponent, CORE_DIRECTIVES] }) -export class TableSection { +export class TableSectionComponent { } diff --git a/demo/components/table/table-demo.html b/demo/components/table/table-demo.html index 3fc2068..2409528 100644 --- a/demo/components/table/table-demo.html +++ b/demo/components/table/table-demo.html @@ -2,10 +2,10 @@ [ngTableFiltering]="config.filtering" (tableChanged)="onChangeTable(config)"/> - - + = []; public columns:Array = [ {title: 'Name', name: 'name'}, @@ -38,32 +36,32 @@ export class TableDemo implements OnInit { private data:Array = TableData; - constructor() { + public constructor() { this.length = this.data.length; } - ngOnInit() { + public ngOnInit():void { this.onChangeTable(this.config); } - changePage(page:any, data:Array = this.data):Array { + public changePage(page:any, data:Array = this.data):Array { console.log(page); let start = (page.page - 1) * page.itemsPerPage; let end = page.itemsPerPage > -1 ? (start + page.itemsPerPage) : data.length; return data.slice(start, end); } - changeSort(data:any, config:any) { + public changeSort(data:any, config:any):any { if (!config.sorting) { return data; } let columns = this.config.sorting.columns || []; - let columnName: string = null; - let sort: string = null; + let columnName:string = void 0; + let sort:string = void 0; for (let i = 0; i < columns.length; i++) { - if (columns[i].sort != '') { + if (columns[i].sort !== '') { columnName = columns[i].name; sort = columns[i].sort; } @@ -74,7 +72,7 @@ export class TableDemo implements OnInit { } // simple sorting - return data.sort((previous: any, current: any) => { + return data.sort((previous:any, current:any) => { if (previous[columnName] > current[columnName]) { return sort === 'desc' ? -1 : 1; } else if (previous[columnName] < current[columnName]) { @@ -84,7 +82,7 @@ export class TableDemo implements OnInit { }); } - changeFilter(data:any, config:any):any { + public changeFilter(data:any, config:any):any { if (!config.filtering) { return data; } @@ -95,7 +93,7 @@ export class TableDemo implements OnInit { return filteredData; } - onChangeTable(config: any, page: any = { page: this.page, itemsPerPage: this.itemsPerPage }) { + public onChangeTable(config:any, page:any = {page: this.page, itemsPerPage: this.itemsPerPage}):any { if (config.filtering) { Object.assign(this.config.filtering, config.filtering); } diff --git a/demo/index.html b/demo/index.html index ffdc2f9..4edaa1b 100644 --- a/demo/index.html +++ b/demo/index.html @@ -35,12 +35,5 @@ Loading... - - - - - - - diff --git a/demo/index.ts b/demo/index.ts index 210ac5c..39370a5 100644 --- a/demo/index.ts +++ b/demo/index.ts @@ -1,9 +1,7 @@ import {bootstrap} from '@angular/platform-browser-dynamic'; import {Component} from '@angular/core'; import {NgClass} from '@angular/common'; - - -import {TableSection} from './components/table-section'; +import {TableSectionComponent} from './components/table-section'; let gettingStarted = require('./getting-started.md'); @@ -36,10 +34,10 @@ let gettingStarted = require('./getting-started.md'); `, directives: [ NgClass, - TableSection + TableSectionComponent ] }) -export class Demo { +export class DemoComponent { } -bootstrap(Demo); +bootstrap(DemoComponent); diff --git a/gulp-tasks/lint.js b/gulp-tasks/lint.js index 1371ed5..62c7806 100644 --- a/gulp-tasks/lint.js +++ b/gulp-tasks/lint.js @@ -1,23 +1,20 @@ -var gulp = require('gulp'); -var esLint = require('gulp-eslint'); -var tslint = require('gulp-tslint'); +'use strict'; -var paths = gulp.paths; +const gulp = require('gulp'); +const tslint = require('gulp-tslint'); +const gitignore = require('gitignore-to-glob')(); -gulp.task('eslint', function() { - return gulp.src(paths.jssrc) - .pipe(esLint({useEslintrc: true})) - .pipe(esLint.format()) - .pipe(esLint.failOnError()); -}); +gitignore.push('**/*.ts'); -gulp.task('tslint', function() { - return gulp.src(paths.tssrc) +gulp.task('tslint', () => + gulp + .src(gitignore) .pipe(tslint()) - .pipe(tslint.report('verbose', { + .pipe(tslint.report('prose', { emitError: true, - reportLimit: 0 - })); -}); + summarizeFailureOutput: true, + reportLimit: 50 + })) +); -gulp.task('lint', ['tslint', 'eslint']); +gulp.task('lint', ['tslint']); diff --git a/gulpfile.js b/gulpfile.js index bffd73d..3d44e09 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,29 +1,9 @@ -var gulp = require('gulp'); +'use strict'; -gulp.paths = { - tssrc: [ - '**/*.ts', - '!node_modules/**/*', - '!dist/**/*', - '!typings/**/*', - '!**/*.{ts,coffee}.js'], - jssrc: [ - '*.js', - 'gulp-tasks/*.js', - '!ng2-table.js', - '!angular2-table.js', - '!node_modules', - '!**/*.{ts,coffee}.js'] -}; +const gulp = require('gulp'); require('require-dir')('./gulp-tasks'); -var clean = require('gulp-clean'); -gulp.task('clean', function () { - return gulp.src('dist', {read: false}) - .pipe(clean()); -}); - -gulp.task('default', function () { +gulp.task('default', () => { gulp.start('lint'); -}); \ No newline at end of file +}); diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..31fec66 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,101 @@ +'use strict'; + +const path = require('path'); +const cwd = process.cwd(); + +module.exports = config => { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + // list of files / patterns to load in the browser + files: [ + {pattern: 'test.bundle.js', watched: false} + ], + + // list of files to exclude + exclude: [], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'test.bundle.js': ['coverage', 'webpack', 'sourcemap'] + }, + + webpack: { + resolve: { + root: [path.resolve(cwd)], + modulesDirectories: ['node_modules', 'demo', 'components', 'test', '.'], + extensions: ['', '.ts', '.js', '.css'] + }, + module: { + loaders: [ + {test: /\.ts$/, loader: 'ts-loader', exclude: [/node_modules/]} + ], + postLoaders: [ + // instrument only testing sources with Istanbul + { + test: /\.(js|ts)$/, + include: root('components'), + loader: 'istanbul-instrumenter-loader', + exclude: [ + /\.e2e\.ts$/, + /node_modules/ + ] + } + ] + }, + stats: { + colors: true, + reasons: true + }, + watch: true, + debug: true + }, + + coverageReporter: { + dir: 'coverage/', + reporters: [ + {type: 'text'}, + {type: 'json'}, + {type: 'html'} + ] + }, + webpackServer: {noInfo: true}, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['spec', 'coverage'], + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || + // config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true + }); +}; + +function root(partialPath) { + return path.join(__dirname, partialPath); +} diff --git a/ng2-table.ts b/ng2-table.ts index f5f1c70..00db65e 100644 --- a/ng2-table.ts +++ b/ng2-table.ts @@ -1,3 +1,9 @@ +import {NgTableComponent} from './components/table/ng-table.component'; + +import {NgTableFilteringDirective} from './components/table/ng-table-filtering.directive'; +import {NgTablePagingDirective} from './components/table/ng-table-paging.directive'; +import {NgTableSortingDirective} from './components/table/ng-table-sorting.directive'; + export * from './components/table/ng-table.component'; export * from './components/table/ng-table-filtering.directive'; @@ -5,3 +11,12 @@ export * from './components/table/ng-table-paging.directive'; export * from './components/table/ng-table-sorting.directive'; export * from './components/ng-table-directives'; + +export default { + directives: [ + NgTableComponent, + NgTableFilteringDirective, + NgTableSortingDirective, + NgTablePagingDirective + ] +}; diff --git a/package.json b/package.json index eba2944..aeedb9b 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,32 @@ { "name": "ng2-table", - "version": "1.0.0-beta.0", - "description": "angular2 table components", + "version": "1.0.1", + "description": "Simple angular2 table components with sorting, filtering...", "scripts": { - "typings": "typings", - "deploy": "NODE_ENV=production webpack -p --progress --color --optimize-minimize --optimize-dedupe --optimize-occurence-order", - "postinstall": "npm run typings -- install", - "prepublish": "gulp clean && tsc", - "server": "webpack-dev-server --hot --inline --colors --display-error-details --display-cached", - "start": "npm run server", - "test": "gulp lint" + "flow.install:typings": "./node_modules/.bin/typings install", + "flow.compile": "npm run flow.install:typings && npm run flow.compile:common && npm run flow.compile:system ", + "flow.compile:common": "./node_modules/.bin/tsc", + "flow.compile:system": "./.config/bundle-system.js", + "flow.copy:src": "./node_modules/.bin/cpy ng2-table.ts \"components/*.ts\" ts --parents", + "flow.clean": "./node_modules/.bin/del bundles coverage demo-build typings \"components/**/*.+(js|d.ts|js.map)\" dist \"ng2-table.+(js|d.ts|js.map)\"", + "flow.deploy:gh-pages": "npm run flow.build:prod && ./node_modules/.bin/gh-pages -d demo-build", + "flow.eslint": "./node_modules/.bin/eslint --ignore-path .gitignore --ext js --fix . .config", + "flow.tslint": "./node_modules/.bin/gulp lint", + "flow.lint": "npm run flow.eslint && npm run flow.tslint", + "flow.changelog": "./node_modules/.bin/conventional-changelog -i CHANGELOG.md -s -p angular -v", + "flow.github-release": "./node_modules/.bin/conventional-github-releaser -p angular", + "flow.build:prod": "NODE_ENV=production ./node_modules/.bin/webpack --progress --color", + "flow.build:dev": "./node_modules/.bin/webpack --progress --color", + "flow.serve:dev": "./node_modules/.bin/webpack-dev-server --hot --inline --colors --display-error-details --display-cached", + "flow.serve:prod": "NODE_ENV=production ./node_modules/.bin/webpack-dev-server --hot --inline --colors --display-error-details --display-cached", + "prepublish": "npm run flow.clean && npm run flow.compile", + "postpublish": "npm run flow.deploy:gh-pages", + "start": "npm run flow.serve:dev", + "pretest": "npm run flow.lint", + "test": "NODE_ENV=test ./node_modules/.bin/karma start", + "preversion": "npm test", + "version": "npm run flow.changelog && git add -A", + "postversion": "git push origin development && git push --tags" }, "main": "ng2-table.js", "typings": "ng2-table.d.ts", @@ -31,43 +48,69 @@ }, "homepage": "https://github.com/valor-software/ng2-table#readme", "dependencies": {}, + "peerDependencies": { + "@angular/common": "^2.0.0-rc.1", + "@angular/compiler": "^2.0.0-rc.1", + "@angular/core": "^2.0.0-rc.1" + }, "devDependencies": { - "@angular/common": "2.0.0-rc.1", - "@angular/compiler": "2.0.0-rc.1", - "@angular/core": "2.0.0-rc.1", - "@angular/platform-browser": "2.0.0-rc.1", - "@angular/platform-browser-dynamic": "2.0.0-rc.1", - "bootstrap": "3.3.6", - "clean-webpack-plugin": "0.1.8", + "@angular/common": "^2.0.0-rc.1", + "@angular/compiler": "^2.0.0-rc.1", + "@angular/core": "^2.0.0-rc.1", + "@angular/platform-browser": "^2.0.0-rc.1", + "@angular/platform-browser-dynamic": "^2.0.0-rc.1", + "async": "1.5.2", + "codecov": "1.0.1", "compression-webpack-plugin": "0.3.1", - "es6-shim": "^0.35.0", - "eslint": "1.10.3", + "conventional-changelog-cli": "1.2.0", + "conventional-github-releaser": "1.1.2", + "copy-webpack-plugin": "3.0.0", + "cpy-cli": "1.0.0", + "del-cli": "0.2.0", + "es6-promise": "3.2.1", + "es6-shim": "0.35.1", + "es7-reflect-metadata": "1.6.0", + "eslint-config-valorsoft": "0.0.13", "exports-loader": "0.6.3", "file-loader": "0.8.5", + "gh-pages": "0.11.0", + "gitignore-to-glob": "0.2.1", "gulp": "3.9.1", - "gulp-clean": "0.3.2", - "gulp-eslint": "1.1.1", "gulp-size": "2.1.0", - "gulp-tsc": "1.1.5", - "gulp-tslint": "4.3.5", + "gulp-tslint": "5.0.0", "html-loader": "0.4.3", + "html-webpack-plugin": "2.17.0", + "istanbul-instrumenter-loader": "0.2.0", + "jasmine": "2.4.1", + "karma": "0.13.22", + "karma-chrome-launcher": "1.0.1", + "karma-coverage": "1.0.0", + "karma-jasmine": "1.0.2", + "karma-phantomjs-launcher": "1.0.0", + "karma-sourcemap-loader": "0.3.7", + "karma-spec-reporter": "0.0.26", + "karma-webpack": "1.7.0", + "lite-server": "2.2.0", "markdown-loader": "0.1.7", "marked": "0.3.5", - "moment": "2.11.2", "ng2-bootstrap": "1.0.16", - "pre-commit": "1.1.2", - "prismjs": "valorkin/prism", - "prismjs-loader": "0.0.2", + "phantomjs-polyfill": "0.0.2", + "phantomjs-prebuilt": "2.1.7", + "pre-commit": "1.1.3", + "prismjs": "1.5.0", + "prismjs-loader": "0.0.3", "raw-loader": "0.5.1", - "reflect-metadata": "0.1.2", + "reflect-metadata": "0.1.3", "require-dir": "0.3.0", "rxjs": "5.0.0-beta.6", + "source-map-loader": "0.1.5", + "systemjs-builder": "0.15.16", "ts-loader": "0.8.2", - "tslint": "3.6.0", - "typescript": "1.8.7", - "typings": "^0.8.1", - "webpack": "1.12.15", - "webpack-dev-server": "1.14.0", - "zone.js": "^0.6.12" + "tslint-config-valorsoft": "1.0.3", + "typescript": "1.8.10", + "typings": "0.8.1", + "webpack": "1.13.0", + "webpack-dev-server": "1.14.1", + "zone.js": "0.6.12" } } diff --git a/test.bundle.js b/test.bundle.js new file mode 100644 index 0000000..9ade857 --- /dev/null +++ b/test.bundle.js @@ -0,0 +1,47 @@ +'use strict'; + +/* eslint vars-on-top:0 no-var:0 */ +// @AngularClass +/* + * When testing with webpack and ES6, we have to do some extra + * things get testing to work right. Because we are gonna write test + * in ES6 to, we have to compile those as well. That's handled in + * karma.conf.js with the karma-webpack plugin. This is the entry + * file for webpack test. Just like webpack will create a bundle.js + * file for our client, when we run test, it well compile and bundle them + * all here! Crazy huh. So we need to do some setup + */ +Error.stackTraceLimit = Infinity; +require('phantomjs-polyfill'); +require('es6-promise'); +require('es6-shim'); +require('es7-reflect-metadata/dist/browser'); + +// require('zone.js'); +require('zone.js/dist/zone.js'); +require('zone.js/dist/long-stack-trace-zone.js'); +require('zone.js/dist/jasmine-patch.js'); +require('zone.js/dist/async-test.js'); + +var testing = require('@angular/core/testing'); +var browser = require('@angular/platform-browser-dynamic/testing'); + +testing.setBaseTestProviders( + browser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, + browser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS); + +/* + Ok, this is kinda crazy. We can use the the context method on + require that webpack created in order to tell webpack + what files we actually want to require or import. + Below, context will be an function/object with file names as keys. + using that regex we are saying look in ./src/app and ./test then find + any file that ends with spec.js and get its path. By passing in true + we say do this recursively + */ +var testContext = require.context('./components', true, /\.spec\.ts/); + +// get all the files, for each file, call the context function +// that will require the file and load it up here. Context will +// loop and require those spec files here +testContext.keys().forEach(testContext); diff --git a/tsconfig.json b/tsconfig.json index 6877115..bb6cb3b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,8 @@ { - "version": "1.7.5", "compilerOptions": { "target": "es5", "module": "commonjs", - "sourceMap": true, + "sourceMap": false, "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, diff --git a/tslint.json b/tslint.json index a412061..ea3f776 100644 --- a/tslint.json +++ b/tslint.json @@ -1,56 +1,4 @@ { - "rules": { - "class-name": true, - "comment-format": [true, "check-space"], - "curly": true, - "eofline": true, - "forin": true, - "indent": [true, "spaces"], - "label-position": true, - "label-undefined": true, - "max-line-length": [false, 140], - "no-arg": true, - "no-bitwise": true, - "no-console": [true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-debugger": true, - "no-duplicate-key": true, - "no-duplicate-variable": true, - "no-empty": false, - "no-eval": true, - "no-shadowed-variable": true, - "no-string-literal": true, - "no-switch-case-fall-through": true, - "no-trailing-comma": true, - "no-trailing-whitespace": true, - "no-unused-expression": true, - "no-unused-variable": false, - "no-unreachable": true, - "no-use-before-declare": true, - "no-var-keyword": true, - "one-line": [true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "quotemark": [true, "single"], - "radix": true, - "semicolon": true, - "sort-object-literal-keys": false, - "triple-equals": [true, "allow-null-check"], - "variable-name": false, - "whitespace": [true, - "check-branch", - "check-decl", - "check-operator", - "check-separator" - ] - } + "extends": "tslint-config-valorsoft", + "rulesDirectory": "./node_modules/codelyzer" } diff --git a/typings.json b/typings.json index da1bd79..592b524 100644 --- a/typings.json +++ b/typings.json @@ -1,6 +1,12 @@ { + "dependencies": { + "moment": "registry:npm/moment#2.10.5+20160211003958", + "webpack": "registry:npm/webpack#1.12.9+20160219013405" + }, + "devDependencies": {}, "ambientDependencies": { - "core-js": "registry:dt/core-js#0.0.0+20160317120654", - "node": "registry:dt/node#4.0.0+20160509154515" + "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654", + "jasmine": "registry:dt/jasmine#2.2.0+20160317120654", + "require": "registry:dt/require#2.1.20+20160316155526" } } diff --git a/webpack.config.js b/webpack.config.js index 47cd668..68c526b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,35 +1,35 @@ -var path = require('path'); -var marked = require('marked'); -var webpack = require('webpack'); +/* eslint global-require: 0 */ +'use strict'; -var Clean = require('clean-webpack-plugin'); -var CompressionPlugin = require('compression-webpack-plugin'); +const path = require('path'); +const marked = require('marked'); +const webpack = require('webpack'); +const reqPrism = require('prismjs'); +const CompressionPlugin = require('compression-webpack-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); // marked renderer hack -marked.Renderer.prototype.code = function (code, lang) { - var out = this.options.highlight(code, lang); +marked.Renderer.prototype.code = function renderCode(code, lang) { + const out = this.options.highlight(code, lang); + const classMap = this.options.langPrefix + lang; if (!lang) { - return '
' + out + '\n
'; + return `
${out}\n
`; } - - var classMap = this.options.langPrefix + lang; - return '
' + out + '\n
\n'; + return `
${out}\n
\n`; }; /*eslint no-process-env:0, camelcase:0*/ -var isProduction = (process.env.NODE_ENV || 'development') === 'production'; - -var src = 'demo'; -//var absSrc = path.join(__dirname, src); -var dest = '/build'; -var absDest = path.join(__dirname, dest); +const isProduction = (process.env.NODE_ENV || 'development') === 'production'; +const devtool = process.env.NODE_ENV === 'test' ? 'inline-source-map' : 'source-map'; +const dest = 'demo-build'; +const absDest = root(dest); -var config = { +const config = { // isProduction ? 'source-map' : 'evale', - devtool: 'source-map', - debug: true, - cache: true, + devtool, + debug: false, verbose: true, displayErrorDetails: true, @@ -40,15 +40,17 @@ var config = { }, resolve: { + cache: false, root: __dirname, - extensions: ['', '.ts', '.js', '.json'], - alias: {} + extensions: ['', '.ts', '.js', '.json'] }, entry: { angular2: [ // Angular 2 Deps - 'zone.js/dist/zone', + 'es6-shim', + 'es6-promise', + 'zone.js', 'reflect-metadata', '@angular/common', '@angular/core' @@ -69,20 +71,20 @@ var config = { inline: true, colors: true, historyApiFallback: true, - contentBase: src, - publicPath: dest + contentBase: dest, + //publicPath: dest, + outputPath: dest, + watchOptions: {aggregateTimeout: 300, poll: 1000} }, markdownLoader: { langPrefix: 'language-', - highlight: function (code, lang) { - var language = !lang || lang === 'html' ? 'markup' : lang; - if (!global.Prism) { - global.Prism = require('prismjs'); - } - var Prism = global.Prism; + highlight(code, lang) { + const language = !lang || lang === 'html' ? 'markup' : lang; + const Prism = global.Prism || reqPrism; + if (!Prism.languages[language]) { - require('prismjs/components/prism-' + language + '.js'); + require(`prismjs/components/prism-${language}.js`); } return Prism.highlight(code, Prism.languages[language]); } @@ -91,64 +93,65 @@ var config = { loaders: [ // support markdown {test: /\.md$/, loader: 'html?minimize=false!markdown'}, - // Support for *.json files. {test: /\.json$/, loader: 'json'}, - // Support for CSS as raw text {test: /\.css$/, loader: 'raw'}, - // support for .html as raw text {test: /\.html$/, loader: 'raw'}, - // Support for .ts files. { test: /\.ts$/, loader: 'ts', - exclude: [ - /\.min\.js$/, - /\.spec\.ts$/, - /\.e2e\.ts$/, - /web_modules/, - /test/ - ] + query: { + compilerOptions: { + removeComments: true, + noEmitHelpers: false + } + }, + exclude: [/\.(spec|e2e)\.ts$/] } ], noParse: [ /rtts_assert\/src\/rtts_assert/, - /reflect-metadata/ + /reflect-metadata/, + /zone\.js\/dist\/zone-microtask/ ] }, plugins: [ - new Clean(['build']), + //new Clean([dest]), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.OccurenceOrderPlugin(true), new webpack.optimize.CommonsChunkPlugin({ name: 'angular2', minChunks: Infinity, filename: 'angular2.js' }), - new webpack.optimize.DedupePlugin({ - __isProduction: isProduction - }), - new webpack.optimize.OccurenceOrderPlugin(), - new webpack.optimize.DedupePlugin() + // static assets + new CopyWebpackPlugin([{from: 'demo/favicon.ico', to: 'favicon.ico'}]), + new CopyWebpackPlugin([{from: 'demo/assets', to: 'assets'}]), + // generating html + new HtmlWebpackPlugin({template: 'demo/index.html'}) ], - pushPlugins: function () { + pushPlugins() { if (!isProduction) { return; } - - this.plugins.push.apply(this.plugins, [ + const plugins = [ //production only new webpack.optimize.UglifyJsPlugin({ + beautify: false, + mangle: false, + comments: false, compress: { - warnings: false, - drop_debugger: false - }, - output: { - comments: false - }, - beautify: false + screw_ie8: true + //warnings: false, + //drop_debugger: false + } + //verbose: true, + //beautify: false, + //quote_style: 3 }), new CompressionPlugin({ asset: '{file}.gz', @@ -157,10 +160,19 @@ var config = { threshold: 10240, minRatio: 0.8 }) - ]); + ]; + + this + .plugins + .push + .apply(plugins); } }; config.pushPlugins(); module.exports = config; + +function root(partialPath) { + return path.join(__dirname, partialPath); +}