├── .nvmrc
├── index.ts
├── karma.conf.js
├── bs-config.json
├── .npmignore
├── docs
├── index.html
├── main.ts
├── tsconfig.json
├── app.module.ts
├── app.component.ts
└── app.html
├── config
├── helpers.js
├── karma-test-shim.js
├── webpack.test.js
├── karma.conf.js
└── karma-require.js
├── .editorconfig
├── .vcmrc
├── src
├── focus.module.ts
├── focus.directive.ts
└── focus.directive.spec.ts
├── .travis.yml
├── .all-contributorsrc
├── tsconfig.json
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── .gitignore
├── LICENSE
├── tslint.json
├── wallaby.js
├── CODE_OF_CONDUCT.md
├── README.md
├── CONTRIBUTING.md
└── package.json
/.nvmrc:
--------------------------------------------------------------------------------
1 | 8
2 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | export * from './src/focus.module';
2 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./config/karma.conf.js');
2 |
--------------------------------------------------------------------------------
/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "./docs/**/*.{html,htm,css,js}"
4 | ],
5 | "server": {
6 | "baseDir": "./docs"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Node generated files
2 | node_modules
3 | npm-debug.log
4 |
5 | # OS generated files
6 | Thumbs.db
7 | .DS_Store
8 |
9 | # IDE generated files
10 | .idea
11 |
12 | # Demo
13 | docs
14 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | angular2-focus
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/config/helpers.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const _root = path.resolve(__dirname, '..');
3 | function root(args) {
4 | args = Array.prototype.slice.call(arguments, 0);
5 | return path.join.apply(path, [_root].concat(args));
6 | }
7 | exports.root = root;
8 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org/
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | [*.html]
14 | indent_size = 4
15 |
--------------------------------------------------------------------------------
/docs/main.ts:
--------------------------------------------------------------------------------
1 | import 'core-js/es7/reflect';
2 | import 'zone.js/dist/zone';
3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
4 | import { AppModule } from './app.module';
5 | import { enableProdMode } from '@angular/core';
6 | enableProdMode();
7 | const platform = platformBrowserDynamic();
8 | platform.bootstrapModule(AppModule);
9 |
--------------------------------------------------------------------------------
/.vcmrc:
--------------------------------------------------------------------------------
1 | {
2 | "helpMessage": "\nPlease fix your commit message (and consider using http://npm.im/commitizen)\n",
3 | "types": [
4 | "feat",
5 | "fix",
6 | "docs",
7 | "style",
8 | "refactor",
9 | "perf",
10 | "test",
11 | "chore",
12 | "revert",
13 | "custom"
14 | ],
15 | "warnOnFail": false,
16 | "autoFix": false
17 | }
18 |
--------------------------------------------------------------------------------
/src/focus.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ModuleWithProviders } from '@angular/core';
2 | import { FocusDirective } from './focus.directive';
3 |
4 | @NgModule({
5 | declarations: [FocusDirective],
6 | exports: [FocusDirective]
7 | })
8 | export class FocusModule {
9 | static forRoot(): ModuleWithProviders {
10 | return {
11 | ngModule: FocusModule
12 | };
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | cache: yarn
3 | branches:
4 | only:
5 | - master
6 | notifications:
7 | email: false
8 | script:
9 | - yarn lint
10 | - yarn test
11 | before_install:
12 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.3.2
13 | - export PATH=$HOME/.yarn/bin:$PATH
14 | after_success:
15 | - yarn travis-deploy-once "npm run semantic-release"
16 |
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "sourceMap": true,
8 | "inlineSources": true,
9 | "moduleResolution": "node",
10 | "declaration": true,
11 | "lib": ["es2017", "dom"]
12 | },
13 | "files": [
14 | "./main.ts",
15 | "./app.component.ts",
16 | "./app.module.ts"
17 | ],
18 | "exclude": [
19 | "node_modules"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "angular2-focus",
3 | "projectOwner": "spirosikmd",
4 | "files": [
5 | "README.md"
6 | ],
7 | "imageSize": 100,
8 | "commit": false,
9 | "contributors": [
10 | {
11 | "login": "spirosikmd",
12 | "name": "Spyros Ioakeimidis",
13 | "avatar_url": "https://avatars.githubusercontent.com/u/1057324?v=3",
14 | "profile": "http://www.spyros.io",
15 | "contributions": [
16 | "question",
17 | "code",
18 | "test"
19 | ]
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es5",
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "sourceMap": true,
8 | "inlineSources": true,
9 | "moduleResolution": "node",
10 | "declaration": true,
11 | "lib": ["es2017", "dom"]
12 | },
13 | "files": [
14 | "index.ts"
15 | ],
16 | "exclude": [
17 | "node_modules"
18 | ],
19 | "angularCompilerOptions": {
20 | "strictMetadataEmit": true,
21 | "skipTemplateCodegen": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/docs/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 | import { AppComponent } from './app.component';
4 | import { FocusModule } from '../index';
5 | import { ReactiveFormsModule } from '@angular/forms';
6 | import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
7 |
8 | @NgModule({
9 | imports: [
10 | BrowserModule,
11 | FocusModule.forRoot(),
12 | ReactiveFormsModule,
13 | NgbModule.forRoot()
14 | ],
15 | declarations: [AppComponent],
16 | bootstrap: [AppComponent]
17 | })
18 | export class AppModule {}
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/config/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | Error.stackTraceLimit = Infinity;
2 |
3 | require('core-js/es6');
4 | require('core-js/es7/reflect');
5 |
6 | require('zone.js/dist/zone');
7 | require('zone.js/dist/long-stack-trace-zone');
8 | require('zone.js/dist/proxy');
9 | require('zone.js/dist/sync-test');
10 | require('zone.js/dist/jasmine-patch');
11 | require('zone.js/dist/async-test');
12 | require('zone.js/dist/fake-async-test');
13 |
14 | const testing = require('@angular/core/testing');
15 | const browser = require('@angular/platform-browser-dynamic/testing');
16 |
17 | testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
18 |
19 | window.__karma__ && require('./karma-require');
20 |
--------------------------------------------------------------------------------
/config/webpack.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const helpers = require('./helpers');
3 |
4 | module.exports = {
5 | devtool: 'cheap-module-eval-source-map',
6 |
7 | resolve: {
8 | extensions: ['.ts', '.js']
9 | },
10 |
11 | module: {
12 | rules: [
13 | {
14 | test: /\.ts$/,
15 | loaders: ['awesome-typescript-loader']
16 | },
17 | ]
18 | },
19 |
20 | plugins: [
21 | new webpack.ContextReplacementPlugin(
22 | // The (\\|\/) piece accounts for path separators in *nix and Windows
23 | /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
24 | helpers.root('./src'), // location of your src
25 | {} // a map of your routes
26 | )
27 | ]
28 | };
29 |
--------------------------------------------------------------------------------
/config/karma.conf.js:
--------------------------------------------------------------------------------
1 | const webpackConfig = require('./webpack.test');
2 |
3 | module.exports = function(config) {
4 | const _config = {
5 | basePath: '',
6 |
7 | frameworks: ['jasmine'],
8 |
9 | files: [
10 | {pattern: './config/karma-test-shim.js', watched: false}
11 | ],
12 |
13 | preprocessors: {
14 | './config/karma-test-shim.js': ['webpack', 'sourcemap']
15 | },
16 |
17 | webpack: webpackConfig,
18 |
19 | webpackMiddleware: {
20 | stats: 'errors-only'
21 | },
22 |
23 | webpackServer: {
24 | noInfo: true
25 | },
26 |
27 | reporters: ['progress'],
28 | port: 9876,
29 | colors: true,
30 | logLevel: config.LOG_INFO,
31 | autoWatch: false,
32 | browsers: ['PhantomJS'],
33 | singleRun: true
34 | };
35 |
36 | config.set(_config);
37 | };
38 |
--------------------------------------------------------------------------------
/src/focus.directive.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Directive,
3 | ElementRef,
4 | Input,
5 | SimpleChanges,
6 | OnInit,
7 | OnChanges
8 | } from '@angular/core';
9 |
10 | @Directive({
11 | selector: '[focus]'
12 | })
13 | export class FocusDirective implements OnInit, OnChanges {
14 | @Input() focus: boolean;
15 | private element: HTMLElement;
16 |
17 | constructor($element: ElementRef) {
18 | this.element = $element.nativeElement;
19 | }
20 |
21 | ngOnInit(): void {
22 | if (this.focus) {
23 | this.focusElement();
24 | }
25 | }
26 |
27 | ngOnChanges(changes: SimpleChanges): void {
28 | const focus = changes.focus;
29 | if (
30 | focus.currentValue !== focus.previousValue &&
31 | focus.currentValue === true
32 | ) {
33 | this.focusElement();
34 | }
35 | }
36 |
37 | focusElement(): void {
38 | this.element.focus();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { FormControl, FormGroup } from '@angular/forms';
3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
4 |
5 | @Component({
6 | selector: 'app',
7 | templateUrl: 'app.html'
8 | })
9 | export class AppComponent {
10 | isFocused = true;
11 | sins = ['gluttony', 'greed', 'sloth', 'envy', 'wrath', 'pride', 'lust'];
12 |
13 | form = new FormGroup({
14 | sin: new FormControl(),
15 | name: new FormControl()
16 | });
17 |
18 | constructor(private modalService: NgbModal) {}
19 |
20 | open(content) {
21 | this.modalService.open(content).result.then(
22 | result => {
23 | console.log(`Closed with: ${result}`);
24 | },
25 | reason => {
26 | console.log(`Dismissed ${reason}`);
27 | }
28 | );
29 | }
30 |
31 | toggleFocus() {
32 | this.isFocused = !this.isFocused;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/config/karma-require.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Ok, this is kinda crazy. We can use the context method on
3 | * require that webpack created in order to tell webpack
4 | * what files we actually want to require or import.
5 | * Below, context will be a function/object with file names as keys.
6 | * Using that regex we are saying look in ../src then find
7 | * any file that ends with spec.ts and get its path. By passing in true
8 | * we say do this recursively
9 | */
10 | const testContext = require.context('../src', true, /\.spec\.ts/);
11 |
12 | /*
13 | * get all the files, for each file, call the context function
14 | * that will require the file and load it up here. Context will
15 | * loop and require those spec files here
16 | */
17 | function requireAll(requireContext) {
18 | return requireContext.keys().map(requireContext);
19 | }
20 |
21 | // requires and returns all modules that match
22 | const modules = requireAll(testContext);
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Node template
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 |
13 | # Directory for instrumented libs generated by jscoverage/JSCover
14 | lib-cov
15 |
16 | # Coverage directory used by tools like istanbul
17 | coverage
18 |
19 | # nyc test coverage
20 | .nyc_output
21 |
22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
23 | .grunt
24 |
25 | # node-waf configuration
26 | .lock-wscript
27 |
28 | # Compiled binary addons (http://nodejs.org/api/addons.html)
29 | build/Release
30 |
31 | # Dependency directories
32 | node_modules
33 | jspm_packages
34 |
35 | # Optional npm cache directory
36 | .npm
37 |
38 | # Optional REPL history
39 | .node_repl_history
40 |
41 | # Compiled angular 2 files
42 | aot
43 |
44 | # Generated compiled source files
45 | index.js
46 | index.js.map
47 | src/*.js
48 | src/*.js.map
49 | *.d.ts
50 | *.metadata.json
51 |
52 | # Exclude the bundle demo file
53 | !docs/bundle.js
54 |
55 | # Generated build
56 | dist
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "comment-format": [
5 | true,
6 | "check-space"
7 | ],
8 | "indent": [
9 | true,
10 | "spaces"
11 | ],
12 | "no-duplicate-variable": true,
13 | "no-eval": true,
14 | "no-internal-module": true,
15 | "no-trailing-whitespace": true,
16 | "no-unsafe-finally": true,
17 | "no-var-keyword": true,
18 | "one-line": [
19 | true,
20 | "check-open-brace",
21 | "check-whitespace"
22 | ],
23 | "quotemark": [
24 | true,
25 | "single"
26 | ],
27 | "semicolon": [
28 | true,
29 | "always"
30 | ],
31 | "triple-equals": [
32 | true,
33 | "allow-null-check"
34 | ],
35 | "typedef-whitespace": [
36 | true,
37 | {
38 | "call-signature": "nospace",
39 | "index-signature": "nospace",
40 | "parameter": "nospace",
41 | "property-declaration": "nospace",
42 | "variable-declaration": "nospace"
43 | }
44 | ],
45 | "variable-name": [
46 | true,
47 | "ban-keywords"
48 | ],
49 | "whitespace": [
50 | true,
51 | "check-branch",
52 | "check-decl",
53 | "check-operator",
54 | "check-separator",
55 | "check-type"
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/wallaby.js:
--------------------------------------------------------------------------------
1 | const wallabyWebpack = require('wallaby-webpack');
2 |
3 | // if you use the webpack defined variable ENV in any components
4 | const DefinePlugin = require('webpack/lib/DefinePlugin');
5 | const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
6 |
7 | const webpackPostprocessor = wallabyWebpack({
8 | entryPatterns: [
9 | 'config/karma-test-shim.js',
10 | 'src/**/*spec.js',
11 | ],
12 |
13 | module: {
14 | rules: [
15 | {test: /\.json$/, loader: 'json-loader'},
16 | {test: /karma-require/, loader: 'null-loader'},
17 | ]
18 | },
19 | plugins: [
20 | new DefinePlugin({
21 | 'ENV': JSON.stringify(ENV)
22 | })
23 | ]
24 | });
25 |
26 | module.exports = function() {
27 |
28 | return {
29 | files: [
30 | {pattern: 'config/karma-test-shim.js', load: false},
31 | {pattern: 'config/karma-require.js', load: false},
32 | {pattern: 'src/**/*.ts', load: false},
33 | {pattern: 'src/**/*.json', load: false},
34 | {pattern: 'src/**/*spec.ts', ignore: true},
35 | {pattern: 'src/**/*.d.ts', ignore: true}
36 | ],
37 |
38 | tests: [
39 | {pattern: 'src/**/*spec.ts', load: false},
40 | ],
41 |
42 | testFramework: 'jasmine',
43 |
44 | postprocessor: webpackPostprocessor,
45 |
46 | setup: function() {
47 | window.__moduleBundler.loadTests();
48 | },
49 |
50 | debug: true
51 | };
52 | };
53 |
--------------------------------------------------------------------------------
/docs/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Using angumar forms
4 |
16 |
17 |
Form value: {{ form.value | json }}
18 |
19 |
20 |
21 |
Using bootstrap modal
22 |
23 |
24 |
25 |
Modal title
26 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4 |
5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6 |
7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8 |
9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10 |
11 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
12 |
13 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
14 |
15 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
16 |
--------------------------------------------------------------------------------
/src/focus.directive.spec.ts:
--------------------------------------------------------------------------------
1 | import { FocusDirective } from './focus.directive';
2 | import { ElementRef } from '@angular/core';
3 |
4 | describe('focus', function() {
5 | beforeEach(function() {
6 | this.elementRef = {
7 | nativeElement: jasmine.createSpyObj('nativeElement', ['focus'])
8 | };
9 | this.directive = new FocusDirective(this.elementRef);
10 | });
11 |
12 | describe('ngOnInit', function() {
13 | beforeEach(function() {
14 | spyOn(this.directive, 'focusElement');
15 | });
16 |
17 | it('does not call focusElement when focus is false', function() {
18 | this.directive.ngOnInit();
19 | expect(this.directive.focusElement).not.toHaveBeenCalled();
20 | });
21 |
22 | it('calls focusElement when focus is true', function() {
23 | this.directive.focus = true;
24 | this.directive.ngOnInit();
25 | expect(this.directive.focusElement).toHaveBeenCalled();
26 | });
27 | });
28 |
29 | describe('ngOnChanges', function() {
30 | beforeEach(function() {
31 | spyOn(this.directive, 'focusElement');
32 | });
33 |
34 | it('calls focusElement when focus current value is true and previous is false', function() {
35 | this.directive.ngOnChanges({
36 | focus: {
37 | previousValue: false,
38 | currentValue: true
39 | }
40 | });
41 | expect(this.directive.focusElement).toHaveBeenCalled();
42 | });
43 |
44 | it('does not call focusElement when focus current value is false', function() {
45 | this.directive.ngOnChanges({
46 | focus: {
47 | previousValue: true,
48 | currentValue: false
49 | }
50 | });
51 | expect(this.directive.focusElement).not.toHaveBeenCalled();
52 | });
53 |
54 | it('does not call focusElement when focus current value is same as previous value', function() {
55 | this.directive.ngOnChanges({
56 | focus: {
57 | previousValue: true,
58 | currentValue: true
59 | }
60 | });
61 | expect(this.directive.focusElement).not.toHaveBeenCalled();
62 | });
63 | });
64 |
65 | describe('focusElement', function() {
66 | it('calls focus on element ', function() {
67 | this.directive.focusElement();
68 | expect(this.elementRef.nativeElement.focus).toHaveBeenCalled();
69 | });
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular2-focus
2 |
3 | Angular attribute directive that gives focus on an element depending on a given expression.
4 |
5 | [![Build Status][build-badge]][build]
6 | [![version][version-badge]][package]
7 | [![PRs Welcome][prs-badge]](http://makeapullrequest.com)
8 | [![All Contributors][all-contributors-badge]](#contributors)
9 | [![Greenkeeper badge][greenkeeper-badge]](https://greenkeeper.io/)
10 |
11 | ## Install
12 |
13 | `npm install --save angular2-focus`
14 |
15 | ## Example
16 |
17 | ```typescript
18 | import {NgModule, Component} from '@angular/core';
19 | import {FocusModule} from 'angular2-focus';
20 |
21 | @Component({
22 | template: `
23 |
24 | `
25 | })
26 | class AppComponent { }
27 |
28 | @NgModule({
29 | imports: [FocusModule.forRoot()],
30 | declarations: [AppComponent],
31 | bootstrap: [AppComponent]
32 | })
33 | export class AppModule { }
34 | ```
35 |
36 | Check the [docs](docs) for examples using `@angular/forms` and other third party libraries such as
37 | `@ng-bootstrap/ng-bootstrap`, to focus elements when e.g. using a modal.
38 |
39 | ## Contributors
40 |
41 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
42 |
43 |
44 | | [
Spyros Ioakeimidis](http://www.spyros.io)
💬 [💻](https://github.com/spirosikmd/angular2-focus/commits?author=spirosikmd) [⚠️](https://github.com/spirosikmd/angular2-focus/commits?author=spirosikmd) |
45 | | :---: |
46 |
47 |
48 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification.
49 | Contributions of any kind welcome!
50 |
51 | [version-badge]: https://img.shields.io/npm/v/angular2-focus.svg?style=flat-square
52 | [package]: https://www.npmjs.com/package/angular2-focus
53 | [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
54 | [build-badge]: https://img.shields.io/travis/spirosikmd/angular2-focus.svg?style=flat-square
55 | [build]: https://travis-ci.org/spirosikmd/angular2-focus.svg
56 | [all-contributors-badge]: https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square
57 | [greenkeeper-badge]: https://badges.greenkeeper.io/spirosikmd/angular2-focus.svg
58 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thanks for being willing to contribute!
4 |
5 | **Working on your first Pull Request?** You can learn how from this *free* series
6 | [How to Contribute to an Open Source Project on GitHub][egghead]
7 |
8 | ## Project setup
9 |
10 | You're going to need [`git`](https://git-scm.com/) to get the project, and [`node`](https://nodejs.org/en/) and
11 | [`yarn`](https://yarnpkg.com/) to install dependencies and run scripts.
12 |
13 | 1. Fork and clone the repo
14 | 2. Run `yarn` to install dependencies
15 | 3. Run `yarn test` for testing
16 | 4. Run `yarn lint` for linting
17 | 5. Run `yarn start` to compile
18 | 6. Run `yarn docs` to test the directive using the example project
19 | 7. Create a branch for your PR
20 |
21 | ## Add yourself as a contributor
22 |
23 | This project follows the [all contributors][all-contributors] specification. To add yourself to the table of
24 | contributors on the README.md, please use the automated script as part of your PR:
25 |
26 | ```console
27 | yarn add-contributor
28 | ```
29 |
30 | Follow the prompt. If you've already added yourself to the list and are making a new type of contribution, you can run
31 | it again and select the added contribution type.
32 |
33 | ## Committing and Pushing changes
34 |
35 | This project uses [`semantic-release`][semantic-release] to do automatic releases and generate a changelog based on the
36 | commit history. So we follow [a convention][convention] for commit messages. Please follow this convention for your
37 | commit messages.
38 |
39 | You can use `commitizen` to help you to follow [the convention][convention]
40 |
41 | Once you are ready to commit the changes, please use the below commands
42 |
43 | 1. Run `git add ` to stage changed files
44 | 2. Run `yarn commit` to start commitizen to commit those files
45 |
46 | ... and follow the instruction of the interactive prompt.
47 |
48 | ## Help needed
49 |
50 | Please checkout [the issues](https://github.com/spirosikmd/angular2-focus/issues)! Also, please watch the repo
51 | and respond to questions/bug reports/feature requests! Thanks!
52 |
53 | [egghead]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
54 | [semantic-release]: https://npmjs.com/package/semantic-release
55 | [convention]: https://github.com/conventional-changelog/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
56 | [all-contributors]: https://github.com/kentcdodds/all-contributors
57 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular2-focus",
3 | "version": "0.0.0-development",
4 | "description": "Angular attribute directive that gives focus on an element depending on a given expression",
5 | "main": "dist/bundles/angular2-focus.umd.js",
6 | "module": "dist/angular2-focus.es5.js",
7 | "es2015": "dist/angular2-focus.js",
8 | "typings": "dist/angular2-focus.d.ts",
9 | "scripts": {
10 | "test": "karma start",
11 | "lint": "tslint -c tslint.json 'index.ts src/**/*.ts docs/**/*.ts'",
12 | "start": "ngc",
13 | "build": "ng-packagr -p package.json",
14 | "prepare": "yarn build",
15 | "docs": "concurrently \"watchify docs/main.ts -p [ tsify ] -o docs/bundle.js\" \"lite-server\"",
16 | "semantic-release": "semantic-release",
17 | "commit": "git-cz",
18 | "add-contributor": "all-contributors add",
19 | "generate-contributors": "all-contributors generate",
20 | "precommit": "lint-staged",
21 | "travis-deploy-once": "travis-deploy-once"
22 | },
23 | "keywords": [
24 | "angular",
25 | "angular2",
26 | "@angular",
27 | "focus"
28 | ],
29 | "author": "Spyros Ioakeimidis (http://www.spyros.io)",
30 | "license": "MIT",
31 | "devDependencies": {
32 | "@angular/animations": "^6.1.1",
33 | "@angular/common": "^6.1.1",
34 | "@angular/compiler": "^6.1.1",
35 | "@angular/compiler-cli": "^6.1.1",
36 | "@angular/core": "^6.1.1",
37 | "@angular/forms": "^6.1.1",
38 | "@angular/platform-browser": "^6.1.1",
39 | "@angular/platform-browser-dynamic": "^6.1.1",
40 | "@angular/platform-server": "^6.1.1",
41 | "@ng-bootstrap/ng-bootstrap": "^2.2.0",
42 | "@types/core-js": "^2.5.0",
43 | "@types/jasmine": "^2.5.47",
44 | "all-contributors-cli": "^4.3.0",
45 | "awesome-typescript-loader": "^3.1.3",
46 | "browserify": "^14.3.0",
47 | "commitizen": "^2.9.6",
48 | "concurrently": "^3.5.0",
49 | "core-js": "^2.4.1",
50 | "cz-conventional-changelog": "^2.0.0",
51 | "husky": "^0.14.0",
52 | "jasmine-core": "^2.6.1",
53 | "karma": "^1.7.0",
54 | "karma-jasmine": "^1.1.0",
55 | "karma-phantomjs-launcher": "^1.0.4",
56 | "karma-sourcemap-loader": "^0.3.7",
57 | "karma-webpack": "^2.0.3",
58 | "lint-staged": "^7.2.0",
59 | "lite-server": "^2.3.0",
60 | "ng-packagr": "^1.6.0",
61 | "null-loader": "^0.1.1",
62 | "prettier": "^1.4.2",
63 | "rxjs": "^6.2.2",
64 | "semantic-release": "^15.7.1",
65 | "travis-deploy-once": "^5.0.1",
66 | "tsify": "^3.0.1",
67 | "tslint": "^5.0.0",
68 | "typescript": "~2.9.2",
69 | "wallaby-webpack": "^3.9.4",
70 | "watchify": "^3.7.0",
71 | "webpack": "^3.0.0",
72 | "zone.js": "^0.8.26"
73 | },
74 | "repository": {
75 | "type": "git",
76 | "url": "https://github.com/spirosikmd/angular2-focus"
77 | },
78 | "config": {
79 | "commitizen": {
80 | "path": "node_modules/cz-conventional-changelog"
81 | }
82 | },
83 | "lint-staged": {
84 | "*.ts": [
85 | "prettier --single-quote --write",
86 | "git add"
87 | ]
88 | },
89 | "ngPackage": {
90 | "lib": {
91 | "entryFile": "index.ts"
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------