├── .gitignore
├── .npmignore
├── .travis.yml
├── .yo-rc.json
├── LICENSE
├── README.MD
├── bs-config.json
├── gulpfile.js
├── package.json
├── playground
├── index.html
├── index.ts
├── systemjs-angular-loader.js
├── systemjs.config.js
└── tsconfig.json
├── src
├── index.ts
├── package.json
├── timezone-picker.component.spec.ts
├── timezone-picker.component.ts
├── timezone-picker.pipe.ts
├── timezone-picker.service.ts
├── tsconfig.es5.json
└── tsconfig.spec.json
├── tools
└── gulp
│ └── inline-resources.js
├── tsconfig.json
└── tslint.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 |
5 | # TypeScript
6 | src/*.js
7 | src/*.map
8 | src/*.d.ts
9 |
10 | # JetBrains
11 | .idea
12 | .project
13 | .settings
14 | .idea/*
15 | *.iml
16 |
17 | # VS Code
18 | .vscode/*
19 |
20 | # Windows
21 | Thumbs.db
22 | Desktop.ini
23 |
24 | # Mac
25 | .DS_Store
26 | **/.DS_Store
27 |
28 | # Ngc generated files
29 | **/*.ngfactory.ts
30 |
31 | # Build files
32 | dist/*
33 | docs/*
34 | ng2-demo-app/*
35 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Node
2 | node_modules/*
3 | npm-debug.log
4 | docs/*
5 | # DO NOT IGNORE TYPESCRIPT FILES FOR NPM
6 | # TypeScript
7 | # *.js
8 | # *.map
9 | # *.d.ts
10 |
11 | # JetBrains
12 | .idea
13 | .project
14 | .settings
15 | .idea/*
16 | *.iml
17 |
18 | # VS Code
19 | .vscode/*
20 |
21 | # Windows
22 | Thumbs.db
23 | Desktop.ini
24 |
25 | # Mac
26 | .DS_Store
27 | **/.DS_Store
28 |
29 | # Ngc generated files
30 | **/*.ngfactory.ts
31 |
32 | # Library files
33 | src/*
34 | build/*
35 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - '4.2.1'
5 |
--------------------------------------------------------------------------------
/.yo-rc.json:
--------------------------------------------------------------------------------
1 | {
2 | "generator-angular2-library": {
3 | "promptValues": {
4 | "gitRepositoryUrl": "https://github.com/samuelnygaard/ng2-timezone-selector"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Samuel Nygaard
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # ng2-timezone-selector
2 |
3 | A simple Angular module to create a timezone selector using [moment-timezones](https://github.com/moment/moment-timezone).
4 |
5 | ## [Demo](https://samuelnygaard.github.io/ng2-timezone-selector/) | [Documentation](https://samuelnygaard.github.io/ng2-timezone-selector/docs/)
6 |
7 | ## New features (0.2.3)
8 |
9 | * Guess the timezone based on browser settings, usage:
10 | * ``
11 | * Show GMT offset (equivalent with UTC offset), e.g.: `Denmark (GTM+01:00)`, usage:
12 | * ``
13 | * Select timezone based on country iso code and outputs country iso code based on timezone, usage:
14 | * ``
15 |
16 | ## Installation
17 |
18 | To install this library, run:
19 |
20 | ```bash
21 | $ npm install ng2-timezone-selector --save
22 | ```
23 |
24 | ### Requirements (IMPORTANT, use one of the following methods)
25 |
26 | The library depent on [jQuery](https://github.com/jquery/jquery) and [select2](https://github.com/select2/select2) and [moment-timezone](https://github.com/moment/moment-timezone)
27 |
28 | The only file required is the select2 `select2.min.css` file:
29 |
30 | #### 1. Method (should work for all)
31 |
32 | Include the `select2.min.css` file in the `angular-cli.json` file (remember to re-run `ng serve`, after editing `angular-cli.json`):
33 |
34 | ```json
35 | {
36 | "project": {
37 | ...
38 | },
39 | "apps": [
40 | {
41 | ...
42 | "styles": [
43 | "styles.scss",
44 | "../node_modules/select2/dist/css/select2.min.css"
45 | ],
46 | ...
47 | }
48 | ```
49 |
50 | #### 2. Method (simplest)
51 |
52 | If the angular project is setup to use `*.scss` instead of `*.css`, then you can add the following `@import` to the default `*.scss` file, othen called: `styles.scss`:
53 |
54 | ```scss
55 | @import '~select2/dist/css/select2.min.css';
56 | ```
57 |
58 | #### 3. Method (HTML-link)
59 |
60 | Include the `css` resource from a CDN link in the `index.html` file:
61 |
62 | ```xml
63 |
64 | ...
65 |
66 | ...
67 |
68 | ```
69 |
70 | ### Importing
71 |
72 | Import the module in `app.module.ts`:
73 |
74 | ```typescript
75 | import { BrowserModule } from '@angular/platform-browser';
76 | import { NgModule } from '@angular/core';
77 |
78 | import { AppComponent } from './app.component';
79 |
80 | // Import the library
81 | import { TimezonePickerModule } from 'ng2-timezone-selector';
82 |
83 | @NgModule({
84 | declarations: [
85 | AppComponent
86 | ],
87 | imports: [
88 | BrowserModule,
89 | ...,
90 | // Include the library in the imports section
91 | TimezonePickerModule
92 | ],
93 | providers: [],
94 | bootstrap: [AppComponent]
95 | })
96 | export class AppModule { }
97 | ```
98 |
99 | ## Usage
100 |
101 | Once the library is imported, you can use the component in your Angular application:
102 |
103 | ```xml
104 |
106 |
109 |
110 | ```
111 |
112 | ```xml
113 |
115 |
121 |
122 | ```
123 |
124 | ```typescript
125 | // Example of usage in app.component.ts:
126 | user = {};
127 | placeholderString = 'Select timezone';
128 |
129 | changeTimezone(timezone) {
130 | this.user.timezone = timezone;
131 | }
132 | ```
133 |
134 | ## Parameters
135 |
136 | ### Component configuration
137 |
138 | You can configure component with the following input attributes:
139 |
140 | * `timezone: string` - Required: must be defined. The timezone string. If you are using the Two-Way Data Binding `[(timezone)]="timezoneString"` it will change on selection of timezone.
141 | * `placeholder: string` - Optional: default = `''`. The placeholder string to show when no timezone is selected.
142 | * `disabled: boolean` - Optional: default = `false`. Disable the the component.
143 | * `showOffset: boolean` - Optional: default = `false`. Condition to show GMT offset in the dropdown.
144 | * `guess: boolean` - Optional: default = `false`. If set to `true` and if the `timezone` parameters is `null` or `undefined` then guesses the users timezone.
145 | * `country: string` - Optional. The country iso-string (e.g. `'US'` / `'GB'` / `'AU'`). If you are using the Two-Way Data Binding e.g.: `[(country)]="countryIsoCode"` it will change the timezone to the provided iso-code (if the iso code is valid), and if the timezone is changed it changes the value of `countryIsoCode` to the iso of the country.
146 | * `allowClear: boolean` - Optional: default = `false`. Enabled you to clear the selection of a timezone.
147 |
148 | You can configure component with the `(change)="changeFunction($event)` or `(countryChange)="countryIsoCode = $event` output attributes:
149 |
150 | * `change: function($event)` - Trigger-function when timezone is selected or changed, the `$event` parameter is the timezone string.
151 | * `countryChange: function($event: string)` - Trigger-function when timezone is changed, the `$event` parameter is the country iso-code.
152 |
153 | ## License
154 |
155 | MIT © [Samuel Nygaard](mailto:teamnygaard@gmail.com)
156 |
--------------------------------------------------------------------------------
/bs-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "server": {
3 | "baseDir": "src",
4 | "routes": {
5 | "/": "playground",
6 | "/node_modules/": "node_modules",
7 | "/dist/": "dist",
8 | "/.playground": ".playground"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var gulp = require('gulp'),
3 | path = require('path'),
4 | ngc = require('@angular/compiler-cli/src/main').main,
5 | rollup = require('gulp-rollup'),
6 | rename = require('gulp-rename'),
7 | del = require('del'),
8 | runSequence = require('run-sequence'),
9 | inlineResources = require('./tools/gulp/inline-resources');
10 |
11 | const rootFolder = path.join(__dirname);
12 | const srcFolder = path.join(rootFolder, 'src');
13 | const tmpFolder = path.join(rootFolder, '.tmp');
14 | const buildFolder = path.join(rootFolder, 'build');
15 | const distFolder = path.join(rootFolder, 'dist');
16 |
17 | /**
18 | * 1. Delete /dist folder
19 | */
20 | gulp.task('clean:dist', function () {
21 |
22 | // Delete contents but not dist folder to avoid broken npm links
23 | // when dist directory is removed while npm link references it.
24 | return deleteFolders([distFolder + '/**', '!' + distFolder]);
25 | });
26 |
27 | /**
28 | * 2. Clone the /src folder into /.tmp. If an npm link inside /src has been made,
29 | * then it's likely that a node_modules folder exists. Ignore this folder
30 | * when copying to /.tmp.
31 | */
32 | gulp.task('copy:source', function () {
33 | return gulp.src([`${srcFolder}/**/*`, `!${srcFolder}/node_modules`])
34 | .pipe(gulp.dest(tmpFolder));
35 | });
36 |
37 | /**
38 | * 3. Inline template (.html) and style (.css) files into the the component .ts files.
39 | * We do this on the /.tmp folder to avoid editing the original /src files
40 | */
41 | gulp.task('inline-resources', function () {
42 | return Promise.resolve()
43 | .then(() => inlineResources(tmpFolder));
44 | });
45 |
46 |
47 | /**
48 | * 4. Run the Angular compiler, ngc, on the /.tmp folder. This will output all
49 | * compiled modules to the /build folder.
50 | *
51 | * As of Angular 5, ngc accepts an array and no longer returns a promise.
52 | */
53 | gulp.task('ngc', function () {
54 | ngc([ '--project', `${tmpFolder}/tsconfig.es5.json` ]);
55 | return Promise.resolve()
56 | });
57 |
58 | /**
59 | * 5. Run rollup inside the /build folder to generate our Flat ES module and place the
60 | * generated file into the /dist folder
61 | */
62 | gulp.task('rollup:fesm', function () {
63 | return gulp.src(`${buildFolder}/**/*.js`)
64 | // transform the files here.
65 | .pipe(rollup({
66 |
67 | // Bundle's entry point
68 | // See "input" in https://rollupjs.org/#core-functionality
69 | input: `${buildFolder}/index.js`,
70 |
71 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
72 | // accessed by Rollup or produced by plugins further down the chain.
73 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
74 | // when subdirectories are used in the `src` directory.
75 | allowRealFiles: true,
76 |
77 | // A list of IDs of modules that should remain external to the bundle
78 | // See "external" in https://rollupjs.org/#core-functionality
79 | external: [
80 | '@angular/core',
81 | '@angular/common'
82 | ],
83 |
84 | // Format of generated bundle
85 | // See "format" in https://rollupjs.org/#core-functionality
86 | format: 'es'
87 | }))
88 | .pipe(gulp.dest(distFolder));
89 | });
90 |
91 | /**
92 | * 6. Run rollup inside the /build folder to generate our UMD module and place the
93 | * generated file into the /dist folder
94 | */
95 | gulp.task('rollup:umd', function () {
96 | return gulp.src(`${buildFolder}/**/*.js`)
97 | // transform the files here.
98 | .pipe(rollup({
99 |
100 | // Bundle's entry point
101 | // See "input" in https://rollupjs.org/#core-functionality
102 | input: `${buildFolder}/index.js`,
103 |
104 | // Allow mixing of hypothetical and actual files. "Actual" files can be files
105 | // accessed by Rollup or produced by plugins further down the chain.
106 | // This prevents errors like: 'path/file' does not exist in the hypothetical file system
107 | // when subdirectories are used in the `src` directory.
108 | allowRealFiles: true,
109 |
110 | // A list of IDs of modules that should remain external to the bundle
111 | // See "external" in https://rollupjs.org/#core-functionality
112 | external: [
113 | '@angular/core',
114 | '@angular/common'
115 | ],
116 |
117 | // Format of generated bundle
118 | // See "format" in https://rollupjs.org/#core-functionality
119 | format: 'umd',
120 |
121 | // Export mode to use
122 | // See "exports" in https://rollupjs.org/#danger-zone
123 | exports: 'named',
124 |
125 | // The name to use for the module for UMD/IIFE bundles
126 | // (required for bundles with exports)
127 | // See "name" in https://rollupjs.org/#core-functionality
128 | name: 'ng2-timezone-selector',
129 |
130 | // See "globals" in https://rollupjs.org/#core-functionality
131 | globals: {
132 | typescript: 'ts'
133 | }
134 |
135 | }))
136 | .pipe(rename('ng2-timezone-selector.umd.js'))
137 | .pipe(gulp.dest(distFolder));
138 | });
139 |
140 | /**
141 | * 7. Copy all the files from /build to /dist, except .js files. We ignore all .js from /build
142 | * because with don't need individual modules anymore, just the Flat ES module generated
143 | * on step 5.
144 | */
145 | gulp.task('copy:build', function () {
146 | return gulp.src([`${buildFolder}/**/*`, `!${buildFolder}/**/*.js`])
147 | .pipe(gulp.dest(distFolder));
148 | });
149 |
150 | /**
151 | * 8. Copy package.json from /src to /dist
152 | */
153 | gulp.task('copy:manifest', function () {
154 | return gulp.src([`${srcFolder}/package.json`])
155 | .pipe(gulp.dest(distFolder));
156 | });
157 |
158 | /**
159 | * 9. Copy README.md from / to /dist
160 | */
161 | gulp.task('copy:readme', function () {
162 | return gulp.src([path.join(rootFolder, 'README.MD')])
163 | .pipe(gulp.dest(distFolder));
164 | });
165 |
166 | /**
167 | * 10. Delete /.tmp folder
168 | */
169 | gulp.task('clean:tmp', function () {
170 | return deleteFolders([tmpFolder]);
171 | });
172 |
173 | /**
174 | * 11. Delete /build folder
175 | */
176 | gulp.task('clean:build', function () {
177 | return deleteFolders([buildFolder]);
178 | });
179 |
180 | gulp.task('compile', function () {
181 | runSequence(
182 | 'clean:dist',
183 | 'copy:source',
184 | 'inline-resources',
185 | 'ngc',
186 | 'rollup:fesm',
187 | 'rollup:umd',
188 | 'copy:build',
189 | 'copy:manifest',
190 | 'copy:readme',
191 | 'clean:build',
192 | 'clean:tmp',
193 | function (err) {
194 | if (err) {
195 | console.log('ERROR:', err.message);
196 | deleteFolders([distFolder, tmpFolder, buildFolder]);
197 | } else {
198 | console.log('Compilation finished succesfully');
199 | }
200 | });
201 | });
202 |
203 | /**
204 | * Watch for any change in the /src folder and compile files
205 | */
206 | gulp.task('watch', function () {
207 | gulp.watch(`${srcFolder}/**/*`, ['compile']);
208 | });
209 |
210 | gulp.task('clean', ['clean:dist', 'clean:tmp', 'clean:build']);
211 |
212 | gulp.task('build', ['clean', 'compile']);
213 | gulp.task('build:watch', ['build', 'watch']);
214 | gulp.task('default', ['build:watch']);
215 |
216 | /**
217 | * Deletes the specified folder
218 | */
219 | function deleteFolders(folders) {
220 | return del(folders);
221 | }
222 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-timezone-selector",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "build": "gulp build",
6 | "build:watch": "gulp",
7 | "docs": "npm run docs:build",
8 | "docs:build":
9 | "compodoc -p tsconfig.json -n ng2-timezone-selector -d docs --hideGenerator",
10 | "docs:serve": "npm run docs:build -- -s",
11 | "docs:watch": "npm run docs:build -- -s -w",
12 | "lint": "tslint --type-check --project tsconfig.json src/**/*.ts",
13 | "lite": "lite-server",
14 | "playground:build": "tsc -p playground -w",
15 | "playground":
16 | "concurrently \"npm run build:watch\" \"npm run playground:build\" \"npm run lite\"",
17 | "test": "tsc && karma start"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/samuelnygaard/ng2-timezone-selector"
22 | },
23 | "author": {
24 | "name": "Samuel Nygaard",
25 | "email": "teamnygaard@gmail.com"
26 | },
27 | "keywords": ["angular"],
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/samuelnygaard/ng2-timezone-selector/issues"
31 | },
32 | "devDependencies": {
33 | "@angular/common": "^5.0.0",
34 | "@angular/compiler": "^5.0.0",
35 | "@angular/compiler-cli": "^5.0.0",
36 | "@angular/core": "^5.0.0",
37 | "@angular/platform-browser": "^5.0.0",
38 | "@angular/platform-browser-dynamic": "^5.0.0",
39 | "@compodoc/compodoc": "^1.0.0-beta.10",
40 | "@types/jasmine": "2.5.53",
41 | "@types/node": "~6.0.60",
42 | "angular-in-memory-web-api": "^0.3.2",
43 | "codelyzer": "~3.2.0",
44 | "concurrently": "^3.4.0",
45 | "core-js": "^2.4.1",
46 | "del": "^2.2.2",
47 | "gulp": "^3.9.1",
48 | "gulp-rename": "^1.2.2",
49 | "gulp-rollup": "^2.15.0",
50 | "jasmine-core": "~2.6.2",
51 | "jasmine-spec-reporter": "~4.1.0",
52 | "karma": "~1.7.0",
53 | "karma-chrome-launcher": "~2.1.1",
54 | "karma-cli": "~1.0.1",
55 | "karma-coverage-istanbul-reporter": "^1.2.1",
56 | "karma-jasmine": "~1.1.0",
57 | "karma-jasmine-html-reporter": "^0.2.2",
58 | "lite-server": "^2.3.0",
59 | "node-sass": "^4.5.2",
60 | "node-sass-tilde-importer": "^1.0.0",
61 | "node-watch": "^0.5.2",
62 | "protractor": "~5.1.2",
63 | "rollup": "^0.49.3",
64 | "run-sequence": "^1.2.2",
65 | "rxjs": "^5.5.2",
66 | "systemjs": "^0.20.12",
67 | "ts-node": "~3.2.0",
68 | "tslint": "~5.7.0",
69 | "typescript": "~2.4.2",
70 | "zone.js": "^0.8.14"
71 | },
72 | "engines": {
73 | "node": ">=6.0.0"
74 | },
75 | "dependencies": {
76 | "jquery": "^3.3.1",
77 | "moment-timezone": "^0.5.14",
78 | "select2": "^4.0.6-rc.1"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ng2-timezone-selector Playground
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 | Loading AppComponent content here ...
31 |
32 |
33 |
--------------------------------------------------------------------------------
/playground/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is only for local test
3 | */
4 | import { BrowserModule } from '@angular/platform-browser';
5 | import { NgModule } from '@angular/core';
6 | import { Component } from '@angular/core';
7 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
8 |
9 | import { TimezonePickerModule } from '../dist';
10 |
11 | @Component({
12 | selector: 'app',
13 | template: ``
14 | })
15 | class AppComponent {}
16 |
17 | @NgModule({
18 | bootstrap: [AppComponent],
19 | declarations: [AppComponent],
20 | imports: [BrowserModule, TimezonePickerModule]
21 | })
22 | class AppModule {}
23 |
24 | platformBrowserDynamic().bootstrapModule(AppModule);
25 |
--------------------------------------------------------------------------------
/playground/systemjs-angular-loader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
4 | var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
5 | var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
6 |
7 | module.exports.translate = function (load){
8 | if (load.source.indexOf('moduleId') !== -1) {
9 | return load;
10 | }
11 |
12 | // eslint-disable-next-line
13 | var url = document.createElement('a');
14 | url.href = load.address;
15 |
16 | var basePathParts = url.pathname.split('/');
17 |
18 | basePathParts.pop();
19 | var basePath = basePathParts.join('/');
20 |
21 | // eslint-disable-next-line
22 | var baseHref = document.createElement('a');
23 | baseHref.href = this.baseURL;
24 | baseHref = baseHref.pathname;
25 |
26 | if (!baseHref.startsWith('/base/')) { // it is not karma
27 | basePath = basePath.replace(baseHref, '');
28 | }
29 |
30 | load.source = load.source
31 | .replace(templateUrlRegex, function (match, quote, sourceUrl){
32 | var resolvedUrl = sourceUrl;
33 |
34 | if (sourceUrl.startsWith('.')) {
35 | resolvedUrl = basePath + sourceUrl.substr(1);
36 | }
37 |
38 | return 'templateUrl: "' + resolvedUrl + '"';
39 | })
40 | .replace(stylesRegex, function (match, relativeUrls) {
41 | var urls = [];
42 |
43 | while ((match = stringRegex.exec(relativeUrls)) !== null) {
44 | if (match[2].startsWith('.')) {
45 | urls.push('"' + basePath + match[2].substr(1) + '"');
46 | } else {
47 | urls.push('"' + match[2] + '"');
48 | }
49 | }
50 |
51 | return 'styleUrls: [' + urls.join(', ') + ']';
52 | });
53 |
54 | return load;
55 | };
56 |
--------------------------------------------------------------------------------
/playground/systemjs.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * System configuration for Angular samples
4 | * Adjust as necessary for your application needs.
5 | */
6 | (function () {
7 | System.config({
8 | paths: {
9 | // paths serve as alias
10 | 'npm:': '../node_modules/'
11 | },
12 | // map tells the System loader where to look for things
13 | map: {
14 | // our app is within the app folder
15 | app: 'app',
16 |
17 | // angular bundles
18 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
19 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
20 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
21 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
22 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
23 | '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
24 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
25 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
26 |
27 | // other libraries
28 | rxjs: 'npm:rxjs',
29 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
30 | 'ng2-timezone-selector': '../dist'
31 | },
32 | // packages tells the System loader how to load when no filename and/or no extension
33 | packages: {
34 | app: {
35 | defaultExtension: 'js',
36 | meta: {
37 | './*.js': {
38 | loader: 'systemjs-angular-loader.js'
39 | }
40 | }
41 | },
42 | rxjs: {
43 | defaultExtension: 'js'
44 | },
45 | 'ng2-timezone-selector': {
46 | main: 'ng2-timezone-selector.umd.js',
47 | defaultExtension: 'js'
48 | }
49 | }
50 | });
51 | })(this);
52 |
--------------------------------------------------------------------------------
/playground/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../.playground",
4 | "target": "es5",
5 | "module": "commonjs",
6 | "moduleResolution": "node",
7 | "sourceMap": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "lib": [ "es2015", "dom" ],
11 | "noImplicitAny": true,
12 | "suppressImplicitAnyIndexErrors": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { TimezonePickerService } from './timezone-picker.service';
2 | import { NgModule, ModuleWithProviders } from '@angular/core';
3 | import { CommonModule } from '@angular/common';
4 | import { TimezonePickerComponent } from './timezone-picker.component';
5 | import { TimezonePickerPipe } from './timezone-picker.pipe';
6 |
7 | export * from './timezone-picker.component';
8 | export * from './timezone-picker.pipe';
9 | export * from './timezone-picker.service';
10 |
11 | @NgModule({
12 | imports: [CommonModule],
13 | declarations: [TimezonePickerComponent, TimezonePickerPipe],
14 | providers: [TimezonePickerService],
15 | exports: [TimezonePickerComponent, TimezonePickerPipe]
16 | })
17 | export class TimezonePickerModule {
18 | static forRoot(): ModuleWithProviders {
19 | return {
20 | ngModule: TimezonePickerModule,
21 | providers: [TimezonePickerService]
22 | };
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-timezone-selector",
3 | "version": "0.2.4",
4 | "description":
5 | "A simple Angular module to create a timezone selector using moment-timezone",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/samuelnygaard/ng2-timezone-selector"
9 | },
10 | "author": {
11 | "name": "Samuel Nygaard",
12 | "email": "teamnygaard@gmail.com"
13 | },
14 | "keywords": [
15 | "angular",
16 | "angular 4",
17 | "angular 5",
18 | "ng2",
19 | "timezone",
20 | "timezones",
21 | "selector",
22 | "picker",
23 | "moment",
24 | "moment-js",
25 | "moment-timezone",
26 | "timezone selector"
27 | ],
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/samuelnygaard/ng2-timezone-selector/issues"
31 | },
32 | "main": "ng2-timezone-selector.umd.js",
33 | "module": "ng2-timezone-selector.js",
34 | "jsnext:main": "ng2-timezone-selector.js",
35 | "typings": "ng2-timezone-selector.d.ts",
36 | "peerDependencies": {
37 | "@angular/core": "^4.0.0 || ^5.0.0",
38 | "rxjs": "^5.1.0",
39 | "zone.js": "^0.8.4"
40 | },
41 | "dependencies": {
42 | "jquery": "^3.3.1",
43 | "moment-timezone": "^0.5.14",
44 | "select2": "^4.0.6-rc.1"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/timezone-picker.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 | import { By } from '@angular/platform-browser';
3 | import { DebugElement } from '@angular/core';
4 |
5 | import { TimezonePickerComponent } from './timezone-picker.component';
6 |
7 | describe('TimezonePickerComponent', () => {
8 | let comp: TimezonePickerComponent;
9 | let fixture: ComponentFixture;
10 | let de: DebugElement;
11 | let el: HTMLElement;
12 |
13 | beforeEach(() => {
14 | TestBed.configureTestingModule({
15 | declarations: [TimezonePickerComponent] // declare the test component
16 | });
17 |
18 | fixture = TestBed.createComponent(TimezonePickerComponent);
19 |
20 | comp = fixture.componentInstance; // BannerComponent test instance
21 |
22 | // query for the title by CSS element selector
23 | de = fixture.debugElement.query(By.css('h1'));
24 | el = de.nativeElement;
25 | });
26 |
27 | it('Should be false', () => {
28 | expect(false).toBe(true);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/src/timezone-picker.component.ts:
--------------------------------------------------------------------------------
1 | import { TimezonePickerService, Timezone } from './timezone-picker.service';
2 | import {
3 | Component,
4 | AfterViewInit,
5 | Input,
6 | ViewChild,
7 | ElementRef,
8 | EventEmitter,
9 | Output
10 | } from '@angular/core';
11 | import * as moment from 'moment-timezone';
12 | import $ from 'jquery';
13 | import 'select2';
14 |
15 | @Component({
16 | selector: 'ng2-timezone-picker',
17 | template: `
18 | `
31 | })
32 | export class TimezonePickerComponent implements AfterViewInit {
33 | /**
34 | * all time zones combined in one array, for each country
35 | */
36 | allTimezones: Timezone[];
37 | /**
38 | * ElementRef for the select element
39 | */
40 | @ViewChild('select') select: ElementRef;
41 |
42 | /**
43 | * Input (optional) bound to [allowClear]
44 | */
45 | @Input() allowClear = false;
46 |
47 | @Input() showOffset = false;
48 |
49 | @Input() guess = false;
50 |
51 | /**
52 | * Input (optional) bound to [disabled]
53 | */
54 | @Input() disabled = false;
55 |
56 | placeholderString = 'Select timezone';
57 |
58 | /**
59 | * Input (optional) bound to [placeholder]
60 | */
61 | @Input()
62 | set placeholder(placeholder: string) {
63 | if (placeholder) {
64 | this.placeholderString = placeholder;
65 | const placeholderElem = $(this.select.nativeElement.parentElement).find(
66 | '.select2-selection__placeholder'
67 | );
68 | if (placeholderElem.length > 0) {
69 | placeholderElem[0].innerText = placeholder;
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * The current selected timezone.
76 | */
77 | currentTimezone: string;
78 | /**
79 | * Input: string (required) bound to [timezone]
80 | */
81 | @Input()
82 | set timezone(timezone: string) {
83 | if (timezone) {
84 | this.currentTimezone = timezone;
85 | this.triggerChangeEvent();
86 | } else if (this.guess) {
87 | this.currentTimezone = moment.tz.guess();
88 | this.triggerChangeEvent();
89 | }
90 | }
91 |
92 | @Input()
93 | set country(isoCode: string) {
94 | if (isoCode && !this.currentTimezone && !this.guess) {
95 | const res = this.allTimezones.find(x => x.iso === isoCode);
96 | if (res) {
97 | this.currentTimezone = res.zones[0];
98 | this.triggerChangeEvent();
99 | }
100 | }
101 | }
102 |
103 | /**
104 | * Output event bound to (timezone)
105 | */
106 | @Output() timezoneChange = new EventEmitter();
107 |
108 | /**
109 | * Output event bound to (change)
110 | */
111 | @Output() change = new EventEmitter();
112 | @Output() countryChange = new EventEmitter();
113 |
114 | /**
115 | * Contructor function to define all the timezones
116 | */
117 | constructor(public service: TimezonePickerService) {
118 | this.allTimezones = service.getZones();
119 | }
120 |
121 | /**
122 | * $ bounding of select2 framework in the selectElement
123 | */
124 | ngAfterViewInit() {
125 | const selectElement = $(this.select.nativeElement);
126 |
127 | selectElement.select2({
128 | placeholder: this.placeholderString,
129 | allowClear: this.allowClear,
130 | matcher: (term, text) => this.matcher(term, text)
131 | });
132 |
133 | if (this.currentTimezone) {
134 | $(selectElement)
135 | .val(this.currentTimezone)
136 | .trigger('change');
137 | }
138 |
139 | selectElement.on('change', (e: any) => {
140 | this.onChange($(e.target).val());
141 | });
142 | }
143 |
144 | private triggerChangeEvent(): void {
145 | $(this.select.nativeElement)
146 | .val(this.currentTimezone)
147 | .trigger('change');
148 | this.timezoneChange.emit(this.currentTimezone);
149 | this.change.emit(this.currentTimezone);
150 | this.countryChange.emit(
151 | this.allTimezones.find(x => x.zones.indexOf(this.currentTimezone) >= 0)
152 | .iso
153 | );
154 | }
155 |
156 | formatTimezoneString(zone: string): string {
157 | const arr = zone.split('/');
158 | return arr[arr.length - 1].replace('_', ' ');
159 | }
160 |
161 | offsetOfTimezone(zone: string): string {
162 | let offset = moment.tz(zone).utcOffset();
163 | const neg = offset < 0;
164 | if (neg) {
165 | offset = -1 * offset;
166 | }
167 | const hours = Math.floor(offset / 60);
168 | const minutes = (offset / 60 - hours) * 60;
169 | return `(GMT${neg ? '-' : '+'}${this.rjust(
170 | hours.toString(),
171 | 2
172 | )}:${this.rjust(minutes.toString(), 2)})`;
173 | }
174 |
175 | /**
176 | * onChange function called by the "select" element
177 | * @param timezone The timezone string selected
178 | */
179 | private onChange(timezone) {
180 | this.currentTimezone = timezone;
181 | this.timezoneChange.emit(timezone);
182 | this.change.emit(timezone);
183 | }
184 |
185 | /**
186 | * Matcher function to search in the select options
187 | * @param params contains the search term
188 | * @param data contains the data of each row
189 | */
190 | private matcher(params, data) {
191 | // Always return the object if there is nothing to compare
192 | if ($.trim(params.term) === '') {
193 | return data;
194 | }
195 |
196 | let original = data.text.toUpperCase();
197 | const term = params.term.toUpperCase();
198 |
199 | // Replace '_' with ' ' to be able to search for 'New York'
200 | if (original.indexOf('_') !== -1) {
201 | original += original.replace('_', ' ');
202 | }
203 |
204 | // Check if the text contains the term
205 | if (original.indexOf(term) > -1) {
206 | return data;
207 | }
208 |
209 | // Do a recursive check for options with children
210 | if (data.children && data.children.length > 0) {
211 | // Clone the data object if there are children
212 | // This is required as we modify the object to remove any non-matches
213 | const match = $.extend(true, {}, data);
214 | // Check each child of the option
215 | for (let c = data.children.length - 1; c >= 0; c--) {
216 | const child = data.children[c];
217 | const matches = this.matcher(params, child);
218 | // If there wasn't a match, remove the object in the array
219 | if (matches == null) {
220 | match.children.splice(c, 1);
221 | }
222 | }
223 | // If any children matched, return the new object
224 | if (match.children.length > 0) {
225 | return match;
226 | }
227 | // If there were no matching children, check just the plain object
228 | return this.matcher(params, match);
229 | }
230 | // If it doesn't contain the term, don't return anything
231 | return null;
232 | }
233 |
234 | private rjust(string: string, width: number, padding = '0'): string {
235 | padding = padding || ' ';
236 | padding = padding.substr(0, 1);
237 | if (string.length < width) {
238 | return padding.repeat(width - string.length) + string;
239 | } else {
240 | return string;
241 | }
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/src/timezone-picker.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, PipeTransform, Pipe } from '@angular/core';
2 | import { TimezonePickerService } from './timezone-picker.service';
3 |
4 | /**
5 | * Transforms any input value
6 | */
7 | @Pipe({
8 | name: 'iso2CountryPipe'
9 | })
10 | @Injectable()
11 | export class TimezonePickerPipe implements PipeTransform {
12 | constructor(private service: TimezonePickerService) {}
13 | transform(value: string): string {
14 | return this.service.iso2country(value);
15 | // return countryList[value] ? countryList[value] : value;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/timezone-picker.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | export interface Timezone {
4 | iso: string;
5 | zones: string[];
6 | }
7 |
8 | @Injectable()
9 | export class TimezonePickerService {
10 |
11 | /**
12 | * Convert country ISO code to country name (in english)
13 | */
14 | iso2country(iso: string): string {
15 | return countryList[iso] ? countryList[iso] : iso;
16 | }
17 |
18 | /**
19 | * Gets the list of ISO-codes for all countries
20 | */
21 | getCountries(): string[] {
22 | const res: string[] = [];
23 | for (const prop of Object.keys(countryList)) {
24 | res.push(prop);
25 | }
26 | return res;
27 | }
28 |
29 | /**
30 | * Get the timezones for each country
31 | */
32 | getZones(): Timezone[] {
33 | const res = [];
34 | for (const prop of Object.keys(zones)) {
35 | res.push({
36 | iso: prop,
37 | zones: zones[prop]
38 | });
39 | }
40 | return res;
41 | }
42 | }
43 |
44 | const zones = {
45 | AD: ['Europe/Andorra'],
46 | AE: ['Asia/Dubai'],
47 | AF: ['Asia/Kabul'],
48 | AG: ['America/Antigua'],
49 | AI: ['America/Anguilla'],
50 | AL: ['Europe/Tirane'],
51 | AM: ['Asia/Yerevan'],
52 | AO: ['Africa/Luanda'],
53 | AQ: [
54 | 'Antarctica/McMurdo',
55 | 'Antarctica/Rothera',
56 | 'Antarctica/Palmer',
57 | 'Antarctica/Mawson',
58 | 'Antarctica/Davis',
59 | 'Antarctica/Casey',
60 | 'Antarctica/Vostok',
61 | 'Antarctica/DumontDUrville',
62 | 'Antarctica/Syowa',
63 | 'Antarctica/Troll'
64 | ],
65 | AR: [
66 | 'America/Argentina/Buenos_Aires',
67 | 'America/Argentina/Cordoba',
68 | 'America/Argentina/Salta',
69 | 'America/Argentina/Jujuy',
70 | 'America/Argentina/Tucuman',
71 | 'America/Argentina/Catamarca',
72 | 'America/Argentina/La_Rioja',
73 | 'America/Argentina/San_Juan',
74 | 'America/Argentina/Mendoza',
75 | 'America/Argentina/San_Luis',
76 | 'America/Argentina/Rio_Gallegos',
77 | 'America/Argentina/Ushuaia'
78 | ],
79 | AS: ['Pacific/Pago_Pago', 'Pacific/Samoa'],
80 | AT: ['Europe/Vienna'],
81 | AU: [
82 | 'Australia/Lord_Howe',
83 | 'Antarctica/Macquarie',
84 | 'Australia/Hobart',
85 | 'Australia/Currie',
86 | 'Australia/Melbourne',
87 | 'Australia/Sydney',
88 | 'Australia/Broken_Hill',
89 | 'Australia/Brisbane',
90 | 'Australia/Lindeman',
91 | 'Australia/Adelaide',
92 | 'Australia/Darwin',
93 | 'Australia/Perth',
94 | 'Australia/Eucla',
95 | 'Australia/Canberra',
96 | 'Australia/Queensland',
97 | 'Australia/Tasmania',
98 | 'Australia/Victoria'
99 | ],
100 | AW: ['America/Aruba'],
101 | AX: ['Europe/Mariehamn'],
102 | AZ: ['Asia/Baku'],
103 | BA: ['Europe/Sarajevo'],
104 | BB: ['America/Barbados'],
105 | BD: ['Asia/Dhaka'],
106 | BE: ['Europe/Brussels'],
107 | BF: ['Africa/Ouagadougou'],
108 | BG: ['Europe/Sofia'],
109 | BH: ['Asia/Bahrain'],
110 | BI: ['Africa/Bujumbura'],
111 | BJ: ['Africa/Porto-Novo'],
112 | BL: ['America/St_Barthelemy'],
113 | BM: ['Atlantic/Bermuda'],
114 | BN: ['Asia/Brunei'],
115 | BO: ['America/La_Paz'],
116 | BQ: ['America/Kralendijk'],
117 | BR: [
118 | 'America/Noronha',
119 | 'America/Belem',
120 | 'America/Fortaleza',
121 | 'America/Recife',
122 | 'America/Araguaina',
123 | 'America/Maceio',
124 | 'America/Bahia',
125 | 'America/Sao_Paulo',
126 | 'America/Campo_Grande',
127 | 'America/Cuiaba',
128 | 'America/Santarem',
129 | 'America/Porto_Velho',
130 | 'America/Boa_Vista',
131 | 'America/Manaus',
132 | 'America/Eirunepe',
133 | 'America/Rio_Branco'
134 | ],
135 | BS: ['America/Nassau'],
136 | BT: ['Asia/Thimphu'],
137 | BW: ['Africa/Gaborone'],
138 | BY: ['Europe/Minsk'],
139 | BZ: ['America/Belize'],
140 | CA: [
141 | 'America/St_Johns',
142 | 'America/Halifax',
143 | 'America/Glace_Bay',
144 | 'America/Moncton',
145 | 'America/Goose_Bay',
146 | 'America/Blanc-Sablon',
147 | 'America/Toronto',
148 | 'America/Nipigon',
149 | 'America/Thunder_Bay',
150 | 'America/Iqaluit',
151 | 'America/Pangnirtung',
152 | 'America/Resolute',
153 | 'America/Atikokan',
154 | 'America/Rankin_Inlet',
155 | 'America/Winnipeg',
156 | 'America/Rainy_River',
157 | 'America/Regina',
158 | 'America/Swift_Current',
159 | 'America/Edmonton',
160 | 'America/Cambridge_Bay',
161 | 'America/Yellowknife',
162 | 'America/Inuvik',
163 | 'America/Creston',
164 | 'America/Dawson_Creek',
165 | 'America/Vancouver',
166 | 'America/Whitehorse',
167 | 'America/Dawson',
168 | 'America/Montreal',
169 | 'Canada/Atlantic',
170 | 'Canada/Central',
171 | 'Canada/Eastern',
172 | 'Canada/Mountain',
173 | 'Canada/Newfoundland',
174 | 'Canada/Pacific',
175 | 'Canada/Saskatchewan',
176 | 'Canada/Yukon'
177 | ],
178 | CC: ['Indian/Cocos'],
179 | CD: ['Africa/Kinshasa', 'Africa/Lubumbashi'],
180 | CF: ['Africa/Bangui'],
181 | CG: ['Africa/Brazzaville'],
182 | CH: ['Europe/Zurich'],
183 | CI: ['Africa/Abidjan'],
184 | CK: ['Pacific/Rarotonga'],
185 | CL: [
186 | 'America/Santiago',
187 | 'Pacific/Easter',
188 | 'Chile/Continental',
189 | 'Chile/EasterIsland'
190 | ],
191 | CM: ['Africa/Douala'],
192 | CN: [
193 | 'Asia/Shanghai',
194 | 'Asia/Harbin',
195 | 'Asia/Chongqing',
196 | 'Asia/Urumqi',
197 | 'Asia/Kashgar'
198 | ],
199 | CO: ['America/Bogota'],
200 | CR: ['America/Costa_Rica'],
201 | CU: ['America/Havana'],
202 | CV: ['Atlantic/Cape_Verde'],
203 | CW: ['America/Curacao'],
204 | CX: ['Indian/Christmas'],
205 | CY: ['Asia/Nicosia'],
206 | CZ: ['Europe/Prague'],
207 | DE: ['Europe/Berlin'],
208 | DJ: ['Africa/Djibouti'],
209 | DK: ['Europe/Copenhagen'],
210 | DM: ['America/Dominica'],
211 | DO: ['America/Santo_Domingo'],
212 | DZ: ['Africa/Algiers'],
213 | EC: ['America/Guayaquil', 'Pacific/Galapagos'],
214 | EE: ['Europe/Tallinn'],
215 | EG: ['Egypt'],
216 | EH: ['Africa/El_Aaiun'],
217 | ER: ['Africa/Asmara'],
218 | ES: ['Europe/Madrid', 'Africa/Ceuta', 'Atlantic/Canary'],
219 | ET: ['Africa/Addis_Ababa'],
220 | FI: ['Europe/Helsinki'],
221 | FJ: ['Pacific/Fiji'],
222 | FK: ['Atlantic/Stanley'],
223 | FM: ['Pacific/Chuuk', 'Pacific/Pohnpei', 'Pacific/Kosrae'],
224 | FO: ['Atlantic/Faroe'],
225 | FR: ['Europe/Paris'],
226 | GA: ['Africa/Libreville'],
227 | GB: ['Europe/London'],
228 | GD: ['America/Grenada'],
229 | GE: ['Asia/Tbilisi'],
230 | GF: ['America/Cayenne'],
231 | GG: ['Europe/Guernsey'],
232 | GH: ['Africa/Accra'],
233 | GI: ['Europe/Gibraltar'],
234 | GL: [
235 | 'America/Godthab',
236 | 'America/Danmarkshavn',
237 | 'America/Scoresbysund',
238 | 'America/Thule'
239 | ],
240 | GM: ['Africa/Banjul'],
241 | GN: ['Africa/Conakry'],
242 | GP: ['America/Guadeloupe'],
243 | GQ: ['Africa/Malabo'],
244 | GR: ['Europe/Athens'],
245 | GS: ['Atlantic/South_Georgia'],
246 | GT: ['America/Guatemala'],
247 | GU: ['Pacific/Guam'],
248 | GW: ['Africa/Bissau'],
249 | GY: ['America/Guyana'],
250 | HK: ['Asia/Hong_Kong'],
251 | HN: ['America/Tegucigalpa'],
252 | HR: ['Europe/Zagreb'],
253 | HT: ['America/Port-au-Prince'],
254 | HU: ['Europe/Budapest'],
255 | ID: ['Asia/Jakarta', 'Asia/Pontianak', 'Asia/Makassar', 'Asia/Jayapura'],
256 | IE: ['Europe/Dublin'],
257 | IL: ['Asia/Jerusalem'],
258 | IM: ['Europe/Isle_of_Man'],
259 | IN: ['Asia/Kolkata'],
260 | IO: ['Indian/Chagos'],
261 | IQ: ['Asia/Baghdad'],
262 | IR: ['Asia/Tehran'],
263 | IS: ['Atlantic/Reykjavik'],
264 | IT: ['Europe/Rome'],
265 | JE: ['Europe/Jersey'],
266 | JM: ['America/Jamaica'],
267 | JO: ['Asia/Amman'],
268 | JP: ['Asia/Tokyo'],
269 | KE: ['Africa/Nairobi'],
270 | KG: ['Asia/Bishkek'],
271 | KH: ['Asia/Phnom_Penh'],
272 | KI: ['Pacific/Tarawa', 'Pacific/Enderbury', 'Pacific/Kiritimati'],
273 | KM: ['Indian/Comoro'],
274 | KN: ['America/St_Kitts'],
275 | KP: ['Asia/Pyongyang'],
276 | KR: ['Asia/Seoul'],
277 | KW: ['Asia/Kuwait'],
278 | KY: ['America/Cayman'],
279 | KZ: [
280 | 'Asia/Almaty',
281 | 'Asia/Qyzylorda',
282 | 'Asia/Aqtobe',
283 | 'Asia/Aqtau',
284 | 'Asia/Oral'
285 | ],
286 | LA: ['Asia/Vientiane'],
287 | LB: ['Asia/Beirut'],
288 | LC: ['America/St_Lucia'],
289 | LI: ['Europe/Vaduz'],
290 | LK: ['Asia/Colombo'],
291 | LR: ['Africa/Monrovia'],
292 | LS: ['Africa/Maseru'],
293 | LT: ['Europe/Vilnius'],
294 | LU: ['Europe/Luxembourg'],
295 | LV: ['Europe/Riga'],
296 | LY: ['Africa/Tripoli'],
297 | MA: ['Africa/Casablanca'],
298 | MC: ['Europe/Monaco'],
299 | MD: ['Europe/Chisinau'],
300 | ME: ['Europe/Podgorica'],
301 | MF: ['America/Marigot'],
302 | MG: ['Indian/Antananarivo'],
303 | MH: ['Pacific/Majuro', 'Pacific/Kwajalein'],
304 | MK: ['Europe/Skopje'],
305 | ML: ['Africa/Bamako'],
306 | MM: ['Asia/Rangoon'],
307 | MN: ['Asia/Ulaanbaatar', 'Asia/Hovd', 'Asia/Choibalsan'],
308 | MO: ['Asia/Macau'],
309 | MP: ['Pacific/Saipan'],
310 | MQ: ['America/Martinique'],
311 | MR: ['Africa/Nouakchott'],
312 | MS: ['America/Montserrat'],
313 | MT: ['Europe/Malta'],
314 | MU: ['Indian/Mauritius'],
315 | MV: ['Indian/Maldives'],
316 | MW: ['Africa/Blantyre'],
317 | MX: [
318 | 'America/Mexico_City',
319 | 'America/Cancun',
320 | 'America/Merida',
321 | 'America/Monterrey',
322 | 'America/Matamoros',
323 | 'America/Mazatlan',
324 | 'America/Chihuahua',
325 | 'America/Ojinaga',
326 | 'America/Hermosillo',
327 | 'America/Tijuana',
328 | 'America/Santa_Isabel',
329 | 'America/Bahia_Banderas'
330 | ],
331 | MY: ['Asia/Kuala_Lumpur', 'Asia/Kuching'],
332 | MZ: ['Africa/Maputo'],
333 | NA: ['Africa/Windhoek'],
334 | NC: ['Pacific/Noumea'],
335 | NE: ['Africa/Niamey'],
336 | NF: ['Pacific/Norfolk'],
337 | NG: ['Africa/Lagos'],
338 | NI: ['America/Managua'],
339 | NL: ['Europe/Amsterdam'],
340 | NO: ['Europe/Oslo'],
341 | NP: ['Asia/Kathmandu'],
342 | NR: ['Pacific/Nauru'],
343 | NU: ['Pacific/Niue'],
344 | NZ: ['Pacific/Auckland', 'Pacific/Chatham'],
345 | OM: ['Asia/Muscat'],
346 | PA: ['America/Panama'],
347 | PE: ['America/Lima'],
348 | PF: ['Pacific/Tahiti', 'Pacific/Marquesas', 'Pacific/Gambier'],
349 | PG: ['Pacific/Port_Moresby'],
350 | PH: ['Asia/Manila'],
351 | PK: ['Asia/Karachi'],
352 | PL: ['Europe/Warsaw', 'Poland'],
353 | PM: ['America/Miquelon'],
354 | PN: ['Pacific/Pitcairn'],
355 | PR: ['America/Puerto_Rico'],
356 | PS: ['Asia/Gaza', 'Asia/Hebron'],
357 | PT: ['Europe/Lisbon', 'Atlantic/Madeira', 'Atlantic/Azores'],
358 | PW: ['Pacific/Palau'],
359 | PY: ['America/Asuncion'],
360 | QA: ['Asia/Qatar'],
361 | RE: ['Indian/Reunion'],
362 | RO: ['Europe/Bucharest'],
363 | RS: ['Europe/Belgrade'],
364 | RU: [
365 | 'Europe/Kaliningrad',
366 | 'Europe/Moscow',
367 | 'Europe/Volgograd',
368 | 'Europe/Samara',
369 | 'Europe/Simferopol',
370 | 'Asia/Yekaterinburg',
371 | 'Asia/Omsk',
372 | 'Asia/Novosibirsk',
373 | 'Asia/Novokuznetsk',
374 | 'Asia/Krasnoyarsk',
375 | 'Asia/Irkutsk',
376 | 'Asia/Yakutsk',
377 | 'Asia/Khandyga',
378 | 'Asia/Vladivostok',
379 | 'Asia/Sakhalin',
380 | 'Asia/Ust-Nera',
381 | 'Asia/Magadan',
382 | 'Asia/Kamchatka',
383 | 'Asia/Anadyr'
384 | ],
385 | RW: ['Africa/Kigali'],
386 | SA: ['Asia/Riyadh'],
387 | SB: ['Pacific/Guadalcanal'],
388 | SC: ['Indian/Mahe'],
389 | SD: ['Africa/Khartoum'],
390 | SE: ['Europe/Stockholm'],
391 | SG: ['Asia/Singapore'],
392 | SH: ['Atlantic/St_Helena'],
393 | SI: ['Europe/Ljubljana'],
394 | SJ: ['Arctic/Longyearbyen'],
395 | SK: ['Europe/Bratislava'],
396 | SL: ['Africa/Freetown'],
397 | SM: ['Europe/San_Marino'],
398 | SN: ['Africa/Dakar'],
399 | SO: ['Africa/Mogadishu'],
400 | SR: ['America/Paramaribo'],
401 | SS: ['Africa/Juba'],
402 | ST: ['Africa/Sao_Tome'],
403 | SV: ['America/El_Salvador'],
404 | SX: ['America/Lower_Princes'],
405 | SY: ['Asia/Damascus'],
406 | SZ: ['Africa/Mbabane'],
407 | TC: ['America/Grand_Turk'],
408 | TD: ['Africa/Ndjamena'],
409 | TF: ['Indian/Kerguelen'],
410 | TG: ['Africa/Lome'],
411 | TH: ['Asia/Bangkok'],
412 | TJ: ['Asia/Dushanbe'],
413 | TK: ['Pacific/Fakaofo'],
414 | TL: ['Asia/Dili'],
415 | TM: ['Asia/Ashgabat'],
416 | TN: ['Africa/Tunis'],
417 | TO: ['Pacific/Tongatapu'],
418 | TR: ['Europe/Istanbul'],
419 | TT: ['America/Port_of_Spain'],
420 | TV: ['Pacific/Funafuti'],
421 | TW: ['Asia/Taipei'],
422 | TZ: ['Africa/Dar_es_Salaam'],
423 | UA: ['Europe/Kiev', 'Europe/Uzhgorod', 'Europe/Zaporozhye'],
424 | UG: ['Africa/Kampala'],
425 | UM: ['Pacific/Johnston', 'Pacific/Midway', 'Pacific/Wake'],
426 | US: [
427 | 'America/New_York',
428 | 'America/Detroit',
429 | 'America/Kentucky/Louisville',
430 | 'America/Kentucky/Monticello',
431 | 'America/Indiana/Indianapolis',
432 | 'America/Indiana/Vincennes',
433 | 'America/Indiana/Winamac',
434 | 'America/Indiana/Marengo',
435 | 'America/Indiana/Petersburg',
436 | 'America/Indiana/Vevay',
437 | 'America/Chicago',
438 | 'America/Indiana/Tell_City',
439 | 'America/Indiana/Knox',
440 | 'America/Menominee',
441 | 'America/North_Dakota/Center',
442 | 'America/North_Dakota/New_Salem',
443 | 'America/North_Dakota/Beulah',
444 | 'America/Denver',
445 | 'America/Boise',
446 | 'America/Phoenix',
447 | 'America/Los_Angeles',
448 | 'America/Anchorage',
449 | 'America/Juneau',
450 | 'America/Sitka',
451 | 'America/Yakutat',
452 | 'America/Nome',
453 | 'America/Adak',
454 | 'America/Metlakatla',
455 | 'Pacific/Honolulu'
456 | ],
457 | UY: ['America/Montevideo'],
458 | UZ: ['Asia/Samarkand', 'Asia/Tashkent'],
459 | VA: ['Europe/Vatican'],
460 | VC: ['America/St_Vincent'],
461 | VE: ['America/Caracas'],
462 | VG: ['America/Tortola'],
463 | VI: ['America/St_Thomas'],
464 | VN: ['Asia/Ho_Chi_Minh'],
465 | VU: ['Pacific/Efate'],
466 | WF: ['Pacific/Wallis'],
467 | WS: ['Pacific/Apia'],
468 | YE: ['Asia/Aden'],
469 | YT: ['Indian/Mayotte'],
470 | ZA: ['Africa/Johannesburg'],
471 | ZM: ['Africa/Lusaka'],
472 | ZW: ['Africa/Harare']
473 | };
474 |
475 | const countryList = {
476 | AF: 'Afghanistan',
477 | AX: 'Aland Islands',
478 | AL: 'Albania',
479 | DZ: 'Algeria',
480 | AS: 'American Samoa',
481 | AD: 'Andorra',
482 | AO: 'Angola',
483 | AI: 'Anguilla',
484 | AQ: 'Antarctica',
485 | AG: 'Antigua and Barbuda',
486 | AR: 'Argentina',
487 | AM: 'Armenia',
488 | AW: 'Aruba',
489 | AU: 'Australia',
490 | AT: 'Austria',
491 | AZ: 'Azerbaijan',
492 | BS: 'Bahamas',
493 | BH: 'Bahrain',
494 | BD: 'Bangladesh',
495 | BB: 'Barbados',
496 | BY: 'Belarus',
497 | BE: 'Belgium',
498 | BZ: 'Belize',
499 | BJ: 'Benin',
500 | BM: 'Bermuda',
501 | BT: 'Bhutan',
502 | BO: 'Bolivia',
503 | BA: 'Bosnia and Herzegovina',
504 | BW: 'Botswana',
505 | BV: 'Bouvet Island',
506 | BR: 'Brazil',
507 | VG: 'British Virgin Islands',
508 | IO: 'British Indian Ocean Territory',
509 | BN: 'Brunei Darussalam',
510 | BG: 'Bulgaria',
511 | BF: 'Burkina Faso',
512 | BI: 'Burundi',
513 | KH: 'Cambodia',
514 | CM: 'Cameroon',
515 | CA: 'Canada',
516 | CV: 'Cape Verde',
517 | KY: 'Cayman Islands',
518 | CF: 'Central African Republic',
519 | TD: 'Chad',
520 | CL: 'Chile',
521 | CN: 'China',
522 | HK: 'Hong Kong',
523 | MO: 'Macao',
524 | CX: 'Christmas Island',
525 | CC: 'Cocos (Keeling) Islands',
526 | CO: 'Colombia',
527 | KM: 'Comoros',
528 | CG: 'Congo (Brazzaville)',
529 | CD: 'Congo, (Kinshasa)',
530 | CK: 'Cook Islands',
531 | CR: 'Costa Rica',
532 | CI: "Côte d'Ivoire",
533 | HR: 'Croatia',
534 | CU: 'Cuba',
535 | CY: 'Cyprus',
536 | CZ: 'Czech Republic',
537 | DK: 'Denmark',
538 | DJ: 'Djibouti',
539 | DM: 'Dominica',
540 | DO: 'Dominican Republic',
541 | EC: 'Ecuador',
542 | EG: 'Egypt',
543 | SV: 'El Salvador',
544 | GQ: 'Equatorial Guinea',
545 | ER: 'Eritrea',
546 | EE: 'Estonia',
547 | ET: 'Ethiopia',
548 | FK: 'Falkland Islands (Malvinas)',
549 | FO: 'Faroe Islands',
550 | FJ: 'Fiji',
551 | FI: 'Finland',
552 | FR: 'France',
553 | GF: 'French Guiana',
554 | PF: 'French Polynesia',
555 | TF: 'French Southern Territories',
556 | GA: 'Gabon',
557 | GM: 'Gambia',
558 | GE: 'Georgia',
559 | DE: 'Germany',
560 | GH: 'Ghana',
561 | GI: 'Gibraltar',
562 | GR: 'Greece',
563 | GL: 'Greenland',
564 | GD: 'Grenada',
565 | GP: 'Guadeloupe',
566 | GU: 'Guam',
567 | GT: 'Guatemala',
568 | GG: 'Guernsey',
569 | GN: 'Guinea',
570 | GW: 'Guinea-Bissau',
571 | GY: 'Guyana',
572 | HT: 'Haiti',
573 | HM: 'Heard and Mcdonald Islands',
574 | VA: 'Vatican City State',
575 | HN: 'Honduras',
576 | HU: 'Hungary',
577 | IS: 'Iceland',
578 | IN: 'India',
579 | ID: 'Indonesia',
580 | IR: 'Iran',
581 | IQ: 'Iraq',
582 | IE: 'Ireland',
583 | IM: 'Isle of Man',
584 | IL: 'Israel',
585 | IT: 'Italy',
586 | JM: 'Jamaica',
587 | JP: 'Japan',
588 | JE: 'Jersey',
589 | JO: 'Jordan',
590 | KZ: 'Kazakhstan',
591 | KE: 'Kenya',
592 | KI: 'Kiribati',
593 | KP: 'Korea (North)',
594 | KR: 'Korea (South)',
595 | KW: 'Kuwait',
596 | KG: 'Kyrgyzstan',
597 | LA: 'Lao PDR',
598 | LV: 'Latvia',
599 | LB: 'Lebanon',
600 | LS: 'Lesotho',
601 | LR: 'Liberia',
602 | LY: 'Libya',
603 | LI: 'Liechtenstein',
604 | LT: 'Lithuania',
605 | LU: 'Luxembourg',
606 | MK: 'Macedonia',
607 | MG: 'Madagascar',
608 | MW: 'Malawi',
609 | MY: 'Malaysia',
610 | MV: 'Maldives',
611 | ML: 'Mali',
612 | MT: 'Malta',
613 | MH: 'Marshall Islands',
614 | MQ: 'Martinique',
615 | MR: 'Mauritania',
616 | MU: 'Mauritius',
617 | YT: 'Mayotte',
618 | MX: 'Mexico',
619 | FM: 'Micronesia',
620 | MD: 'Moldova',
621 | MC: 'Monaco',
622 | MN: 'Mongolia',
623 | ME: 'Montenegro',
624 | MS: 'Montserrat',
625 | MA: 'Morocco',
626 | MZ: 'Mozambique',
627 | MM: 'Myanmar',
628 | NA: 'Namibia',
629 | NR: 'Nauru',
630 | NP: 'Nepal',
631 | NL: 'Netherlands',
632 | AN: 'Netherlands Antilles',
633 | NC: 'New Caledonia',
634 | NZ: 'New Zealand',
635 | NI: 'Nicaragua',
636 | NE: 'Niger',
637 | NG: 'Nigeria',
638 | NU: 'Niue',
639 | NF: 'Norfolk Island',
640 | MP: 'Northern Mariana Islands',
641 | NO: 'Norway',
642 | OM: 'Oman',
643 | PK: 'Pakistan',
644 | PW: 'Palau',
645 | PS: 'Palestinian Territory',
646 | PA: 'Panama',
647 | PG: 'Papua New Guinea',
648 | PY: 'Paraguay',
649 | PE: 'Peru',
650 | PH: 'Philippines',
651 | PN: 'Pitcairn',
652 | PL: 'Poland',
653 | PT: 'Portugal',
654 | PR: 'Puerto Rico',
655 | QA: 'Qatar',
656 | RE: 'Réunion',
657 | RO: 'Romania',
658 | RU: 'Russian Federation',
659 | RW: 'Rwanda',
660 | BL: 'Saint-Barthélemy',
661 | SH: 'Saint Helena',
662 | KN: 'Saint Kitts and Nevis',
663 | LC: 'Saint Lucia',
664 | MF: 'Saint-Martin (French part)',
665 | PM: 'Saint Pierre and Miquelon',
666 | VC: 'Saint Vincent and Grenadines',
667 | WS: 'Samoa',
668 | SM: 'San Marino',
669 | ST: 'Sao Tome and Principe',
670 | SA: 'Saudi Arabia',
671 | SN: 'Senegal',
672 | RS: 'Serbia',
673 | SC: 'Seychelles',
674 | SL: 'Sierra Leone',
675 | SG: 'Singapore',
676 | SK: 'Slovakia',
677 | SI: 'Slovenia',
678 | SB: 'Solomon Islands',
679 | SO: 'Somalia',
680 | ZA: 'South Africa',
681 | GS: 'South Georgia and the South Sandwich Islands',
682 | SS: 'South Sudan',
683 | ES: 'Spain',
684 | LK: 'Sri Lanka',
685 | SD: 'Sudan',
686 | SR: 'Suriname',
687 | SJ: 'Svalbard and Jan Mayen Islands',
688 | SZ: 'Swaziland',
689 | SE: 'Sweden',
690 | CH: 'Switzerland',
691 | SY: 'Syria',
692 | TW: 'Taiwan',
693 | TJ: 'Tajikistan',
694 | TZ: 'Tanzania',
695 | TH: 'Thailand',
696 | TL: 'Timor-Leste',
697 | TG: 'Togo',
698 | TK: 'Tokelau',
699 | TO: 'Tonga',
700 | TT: 'Trinidad and Tobago',
701 | TN: 'Tunisia',
702 | TR: 'Turkey',
703 | TM: 'Turkmenistan',
704 | TC: 'Turks and Caicos Islands',
705 | TV: 'Tuvalu',
706 | UG: 'Uganda',
707 | UA: 'Ukraine',
708 | AE: 'United Arab Emirates',
709 | GB: 'United Kingdom (GB)',
710 | US: 'United States of America (USA)',
711 | UM: 'US Minor Outlying Islands',
712 | UY: 'Uruguay',
713 | UZ: 'Uzbekistan',
714 | VU: 'Vanuatu',
715 | VE: 'Venezuela',
716 | VN: 'Viet Nam',
717 | VI: 'Virgin Islands, US',
718 | WF: 'Wallis and Futuna Islands',
719 | EH: 'Western Sahara',
720 | YE: 'Yemen',
721 | ZM: 'Zambia',
722 | ZW: 'Zimbabwe'
723 | };
724 |
--------------------------------------------------------------------------------
/src/tsconfig.es5.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "module": "es2015",
5 | "target": "es5",
6 | "baseUrl": ".",
7 | "stripInternal": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "moduleResolution": "node",
11 | "outDir": "../build",
12 | "rootDir": ".",
13 | "lib": [
14 | "es2015",
15 | "dom"
16 | ],
17 | "skipLibCheck": true,
18 | "types": []
19 | },
20 | "angularCompilerOptions": {
21 | "annotateForClosureCompiler": true,
22 | "strictMetadataEmit": true,
23 | "skipTemplateCodegen": true,
24 | "flatModuleOutFile": "ng2-timezone-selector.js",
25 | "flatModuleId": "ng2-timezone-selector"
26 | },
27 | "files": [
28 | "./index.ts"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.es5.json",
3 | "compilerOptions": {
4 | "emitDecoratorMetadata": true,
5 | "experimentalDecorators": true,
6 | "outDir": "../out-tsc/spec",
7 | "module": "commonjs",
8 | "target": "es6",
9 | "baseUrl": "",
10 | "types": [
11 | "jest",
12 | "node"
13 | ]
14 | },
15 | "files": [
16 | "**/*.spec.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/tools/gulp/inline-resources.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // https://github.com/filipesilva/angular-quickstart-lib/blob/master/inline-resources.js
3 | 'use strict';
4 |
5 | const fs = require('fs');
6 | const path = require('path');
7 | const glob = require('glob');
8 | const sass = require('node-sass');
9 | const tildeImporter = require('node-sass-tilde-importer');
10 |
11 | /**
12 | * Simple Promiseify function that takes a Node API and return a version that supports promises.
13 | * We use promises instead of synchronized functions to make the process less I/O bound and
14 | * faster. It also simplifies the code.
15 | */
16 | function promiseify(fn) {
17 | return function () {
18 | const args = [].slice.call(arguments, 0);
19 | return new Promise((resolve, reject) => {
20 | fn.apply(this, args.concat([function (err, value) {
21 | if (err) {
22 | reject(err);
23 | } else {
24 | resolve(value);
25 | }
26 | }]));
27 | });
28 | };
29 | }
30 |
31 | const readFile = promiseify(fs.readFile);
32 | const writeFile = promiseify(fs.writeFile);
33 |
34 | /**
35 | * Inline resources in a tsc/ngc compilation.
36 | * @param projectPath {string} Path to the project.
37 | */
38 | function inlineResources(projectPath) {
39 |
40 | // Match only TypeScript files in projectPath.
41 | const files = glob.sync('**/*.ts', {cwd: projectPath});
42 |
43 | // For each file, inline the templates and styles under it and write the new file.
44 | return Promise.all(files.map(filePath => {
45 | const fullFilePath = path.join(projectPath, filePath);
46 | return readFile(fullFilePath, 'utf-8')
47 | .then(content => inlineResourcesFromString(content, url => {
48 | // Resolve the template url.
49 | return path.join(path.dirname(fullFilePath), url);
50 | }))
51 | .then(content => writeFile(fullFilePath, content))
52 | .catch(err => {
53 | console.error('An error occured: ', err);
54 | });
55 | }));
56 | }
57 |
58 | /**
59 | * Inline resources from a string content.
60 | * @param content {string} The source file's content.
61 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
62 | * @returns {string} The content with resources inlined.
63 | */
64 | function inlineResourcesFromString(content, urlResolver) {
65 | // Curry through the inlining functions.
66 | return [
67 | inlineTemplate,
68 | inlineStyle,
69 | removeModuleId
70 | ].reduce((content, fn) => fn(content, urlResolver), content);
71 | }
72 |
73 | /**
74 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
75 | * replace with `template: ...` (with the content of the file included).
76 | * @param content {string} The source file's content.
77 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
78 | * @return {string} The content with all templates inlined.
79 | */
80 | function inlineTemplate(content, urlResolver) {
81 | return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function (m, templateUrl) {
82 | const templateFile = urlResolver(templateUrl);
83 | const templateContent = fs.readFileSync(templateFile, 'utf-8');
84 | const shortenedTemplate = templateContent
85 | .replace(/([\n\r]\s*)+/gm, ' ')
86 | .replace(/"/g, '\\"');
87 | return `template: "${shortenedTemplate}"`;
88 | });
89 | }
90 |
91 |
92 | /**
93 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
94 | * replace with `styles: [...]` (with the content of the file included).
95 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
96 | * @param content {string} The source file's content.
97 | * @return {string} The content with all styles inlined.
98 | */
99 | function inlineStyle(content, urlResolver) {
100 | return content.replace(/styleUrls\s*:\s*(\[[\s\S]*?\])/gm, function (m, styleUrls) {
101 | const urls = eval(styleUrls);
102 | return 'styles: ['
103 | + urls.map(styleUrl => {
104 | const styleFile = urlResolver(styleUrl);
105 | const originContent = fs.readFileSync(styleFile, 'utf-8');
106 | const styleContent = styleFile.endsWith('.scss') ? buildSass(originContent, styleFile) : originContent;
107 | const shortenedStyle = styleContent
108 | .replace(/([\n\r]\s*)+/gm, ' ')
109 | .replace(/"/g, '\\"');
110 | return `"${shortenedStyle}"`;
111 | })
112 | .join(',\n')
113 | + ']';
114 | });
115 | }
116 |
117 | /**
118 | * build sass content to css
119 | * @param content {string} the css content
120 | * @param sourceFile {string} the scss file sourceFile
121 | * @return {string} the generated css, empty string if error occured
122 | */
123 | function buildSass(content, sourceFile) {
124 | try {
125 | const result = sass.renderSync({
126 | data: content,
127 | file: sourceFile,
128 | importer: tildeImporter
129 | });
130 | return result.css.toString()
131 | } catch (e) {
132 | console.error('\x1b[41m');
133 | console.error('at ' + sourceFile + ':' + e.line + ":" + e.column);
134 | console.error(e.formatted);
135 | console.error('\x1b[0m');
136 | return "";
137 | }
138 | }
139 |
140 | /**
141 | * Remove every mention of `moduleId: module.id`.
142 | * @param content {string} The source file's content.
143 | * @returns {string} The content with all moduleId: mentions removed.
144 | */
145 | function removeModuleId(content) {
146 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
147 | }
148 |
149 | module.exports = inlineResources;
150 | module.exports.inlineResourcesFromString = inlineResourcesFromString;
151 |
152 | // Run inlineResources if module is being called directly from the CLI with arguments.
153 | if (require.main === module && process.argv.length > 2) {
154 | console.log('Inlining resources from project:', process.argv[2]);
155 | return inlineResources(process.argv[2]);
156 | }
157 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./src",
4 | "experimentalDecorators": true,
5 | "moduleResolution": "node",
6 | "rootDir": "./src",
7 | "lib": [
8 | "es2015",
9 | "dom"
10 | ],
11 | "skipLibCheck": true,
12 | "types": []
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "class-name": true,
7 | "comment-format": [
8 | true,
9 | "check-space"
10 | ],
11 | "curly": true,
12 | "eofline": true,
13 | "forin": true,
14 | "indent": [
15 | true,
16 | "spaces"
17 | ],
18 | "label-position": true,
19 | "max-line-length": [
20 | true,
21 | 140
22 | ],
23 | "member-access": false,
24 | "member-ordering": [
25 | true,
26 | "static-before-instance",
27 | "variables-before-functions"
28 | ],
29 | "no-arg": true,
30 | "no-bitwise": true,
31 | "no-console": [
32 | true,
33 | "debug",
34 | "info",
35 | "time",
36 | "timeEnd",
37 | "trace"
38 | ],
39 | "no-construct": true,
40 | "no-debugger": true,
41 | "no-duplicate-variable": true,
42 | "no-empty": false,
43 | "no-eval": true,
44 | "no-inferrable-types": true,
45 | "no-shadowed-variable": true,
46 | "no-string-literal": false,
47 | "no-switch-case-fall-through": true,
48 | "no-trailing-whitespace": true,
49 | "no-unused-expression": true,
50 | "no-unused-variable": true,
51 | "no-use-before-declare": true,
52 | "no-var-keyword": true,
53 | "object-literal-sort-keys": false,
54 | "one-line": [
55 | true,
56 | "check-open-brace",
57 | "check-catch",
58 | "check-else",
59 | "check-whitespace"
60 | ],
61 | "quotemark": [
62 | true,
63 | "single"
64 | ],
65 | "radix": true,
66 | "semicolon": [
67 | "always"
68 | ],
69 | "triple-equals": [
70 | true,
71 | "allow-null-check"
72 | ],
73 | "typedef-whitespace": [
74 | true,
75 | {
76 | "call-signature": "nospace",
77 | "index-signature": "nospace",
78 | "parameter": "nospace",
79 | "property-declaration": "nospace",
80 | "variable-declaration": "nospace"
81 | }
82 | ],
83 | "variable-name": false,
84 | "whitespace": [
85 | true,
86 | "check-branch",
87 | "check-decl",
88 | "check-operator",
89 | "check-separator",
90 | "check-type"
91 | ],
92 | "directive-selector": [true, "attribute", "", "camelCase"],
93 | "component-selector": [true, "element", "", "kebab-case"],
94 | "use-input-property-decorator": true,
95 | "use-output-property-decorator": true,
96 | "use-host-property-decorator": true,
97 | "no-input-rename": true,
98 | "no-output-rename": true,
99 | "use-life-cycle-interface": true,
100 | "use-pipe-transform-interface": true,
101 | "component-class-suffix": true,
102 | "directive-class-suffix": true
103 | }
104 | }
105 |
--------------------------------------------------------------------------------