├── projects ├── demo │ ├── tsconfig.json │ ├── src │ │ ├── favicon.ico │ │ ├── polyfills.ts │ │ ├── assets │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-70x70.png │ │ │ ├── mstile-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ ├── mstile-310x150.png │ │ │ ├── mstile-310x310.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── browsercongig.xml │ │ │ ├── browserconfig.xml │ │ │ ├── site.webmanifest │ │ │ ├── safari-pinned-tab.svg │ │ │ ├── logo.svg │ │ │ └── web-api.svg │ │ ├── app │ │ │ ├── samples │ │ │ │ ├── sample-async.ts │ │ │ │ └── sample.ts │ │ │ ├── types.d.ts │ │ │ ├── app.server.module.ts │ │ │ ├── app.routes.ts │ │ │ ├── map │ │ │ │ ├── map.component.less │ │ │ │ ├── map.component.html │ │ │ │ └── map.component.ts │ │ │ ├── app.browser.module.ts │ │ │ ├── app.component.ts │ │ │ ├── app.style.less │ │ │ └── app.component.html │ │ ├── main.server.ts │ │ ├── main.browser.ts │ │ ├── test.ts │ │ ├── styles.css │ │ └── index.html │ ├── tsconfig.demo.json │ ├── static.paths.ts │ ├── tsconfig.ssr.json │ ├── tsconfig.spec.json │ ├── tsconfig.server.json │ ├── .browserslistrc │ ├── package-lock.json │ ├── .gitignore │ ├── package.json │ ├── karma.conf.js │ ├── prerender.ts │ ├── angular.json │ └── server.ts └── geolocation │ ├── tsconfig.lib.prod.json │ ├── ng-package.json │ ├── src │ ├── tokens │ │ ├── geolocation-options.ts │ │ ├── geolocation.ts │ │ ├── geolocation-support.ts │ │ └── geolocation.spec.ts │ ├── public-api.ts │ ├── test.ts │ └── services │ │ ├── geolocation.service.ts │ │ └── geolocation.service.spec.ts │ ├── tsconfig.spec.json │ ├── README.md │ ├── tsconfig.lib.json │ ├── package.json │ ├── LICENSE │ └── karma.conf.js ├── prettier.config.js ├── .github ├── FUNDING.yml ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── workflows │ └── ci.yml └── PULL_REQUEST_TEMPLATE.md ├── tslint.json ├── scripts ├── syncVersions.js └── postbuild.js ├── .gitignore ├── tsconfig.json ├── LICENSE ├── CONTRIBUTING.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── package.json ├── angular.json └── README.md /projects/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('@tinkoff/linters/prettier/prettier.config'), 3 | }; 4 | -------------------------------------------------------------------------------- /projects/demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/favicon.ico -------------------------------------------------------------------------------- /projects/demo/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6/reflect'; 2 | import 'core-js/es7/reflect'; 3 | import 'zone.js'; 4 | -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/favicon.ico -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | open_collective: ng-web-apis 4 | issuehunt: ng-web-apis 5 | -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/favicon-16x16.png -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/favicon-32x32.png -------------------------------------------------------------------------------- /projects/demo/src/assets/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/mstile-70x70.png -------------------------------------------------------------------------------- /projects/demo/src/assets/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/mstile-144x144.png -------------------------------------------------------------------------------- /projects/demo/src/assets/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/mstile-150x150.png -------------------------------------------------------------------------------- /projects/demo/src/assets/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/mstile-310x150.png -------------------------------------------------------------------------------- /projects/demo/src/assets/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/mstile-310x310.png -------------------------------------------------------------------------------- /projects/demo/src/assets/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/apple-touch-icon.png -------------------------------------------------------------------------------- /projects/demo/src/assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /projects/demo/src/assets/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ng-web-apis/geolocation/HEAD/projects/demo/src/assets/android-chrome-512x512.png -------------------------------------------------------------------------------- /projects/geolocation/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /projects/demo/src/app/samples/sample-async.ts: -------------------------------------------------------------------------------- 1 | export const SAMPLE_ASYNC = ``; 2 | -------------------------------------------------------------------------------- /projects/demo/src/main.server.ts: -------------------------------------------------------------------------------- 1 | export {AppServerModule} from './app/app.server.module'; 2 | 3 | export {renderModule, renderModuleFactory} from '@angular/platform-server'; 4 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": ["src/app/types.d.ts"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/geolocation/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/geolocation", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/demo/src/app/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'highlight.js/lib/highlight'; 2 | declare module 'highlight.js/lib/languages/less'; 3 | declare module 'highlight.js/lib/languages/typescript'; 4 | declare module 'highlight.js/lib/languages/xml'; 5 | -------------------------------------------------------------------------------- /projects/demo/static.paths.ts: -------------------------------------------------------------------------------- 1 | import {appRoutes} from './src/app/app.routes'; 2 | 3 | export const PRERENDERED_ROUTES: ReadonlyArray = appRoutes 4 | .map(route => route.path || '') 5 | .filter(path => path && path !== '**'); 6 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@tinkoff/linters/tslint/bases/prettier.tslint.json"], 3 | "rules": { 4 | "deprecation": { 5 | "severity": "warning" 6 | }, 7 | "ordered-imports": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.ssr.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/demo/ssr", 5 | "module": "commonjs" 6 | }, 7 | "include": ["server.ts", "prerender.ts", "src/**/*.d.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /projects/geolocation/src/tokens/geolocation-options.ts: -------------------------------------------------------------------------------- 1 | import {InjectionToken} from '@angular/core'; 2 | 3 | export const POSITION_OPTIONS = new InjectionToken( 4 | 'Token for an additional position options', 5 | {factory: () => ({})}, 6 | ); 7 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine", "node"] 6 | }, 7 | "files": ["src/test.ts"], 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /projects/geolocation/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine", "node"] 6 | }, 7 | "files": ["src/test.ts"], 8 | "include": ["**/*.spec.ts", "**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /projects/demo/src/assets/browsercongig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #9f00a7 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/geolocation/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Public API Surface of geolocation 3 | */ 4 | 5 | /* Services */ 6 | export * from './services/geolocation.service'; 7 | 8 | /* Tokens */ 9 | export * from './tokens/geolocation'; 10 | export * from './tokens/geolocation-options'; 11 | export * from './tokens/geolocation-support'; 12 | -------------------------------------------------------------------------------- /projects/demo/src/assets/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /projects/demo/src/app/samples/sample.ts: -------------------------------------------------------------------------------- 1 | export const SAMPLE = `import {GeolocationService} from '@ng-web-apis/geolocation'; 2 | 3 | // ... 4 | 5 | constructor(private readonly geolocation$: GeolocationService) {} 6 | 7 | getPosition() { 8 | geolocation$.subscribe((position) => { 9 | doSomethingWithPosition(position); 10 | }); 11 | }`; 12 | -------------------------------------------------------------------------------- /projects/demo/tsconfig.server.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "target": "es2016" 5 | }, 6 | "angularCompilerOptions": { 7 | "entryModule": "src/app/app.server.module#AppServerModule" 8 | }, 9 | "files": ["src/main.server.ts", "server.ts"], 10 | "include": ["src/**/*.d.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /projects/geolocation/src/tokens/geolocation.ts: -------------------------------------------------------------------------------- 1 | import {inject, InjectionToken} from '@angular/core'; 2 | import {NAVIGATOR} from '@ng-web-apis/common'; 3 | 4 | export const GEOLOCATION = new InjectionToken( 5 | 'An abstraction over window.navigator.geolocation object', 6 | { 7 | factory: () => inject(NAVIGATOR).geolocation, 8 | }, 9 | ); 10 | -------------------------------------------------------------------------------- /projects/geolocation/src/tokens/geolocation-support.ts: -------------------------------------------------------------------------------- 1 | import {inject, InjectionToken} from '@angular/core'; 2 | import {GEOLOCATION} from './geolocation'; 3 | 4 | export const GEOLOCATION_SUPPORT = new InjectionToken( 5 | 'Is Geolocation API supported?', 6 | { 7 | factory: () => { 8 | return !!inject(GEOLOCATION); 9 | }, 10 | }, 11 | ); 12 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.server.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {ServerModule} from '@angular/platform-server'; 3 | import {AppBrowserModule} from './app.browser.module'; 4 | import {AppComponent} from './app.component'; 5 | 6 | @NgModule({ 7 | imports: [AppBrowserModule, ServerModule], 8 | bootstrap: [AppComponent], 9 | }) 10 | export class AppServerModule {} 11 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {RouterModule} from '@angular/router'; 3 | import {AppComponent} from './app.component'; 4 | 5 | export const appRoutes = [ 6 | { 7 | path: '**', 8 | component: AppComponent, 9 | }, 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forRoot(appRoutes)], 14 | exports: [RouterModule], 15 | }) 16 | export class AppRoutingModule {} 17 | -------------------------------------------------------------------------------- /projects/demo/src/app/map/map.component.less: -------------------------------------------------------------------------------- 1 | .map { 2 | min-width: 300px; 3 | height: 300px; 4 | overflow: hidden; 5 | background-color: rgba(236, 234, 234, 0.438); 6 | border: 1px solid rgb(124, 124, 124); 7 | } 8 | 9 | .marker { 10 | position: relative; 11 | top: 50%; 12 | left: 50%; 13 | width: 20px; 14 | height: 20px; 15 | } 16 | 17 | .coords { 18 | position: absolute; 19 | font-family: monospace; 20 | width: max-content; 21 | } 22 | -------------------------------------------------------------------------------- /projects/demo/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /projects/geolocation/README.md: -------------------------------------------------------------------------------- 1 | # Geolocation API for Angular 2 | 3 | [![angular-open-source-starter](https://img.shields.io/badge/made%20with-angular--open--source--starter-d81676?logo=angular)](https://github.com/TinkoffCreditSystems/angular-open-source-starter) 4 | 5 | This is a library for declarative use of [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) with Angular 6+. 6 | 7 | ## How to use 8 | 9 | ### Sources 10 | 11 | ## Tokens 12 | 13 | ## TODO 14 | 15 | -------------------------------------------------------------------------------- /projects/demo/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/highlight.js": { 8 | "version": "9.12.3", 9 | "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", 10 | "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", 11 | "dev": true 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /projects/demo/src/assets/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/geolocation/assets/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/geolocation/assets/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /projects/demo/src/main.browser.ts: -------------------------------------------------------------------------------- 1 | import './polyfills'; 2 | 3 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 4 | import {AppBrowserModule} from './app/app.browser.module'; 5 | 6 | platformBrowserDynamic() 7 | .bootstrapModule(AppBrowserModule) 8 | .then(ref => { 9 | const windowRef: any = window; 10 | 11 | // Ensure Angular destroys itself on hot reloads for Stackblitz 12 | if (windowRef['ngRef']) { 13 | windowRef['ngRef'].destroy(); 14 | } 15 | 16 | windowRef['ngRef'] = ref; 17 | }) 18 | .catch(err => console.error(err)); 19 | -------------------------------------------------------------------------------- /projects/geolocation/src/tokens/geolocation.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | import {catchError} from 'rxjs/operators'; 3 | import {GeolocationService} from '../services/geolocation.service'; 4 | 5 | describe('Geolocation token', () => { 6 | let service: any; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | providers: [GeolocationService], 11 | }); 12 | 13 | service = TestBed.get(GeolocationService).pipe( 14 | catchError((_err, caught) => caught), 15 | ); 16 | }); 17 | 18 | it('defined', () => { 19 | expect(service).toBeDefined(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | # ================================================================================== 3 | # ================================================================================== 4 | # @ng-web-apis/geolocation codeowners 5 | # ================================================================================== 6 | # ================================================================================== 7 | # 8 | # Configuration of code ownership and review approvals for the @ng-web-apis/geolocation repo. 9 | # 10 | # More info: https://help.github.com/articles/about-codeowners/ 11 | # 12 | 13 | * @vladimirpotekhin @waterplea @MarsiBarsi 14 | # will be requested for review when someone opens a pull request 15 | -------------------------------------------------------------------------------- /projects/geolocation/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "declarationMap": true, 6 | "target": "es2015", 7 | "declaration": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": ["dom", "es2018"] 11 | }, 12 | "angularCompilerOptions": { 13 | "skipTemplateCodegen": true, 14 | "strictMetadataEmit": true, 15 | "fullTemplateTypeCheck": true, 16 | "strictInjectionParameters": true, 17 | "enableResourceInlining": true, 18 | "enableIvy": true, 19 | "compilationMode": "partial" 20 | }, 21 | "exclude": ["src/test.ts", "**/*.spec.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /projects/demo/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /tmp 4 | /out-tsc 5 | # Only exists if Bazel was run 6 | /bazel-out 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # profiling files 12 | chrome-profiler-events.json 13 | speed-measure-plugin.json 14 | 15 | # IDEs and editors 16 | /.idea 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | .history/* 31 | 32 | # misc 33 | /.sass-cache 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | npm-debug.log 38 | yarn-error.log 39 | testem.log 40 | /typings 41 | 42 | # System Files 43 | .DS_Store 44 | Thumbs.db 45 | -------------------------------------------------------------------------------- /projects/demo/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | import 'zone.js'; 3 | import 'zone.js/testing'; 4 | 5 | import {getTestBed} from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting, 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: any; 12 | 13 | // First, initialize the Angular testing environment. 14 | getTestBed().initTestEnvironment( 15 | BrowserDynamicTestingModule, 16 | platformBrowserDynamicTesting(), 17 | ); 18 | 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | 22 | // And load the modules. 23 | context.keys().map(context); 24 | -------------------------------------------------------------------------------- /projects/geolocation/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | import 'zone.js'; 3 | import 'zone.js/testing'; 4 | 5 | import {getTestBed} from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting, 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: any; 12 | 13 | // First, initialize the Angular testing environment. 14 | getTestBed().initTestEnvironment( 15 | BrowserDynamicTestingModule, 16 | platformBrowserDynamicTesting(), 17 | ); 18 | 19 | // Then we find all the tests. 20 | const context = require.context('./', true, /\.spec\.ts$/); 21 | 22 | // And load the modules. 23 | context.keys().map(context); 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Bug report 3 | about: Create a report to help us improve 4 | title: '[BUG] ' 5 | labels: '' 6 | assignee: vladimirpotekhin 7 | --- 8 | 9 | # 🐞 Bug report 10 | 11 | ### Description 12 | 13 | 14 | 15 | ### Reproduction 16 | 17 | 18 | 19 | http://www.stackblitz.com/... 20 | 21 | ### Expected behavior 22 | 23 | 24 | 25 | ### Versions 26 | 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Angular [e.g. 8] 30 | 31 | ### Additional context 32 | 33 | 34 | -------------------------------------------------------------------------------- /scripts/syncVersions.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const glob = require('glob'); 3 | const JSON_INDENTATION_LEVEL = 4; 4 | const {version} = require('../package.json'); 5 | 6 | // Sync libraries package.json versions with main package.json 7 | syncVersions('projects'); 8 | 9 | function syncVersions(root) { 10 | glob(root + '/**/package.json', (_, files) => { 11 | files.forEach(file => { 12 | const packageJson = JSON.parse(fs.readFileSync(file)); 13 | 14 | fs.writeFileSync( 15 | file, 16 | JSON.stringify( 17 | { 18 | ...packageJson, 19 | version, 20 | }, 21 | null, 22 | JSON_INDENTATION_LEVEL, 23 | ), 24 | ); 25 | }); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature request 3 | about: Suggest an idea for this project 4 | title: '[FEATURE]' 5 | labels: '' 6 | assignee: vladimirpotekhin 7 | --- 8 | 9 | # 🚀 Feature request 10 | 11 | ### Is your feature request related to a problem? 12 | 13 | 14 | I'm always frustrated when... 15 | 16 | ### Describe the solution you'd like 17 | 18 | 19 | 20 | 21 | ### Describe alternatives you've considered 22 | 23 | 24 | 25 | 26 | ### Additional context 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /scripts/postbuild.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const DIST_LIB_PATH = 'dist/geolocation/'; 4 | const README_PATH = 'README.md'; 5 | const ASSETS_PATH = 'projects/demo/src/assets'; 6 | const PATH_TO_README = DIST_LIB_PATH + README_PATH; 7 | 8 | copyExtraFiles(); 9 | 10 | function copyExtraFiles() { 11 | if (!fs.existsSync(README_PATH)) { 12 | throw new Error('Requested files do not exit'); 13 | } else { 14 | copyReadmeIntoDistFolder(README_PATH, PATH_TO_README); 15 | } 16 | } 17 | 18 | function copyReadmeIntoDistFolder(srcPath, toPath) { 19 | const fileBody = fs.readFileSync(srcPath).toString(); 20 | const withoutLogos = fileBody 21 | .replace(`![ng-web-apis logo](${ASSETS_PATH}/logo.svg) `, '') 22 | .replace(` `, ''); 23 | 24 | fs.writeFileSync(toPath, withoutLogos); 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled schematics 2 | schematics/library-starter/*.js 3 | schematics/library-starter/*.js.map 4 | schematics/library-starter/*.d.ts 5 | 6 | # compiled output 7 | /dist 8 | /tmp 9 | /out-tsc 10 | # Only exists if Bazel was run 11 | /bazel-out 12 | 13 | # dependencies 14 | /node_modules 15 | 16 | # profiling files 17 | chrome-profiler-events.json 18 | speed-measure-plugin.json 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | .history/* 36 | 37 | # misc 38 | /.sass-cache 39 | /connect.lock 40 | /coverage 41 | /libpeerconnection.log 42 | npm-debug.log 43 | yarn-error.log 44 | testem.log 45 | /typings 46 | 47 | # System Files 48 | .DS_Store 49 | Thumbs.db 50 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Web APIs CI 2 | 3 | on: push 4 | 5 | jobs: 6 | ci: 7 | # Setup part 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Use Node.js 12 | uses: actions/setup-node@v1 13 | with: 14 | node-version: '12.x' 15 | - name: Cache Node.js modules 16 | uses: actions/cache@v2 17 | with: 18 | path: ~/.npm 19 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} 20 | restore-keys: | 21 | ${{ runner.OS }}-node- 22 | ${{ runner.OS }}- 23 | - name: Install dependencies 24 | run: npm ci 25 | # End of setup 26 | - run: | 27 | npm run build 28 | npm run test 29 | npm run lint 30 | - name: Coveralls 31 | uses: coverallsapp/github-action@master 32 | with: 33 | github-token: ${{ secrets.GITHUB_TOKEN }} 34 | path-to-lcov: ./coverage/geolocation/report-lcov/lcov.info -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "downlevelIteration": true, 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "module": "es2020", 10 | "moduleResolution": "node", 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "strict": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "noImplicitReturns": true, 16 | "noUnusedParameters": true, 17 | "noUnusedLocals": true, 18 | "target": "es2015", 19 | "typeRoots": ["node_modules/@types"], 20 | "lib": ["es2018", "dom"], 21 | "paths": { 22 | "@ng-web-apis/geolocation": ["projects/geolocation/src/public-api"] 23 | } 24 | }, 25 | "files": ["projects/demo/src/main.browser.ts", "projects/demo/src/polyfills.ts"], 26 | "include": ["projects/demo/src/**/*.d.ts"] 27 | } 28 | -------------------------------------------------------------------------------- /projects/demo/src/styles.css: -------------------------------------------------------------------------------- 1 | @import '~highlight.js/styles/github.css'; 2 | body, 3 | html { 4 | margin: 0; 5 | height: 100%; 6 | font-family: Roboto, 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 7 | 'Lucida Grande', sans-serif; 8 | color: #444; 9 | } 10 | 11 | header { 12 | display: flex; 13 | width: 100%; 14 | max-width: 800px; 15 | margin: 0 auto; 16 | padding: 40px 10px; 17 | box-sizing: border-box; 18 | border-bottom: 1px solid gainsboro; 19 | } 20 | 21 | main { 22 | flex: 1; 23 | display: flex; 24 | justify-content: center; 25 | flex-direction: column; 26 | padding: 40px 0; 27 | max-width: 700px; 28 | margin: 0 auto; 29 | } 30 | 31 | footer { 32 | padding: 16px; 33 | font-size: 12px; 34 | border-top: 1px solid gainsboro; 35 | text-align: center; 36 | } 37 | 38 | a { 39 | color: #1976d2; 40 | text-decoration: none; 41 | } 42 | 43 | .logo { 44 | margin-right: 20px; 45 | } 46 | -------------------------------------------------------------------------------- /projects/geolocation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ng-web-apis/geolocation", 3 | "version": "2.0.0", 4 | "peerDependencies": { 5 | "@angular/common": ">=6.0.0", 6 | "@angular/core": ">=6.0.0", 7 | "@ng-web-apis/common": ">=1.0.0" 8 | }, 9 | "description": "This is a library for declarative use of Geolocation API with Angular", 10 | "keywords": [ 11 | "angular", 12 | "ng", 13 | "geolocation", 14 | "geolocation api", 15 | "pwa", 16 | "progressive web app" 17 | ], 18 | "license": "MIT", 19 | "author": { 20 | "name": "Vladimir Potekhin", 21 | "email": "vladimir.potekh@gmail.com" 22 | }, 23 | "contributors": [ 24 | "Alex Inkin ", 25 | "Roman Sedov <79601794011@ya.ru>" 26 | ], 27 | "repository": "https://github.com/ng-web-apis/geolocation", 28 | "bugs": "https://github.com/ng-web-apis/geolocation/issues", 29 | "dependencies": { 30 | "tslib": "^2.0.0" 31 | }, 32 | "homepage": "https://github.com/ng-web-apis/geolocation#README" 33 | } 34 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## PR Checklist 2 | 3 | Please check if your PR fulfills the following requirements: 4 | 5 | - [ ] The commit message follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) 6 | - [ ] Tests for the changes have been added (for bug fixes / features) 7 | - [ ] Docs have been added / updated (for bug fixes / features) 8 | 9 | ## PR Type 10 | 11 | What kind of change does this PR introduce? 12 | 13 | 14 | 15 | - [ ] Bugfix 16 | - [ ] Feature 17 | - [ ] Refactoring (no functional changes, no api changes) 18 | - [ ] Other... Please describe: 19 | 20 | ## What is the current behavior? 21 | 22 | 23 | 24 | Issue Number: N/A 25 | 26 | ## What is the new behavior? 27 | 28 | ## Does this PR introduce a breaking change? 29 | 30 | - [ ] Yes 31 | - [ ] No 32 | 33 | 34 | 35 | ## Other information 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vladimir Potekhin 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. -------------------------------------------------------------------------------- /projects/geolocation/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vladimir Potekhin 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. -------------------------------------------------------------------------------- /projects/demo/src/app/map/map.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 14 | 15 | 21 | 22 | 23 |
24 |
25 |
long: {{ currentCoords.longitude }}
26 |
lat: {{ currentCoords.latitude }}
27 |
28 |
29 | -------------------------------------------------------------------------------- /projects/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "2.0.0", 4 | "private": true, 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build" 9 | }, 10 | "dependencies": { 11 | "@angular/common": "^8.2.4", 12 | "@angular/compiler": "^8.2.4", 13 | "@angular/core": "^8.2.4", 14 | "@angular/forms": "^8.2.4", 15 | "@angular/platform-browser": "^8.2.4", 16 | "@angular/platform-browser-dynamic": "8.2.0", 17 | "@angular/router": "8.2.0", 18 | "core-js": "2.6.9", 19 | "rxjs": "6.5.2", 20 | "zone.js": "0.9.1", 21 | "@ng-web-apis/geolocation": "latest", 22 | "@ng-web-apis/common": "1.0.1", 23 | "highlight.js": "^9.15.5", 24 | "ngx-highlightjs": "3.0.3" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "^0.803.2", 28 | "@angular/cli": "^8.3.2", 29 | "@angular/compiler-cli": "^8.2.4", 30 | "@angular/language-service": "^8.2.4", 31 | "@types/highlight.js": "^9.12.3", 32 | "@types/node": "~8.9.4", 33 | "ts-node": "~7.0.0", 34 | "tslint": "~5.11.0", 35 | "typescript": "~3.4.5" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | > Thank you for considering contributing to our project. Your help if very welcome! 4 | 5 | When contributing, it's better to first discuss the change you wish to make via issue, 6 | email, or any other method with the owners of this repository before making a change. 7 | 8 | All members of our community are expected to follow our [Code of Conduct](CODE_OF_CONDUCT.md). 9 | Please make sure you are welcoming and friendly in all of our spaces. 10 | 11 | ## Getting started 12 | 13 | In order to make your contribution please make a fork of the repository. After you've pulled 14 | the code, follow these steps to kick start the development: 15 | 16 | 1. Run `npm ci` to install dependencies 17 | 2. Run `npm start` to launch demo project where you could test your changes 18 | 3. Use following commands to ensure code quality 19 | 20 | ``` 21 | npm run lint 22 | npm run build 23 | npm run test 24 | ``` 25 | 26 | ## Pull Request Process 27 | 28 | 1. We follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) 29 | in our commit messages, i.e. `feat(core): improve typing` 30 | 2. Update [README.md](README.md) to reflect changes related to public API and everything relevant 31 | 3. Make sure you cover all code changes with unit tests 32 | 4. When you are ready, create Pull Request of your fork into original repository 33 | -------------------------------------------------------------------------------- /projects/demo/src/app/map/map.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from '@angular/core'; 2 | import {DomSanitizer, SafeStyle} from '@angular/platform-browser'; 3 | import {BehaviorSubject} from 'rxjs'; 4 | 5 | @Component({ 6 | selector: 'app-map', 7 | templateUrl: './map.component.html', 8 | styleUrls: ['./map.component.less'], 9 | }) 10 | export class MapComponent { 11 | @Input() 12 | set coordinatesChange(coords: GeolocationCoordinates) { 13 | this.coordsToStyle(coords); 14 | this.currentCoords = coords; 15 | } 16 | 17 | currentCoords: GeolocationCoordinates | null = null; 18 | 19 | initialCoords: GeolocationCoordinates | null = null; 20 | 21 | markerTransform$ = new BehaviorSubject('translate(0px,0px)'); 22 | 23 | constructor(private readonly domSanitizer: DomSanitizer) {} 24 | 25 | private coordsToStyle(coordinates: GeolocationCoordinates) { 26 | if (!this.initialCoords) { 27 | this.initialCoords = coordinates; 28 | 29 | return; 30 | } 31 | 32 | const deltaX = (this.initialCoords.longitude - coordinates.longitude) * 10000; 33 | const deltaY = (this.initialCoords.latitude - coordinates.latitude) * 10000; 34 | const style = `translate(${deltaX}px,${deltaY}px)`; 35 | 36 | const safestyle = this.domSanitizer.bypassSecurityTrustStyle(style); 37 | 38 | this.markerTransform$.next(safestyle); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /projects/demo/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/demo'), 20 | reporters: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['ChromeHeadless'], 29 | singleRun: true, 30 | customLaunchers: { 31 | ChromeHeadless: { 32 | base: 'Chrome', 33 | flags: [ 34 | '--no-sandbox', 35 | '--headless', 36 | '--disable-gpu', 37 | '--remote-debugging-port=9222', 38 | ], 39 | }, 40 | }, 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /projects/geolocation/src/services/geolocation.service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable} from '@angular/core'; 2 | import {Observable} from 'rxjs'; 3 | import {finalize, shareReplay} from 'rxjs/operators'; 4 | import {GEOLOCATION} from '../tokens/geolocation'; 5 | import {POSITION_OPTIONS} from '../tokens/geolocation-options'; 6 | import {GEOLOCATION_SUPPORT} from '../tokens/geolocation-support'; 7 | 8 | // TODO: Replace type with GeolocationPosition after bumping TS to 4.1.3+ 9 | // @dynamic 10 | @Injectable({ 11 | providedIn: 'root', 12 | }) 13 | export class GeolocationService extends Observable[0]> { 14 | constructor( 15 | @Inject(GEOLOCATION) geolocationRef: Geolocation, 16 | @Inject(GEOLOCATION_SUPPORT) geolocationSupported: boolean, 17 | @Inject(POSITION_OPTIONS) 18 | positionOptions: PositionOptions, 19 | ) { 20 | let watchPositionId = 0; 21 | 22 | super(subscriber => { 23 | if (!geolocationSupported) { 24 | subscriber.error('Geolocation is not supported in your browser'); 25 | } 26 | 27 | watchPositionId = geolocationRef.watchPosition( 28 | position => subscriber.next(position), 29 | positionError => subscriber.error(positionError), 30 | positionOptions, 31 | ); 32 | }); 33 | 34 | return this.pipe( 35 | finalize(() => geolocationRef.clearWatch(watchPositionId)), 36 | shareReplay({bufferSize: 1, refCount: true}), 37 | ) as GeolocationService; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /projects/demo/src/assets/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 20 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /projects/geolocation/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/geolocation'), 20 | reporters: [{type: 'lcov', subdir: 'report-lcov'}], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml', 'coverage'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['ChromeHeadless'], 29 | singleRun: true, 30 | customLaunchers: { 31 | ChromeHeadless: { 32 | base: 'Chrome', 33 | flags: [ 34 | '--no-sandbox', 35 | '--headless', 36 | '--disable-gpu', 37 | '--remote-debugging-port=9222', 38 | ], 39 | }, 40 | }, 41 | }); 42 | }; 43 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.browser.module.ts: -------------------------------------------------------------------------------- 1 | import {LocationStrategy, PathLocationStrategy} from '@angular/common'; 2 | import {NgModule} from '@angular/core'; 3 | import {FormsModule} from '@angular/forms'; 4 | import {BrowserModule} from '@angular/platform-browser'; 5 | import {POSITION_OPTIONS} from '@ng-web-apis/geolocation'; 6 | import {HighlightModule, HighlightOptions, HIGHLIGHT_OPTIONS} from 'ngx-highlightjs'; 7 | 8 | import {AppComponent} from './app.component'; 9 | import {AppRoutingModule} from './app.routes'; 10 | import {MapComponent} from './map/map.component'; 11 | 12 | const highlightOptions: HighlightOptions = { 13 | coreLibraryLoader: () => import('highlight.js/lib/highlight'), 14 | languages: { 15 | less: () => import('highlight.js/lib/languages/less'), 16 | typescript: () => import('highlight.js/lib/languages/typescript'), 17 | xml: () => import('highlight.js/lib/languages/xml'), 18 | }, 19 | }; 20 | 21 | @NgModule({ 22 | bootstrap: [AppComponent], 23 | imports: [ 24 | FormsModule, 25 | BrowserModule.withServerTransition({appId: 'demo'}), 26 | AppRoutingModule, 27 | HighlightModule, 28 | ], 29 | declarations: [AppComponent, MapComponent], 30 | providers: [ 31 | { 32 | provide: HIGHLIGHT_OPTIONS, 33 | useValue: highlightOptions, 34 | }, 35 | { 36 | provide: LocationStrategy, 37 | useClass: PathLocationStrategy, 38 | }, 39 | { 40 | provide: POSITION_OPTIONS, 41 | useValue: {enableHighAccuracy: true, timeout: 3000, maximumAge: 1000}, 42 | }, 43 | ], 44 | }) 45 | export class AppBrowserModule {} 46 | -------------------------------------------------------------------------------- /projects/demo/prerender.ts: -------------------------------------------------------------------------------- 1 | // Load zone.js for the server. 2 | import 'reflect-metadata'; 3 | import 'zone.js/node'; 4 | 5 | import {APP_BASE_HREF} from '@angular/common'; 6 | import {enableProdMode} from '@angular/core'; 7 | import {renderModuleFactory} from '@angular/platform-server'; 8 | import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs'; 9 | import {join} from 'path'; 10 | import {PRERENDERED_ROUTES} from './static.paths'; 11 | 12 | enableProdMode(); 13 | 14 | const {AppServerModuleNgFactory} = require('../../server/main'); 15 | const DEMO_FOLDER = join(process.cwd(), 'dist', 'demo', 'browser'); 16 | const index = readFileSync( 17 | join(process.cwd(), 'dist', 'demo', 'browser', 'index.html'), 18 | 'utf8', 19 | ); 20 | const localFallback = 'http://localhost:4200/'; 21 | 22 | let previousRender = Promise.resolve(); 23 | 24 | // Iterate each route path 25 | PRERENDERED_ROUTES.forEach(route => { 26 | const fullPath = join(DEMO_FOLDER, route); 27 | 28 | // Make sure the directory structure is there 29 | if (!existsSync(fullPath)) { 30 | mkdirSync(fullPath); 31 | } 32 | 33 | // Writes rendered HTML to index.html, replacing the file if it already exists. 34 | previousRender = previousRender 35 | .then(() => 36 | renderModuleFactory(AppServerModuleNgFactory, { 37 | document: index, 38 | url: route, 39 | extraProviders: [ 40 | { 41 | provide: APP_BASE_HREF, 42 | useValue: process.env.ORIGIN || localFallback, 43 | }, 44 | ], 45 | }), 46 | ) 47 | .then(html => writeFileSync(join(fullPath, 'index.html'), html)); 48 | }); 49 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [2.0.0](https://github.com/ng-web-apis/geolocation/compare/v1.0.3...v2.0.0) (2022-08-06) 6 | 7 | ### Features 8 | 9 | - **core:** update to ng v12 ([5790424](https://github.com/ng-web-apis/geolocation/commit/579042424018bdab22ab555b2e868757bdd13c4f)) 10 | 11 | ### [1.0.4](https://github.com/ng-web-apis/geolocation/compare/v1.0.3...v1.0.4) (2021-02-05) 12 | 13 | ### Bug Fixes 14 | 15 | - **service:** add type workaround to support TS 4.1+ ([a1091c7](https://github.com/ng-web-apis/geolocation/commit/a1091c73708013be6805edf857aca2cf3578c437)) 16 | 17 | ### [1.0.3](https://github.com/ng-web-apis/geolocation/compare/v1.0.2...v1.0.3) (2020-02-14) 18 | 19 | ### Features 20 | 21 | - **tokens:** add to public api ([816f059](https://github.com/ng-web-apis/geolocation/commit/816f059b87415013675ba0b17f185542520ae5d8)) 22 | 23 | ### [1.0.2](https://github.com/ng-web-apis/geolocation/compare/v1.0.1...v1.0.2) (2020-02-14) 24 | 25 | ### 1.0.1 (2020-02-13) 26 | 27 | ### Features 28 | 29 | - **geolocation:** service and directive add ([98fa113](https://github.com/ng-web-apis/geolocation/commit/98fa1134a715d68aa1589c29aa444a796d8560d3)) 30 | 31 | ### Bug Fixes 32 | 33 | - **GeolocationService:** add [@dynamic](https://github.com/dynamic) ([6b39b3c](https://github.com/ng-web-apis/geolocation/commit/6b39b3c3ec4757fd2fc6f06c94e5f42d9a022e30)) 34 | - **script:** fix postbuild script ([65bbb2e](https://github.com/ng-web-apis/geolocation/commit/65bbb2e0007393a71994640a7ebc01b92a60404a)) 35 | 36 | # Changelog 37 | 38 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 39 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, ChangeDetectorRef, Component} from '@angular/core'; 2 | import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; 3 | import {GeolocationService} from '@ng-web-apis/geolocation'; 4 | import {Subscription} from 'rxjs'; 5 | import {take} from 'rxjs/operators'; 6 | import {SAMPLE} from './samples/sample'; 7 | import {SAMPLE_ASYNC} from './samples/sample-async'; 8 | 9 | @Component({ 10 | selector: 'main', 11 | templateUrl: './app.component.html', 12 | styleUrls: ['./app.style.less'], 13 | changeDetection: ChangeDetectionStrategy.OnPush, 14 | }) 15 | export class AppComponent { 16 | position: GeolocationPosition | null = null; 17 | toggle = false; 18 | currentPositionUrl: SafeResourceUrl | null = null; 19 | watchSubscription: Subscription | null = null; 20 | error: GeolocationPositionError | null = null; 21 | 22 | readonly sample = SAMPLE; 23 | readonly sampleAsync = SAMPLE_ASYNC; 24 | 25 | constructor( 26 | readonly geolocation$: GeolocationService, 27 | private readonly domSanitizer: DomSanitizer, 28 | private readonly changeDetectorRef: ChangeDetectorRef, 29 | ) {} 30 | 31 | getCurrentPosition() { 32 | this.geolocation$.pipe(take(1)).subscribe( 33 | position => { 34 | this.currentPositionUrl = this.getUrl(position); 35 | this.changeDetectorRef.markForCheck(); 36 | }, 37 | error => { 38 | this.error = error; 39 | this.changeDetectorRef.markForCheck(); 40 | }, 41 | ); 42 | } 43 | 44 | toggleWatch() { 45 | this.toggle = !this.toggle; 46 | } 47 | 48 | private getUrl(position: GeolocationPosition): SafeResourceUrl { 49 | const longitude = position.coords.longitude; 50 | const latitude = position.coords.latitude; 51 | 52 | return this.domSanitizer.bypassSecurityTrustResourceUrl( 53 | `//www.openstreetmap.org/export/embed.html?bbox=${longitude - 54 | 0.005},${latitude - 0.005},${longitude + 0.005},${latitude + 55 | 0.005}&marker=${position.coords.latitude},${ 56 | position.coords.longitude 57 | }&layer=mapnik`, 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /projects/demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Geolocation API for Angular 4 | 9 | 15 | 21 | 22 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 |
38 | 45 |
46 |

Geolocation API for Angular

47 | Part of 48 | 49 | Web APIs logo 56 | Web APIs for Angular 57 | 58 |
59 |
60 | 61 |
loading
62 | 63 |
64 | Get it here: 65 | GitHub | 66 | NPM 67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.style.less: -------------------------------------------------------------------------------- 1 | .map { 2 | display: flex; 3 | justify-content: center; 4 | width: 300px; 5 | } 6 | 7 | .wrapper { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | padding: 10px; 12 | } 13 | 14 | footer { 15 | text-align: center; 16 | margin-top: 32px; 17 | } 18 | 19 | .current-position { 20 | display: flex; 21 | align-items: center; 22 | flex-direction: column; 23 | } 24 | 25 | .watch-position { 26 | margin-top: 32px; 27 | display: flex; 28 | flex-direction: column; 29 | align-items: center; 30 | } 31 | 32 | .switch-container { 33 | display: flex; 34 | &__text { 35 | margin-right: 10px; 36 | } 37 | } 38 | 39 | .coordinates { 40 | margin-top: 22px; 41 | } 42 | 43 | .primary-button { 44 | width: 160px; 45 | background-color: #2190e4; 46 | border: none; 47 | color: white; 48 | padding: 10px 10px; 49 | text-align: center; 50 | font-size: 16px; 51 | margin: 4px 2px; 52 | transition: 0.3s; 53 | display: inline-block; 54 | text-decoration: none; 55 | cursor: pointer; 56 | border-radius: 4px; 57 | 58 | &:hover { 59 | background-color: #1d85d4; 60 | } 61 | } 62 | 63 | .switch { 64 | position: relative; 65 | display: inline-block; 66 | width: 30px; 67 | height: 17px; 68 | } 69 | 70 | .switch input { 71 | opacity: 0; 72 | width: 0; 73 | height: 0; 74 | } 75 | 76 | .slider { 77 | position: absolute; 78 | cursor: pointer; 79 | top: 0; 80 | left: 0; 81 | right: 0; 82 | bottom: 0; 83 | background-color: #ccc; 84 | -webkit-transition: 0.4s; 85 | transition: 0.4s; 86 | } 87 | 88 | .slider:before { 89 | position: absolute; 90 | content: ''; 91 | height: 13px; 92 | width: 13px; 93 | left: 2px; 94 | bottom: 2px; 95 | background-color: white; 96 | -webkit-transition: 0.4s; 97 | transition: 0.4s; 98 | } 99 | 100 | input:checked + .slider { 101 | background-color: #2190e4; 102 | } 103 | 104 | input:checked + .slider:before { 105 | -webkit-transform: translateX(13px); 106 | -ms-transform: translateX(13px); 107 | transform: translateX(13px); 108 | } 109 | 110 | .slider.round { 111 | border-radius: 14px; 112 | } 113 | 114 | .slider.round:before { 115 | border-radius: 50%; 116 | } 117 | 118 | pre { 119 | max-width: 90vw; 120 | } 121 | -------------------------------------------------------------------------------- /projects/demo/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "demo": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/demo", 17 | "index": "src/index.html", 18 | "main": "src/main.browser.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "tsconfig.demo.json", 21 | "aot": false, 22 | "assets": [ 23 | { 24 | "glob": "**/*", 25 | "input": "projects/demo/src/assets/", 26 | "output": "./assets/" 27 | }, 28 | "src/favicon.ico" 29 | ], 30 | "styles": ["src/styles.css"], 31 | "scripts": [] 32 | }, 33 | "configurations": { 34 | "production": { 35 | "optimization": true, 36 | "outputHashing": "all", 37 | "sourceMap": false, 38 | "extractCss": true, 39 | "namedChunks": false, 40 | "aot": true, 41 | "extractLicenses": true, 42 | "vendorChunk": false, 43 | "buildOptimizer": true 44 | } 45 | } 46 | }, 47 | "serve": { 48 | "builder": "@angular-devkit/build-angular:dev-server", 49 | "options": { 50 | "browserTarget": "demo:build" 51 | }, 52 | "configurations": { 53 | "production": { 54 | "browserTarget": "demo:build:production" 55 | } 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | "defaultProject": "demo" 62 | } 63 | -------------------------------------------------------------------------------- /projects/demo/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | background 6 | 7 | 8 | 9 | 10 | 11 | 12 | Layer 1 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | Angular does not have any built-in instruments to use 5 | Geolocation API. This is an Observable based 6 | abstraction over Geolocation API to use with 7 | Angular 8 |

9 |
10 | 11 |
Sorry, position is not avalibale: {{ error.message }}
12 | 13 |
14 |

How to use

15 |

16 | Usage is pretty simple: just import service in your component and subscribe to 17 | it. Service extends Observable and will emit the 18 | Position object. 19 |

20 | 21 |

22 |             {{sample}}
23 |         
24 | 25 |

You also can use async pipe

26 | 27 |

28 |             {{sampleAsync}}
29 |         
30 | 31 |
32 |
33 | 36 | 40 |
41 |
42 | 46 |
47 |
48 | 49 |

Single position

50 |
51 |

52 | If you need to get position just once and stop observing user location, 53 | you can subscribe to geolocation$ and use take(1) RxJs 54 | operator. Service is cold, meaning if there are no Subscribers, it doesn't 55 | track position 56 |

57 | 58 | 61 | 62 | 72 |
73 |
74 |
75 | -------------------------------------------------------------------------------- /projects/demo/src/assets/web-api.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | background 6 | 7 | 8 | 9 | 10 | 11 | 12 | Layer 1 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project at alexander@inkin.ru. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /projects/geolocation/src/services/geolocation.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | import {EMPTY, interval, timer} from 'rxjs'; 3 | import {catchError, skip, take} from 'rxjs/operators'; 4 | import {GEOLOCATION} from '../tokens/geolocation'; 5 | import {GEOLOCATION_SUPPORT} from '../tokens/geolocation-support'; 6 | import {GeolocationService} from './geolocation.service'; 7 | 8 | describe('Geolocation service', () => { 9 | let service: GeolocationService; 10 | let clearWatchCount: number; 11 | 12 | class FakeGeolocation { 13 | watchPosition(success: Function, error: Function) { 14 | interval(300).subscribe(number => success(number.toString())); 15 | timer(1000) 16 | .pipe(take(1)) 17 | .subscribe(() => error('error')); 18 | } 19 | 20 | clearWatch() { 21 | clearWatchCount++; 22 | } 23 | } 24 | 25 | beforeEach(() => { 26 | TestBed.configureTestingModule({ 27 | providers: [ 28 | {provide: GEOLOCATION, useClass: FakeGeolocation}, 29 | GeolocationService, 30 | ], 31 | }); 32 | 33 | service = TestBed.get(GeolocationService).pipe( 34 | catchError((_err, caught) => caught), 35 | ); 36 | clearWatchCount = 0; 37 | }); 38 | 39 | it('Gives a position', done => { 40 | service.pipe(take(1)).subscribe(position => { 41 | expect(position).toMatch('0'); 42 | done(); 43 | }); 44 | }); 45 | 46 | it('Provides position from cache if other subscriptions exist', done => { 47 | let firstPosition: GeolocationPosition; 48 | 49 | service.subscribe(position => { 50 | firstPosition = position; 51 | }); 52 | 53 | service.pipe(skip(2), take(1)).subscribe(position => { 54 | expect(position).toEqual(firstPosition); 55 | done(); 56 | }); 57 | }); 58 | 59 | it('clearWatch method is called once when all subscribers are unsubscribed.', done => { 60 | const firstSubscription = service.subscribe(); 61 | 62 | const secondSubscription = service.subscribe(); 63 | 64 | firstSubscription.unsubscribe(); 65 | secondSubscription.unsubscribe(); 66 | 67 | expect(clearWatchCount).toEqual(1); 68 | done(); 69 | }); 70 | 71 | it('clearWatch method is not called if none of the subscribers unsubscribed', done => { 72 | service.subscribe(); 73 | service.subscribe(); 74 | 75 | expect(clearWatchCount).toEqual(0); 76 | done(); 77 | }); 78 | 79 | it('Error', done => { 80 | service = TestBed.get(GeolocationService); 81 | 82 | service 83 | .pipe( 84 | catchError(error => { 85 | expect(error).toBe('error'); 86 | done(); 87 | 88 | return EMPTY; 89 | }), 90 | ) 91 | .subscribe(); 92 | }); 93 | }); 94 | 95 | describe('Geolocation Service if unsupported', () => { 96 | it('cannot recieve and throws an error if Geolocation is not supported', done => { 97 | TestBed.configureTestingModule({ 98 | providers: [ 99 | {provide: GEOLOCATION_SUPPORT, useValue: false}, 100 | GeolocationService, 101 | ], 102 | }); 103 | 104 | const service$: GeolocationService = TestBed.get(GeolocationService); 105 | 106 | service$.subscribe( 107 | () => {}, 108 | error => { 109 | expect(error).toBe('Geolocation is not supported in your browser'); 110 | done(); 111 | }, 112 | ); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /projects/demo/server.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js/dist/zone-node'; 2 | 3 | import {APP_BASE_HREF} from '@angular/common'; 4 | import {enableProdMode} from '@angular/core'; 5 | import {ngExpressEngine} from '@nguniversal/express-engine'; 6 | import * as express from 'express'; 7 | import {existsSync} from 'fs'; 8 | import {join} from 'path'; 9 | 10 | import {AppServerModule} from './src/main.server'; 11 | 12 | // The Express app is exported so that it can be used by serverless Functions. 13 | export function app(): express.Express { 14 | enableProdMode(); 15 | 16 | const server = express(); 17 | const distFolder = join(process.cwd(), 'dist/demo/browser'); 18 | const indexHtml = existsSync(join(distFolder, 'index.original.html')) 19 | ? 'index.original.html' 20 | : 'index'; 21 | 22 | // Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine) 23 | server.engine( 24 | 'html', 25 | ngExpressEngine({ 26 | bootstrap: AppServerModule, 27 | }), 28 | ); 29 | 30 | server.set('view engine', 'html'); 31 | server.set('views', distFolder); 32 | 33 | // Example Express Rest API endpoints 34 | // server.get('/api/**', (req, res) => { }); 35 | // Serve static files from /browser 36 | server.get( 37 | '*.*', 38 | express.static(distFolder, { 39 | maxAge: '1y', 40 | }), 41 | ); 42 | 43 | // All regular routes use the Universal engine 44 | server.get('*', (req, res) => { 45 | // Add information on current browser and location 46 | addToGlobal( 47 | 'location', 48 | new URL(`${req.protocol}://${req.get('host')}${req.originalUrl}`), 49 | ); 50 | addToGlobal('navigator', {userAgent: req.get('user-agent')}); 51 | 52 | res.render(indexHtml, { 53 | req, 54 | providers: [{provide: APP_BASE_HREF, useValue: req.baseUrl}], 55 | }); 56 | 57 | function addToGlobal(key: string, value: any) { 58 | (global as any)[key] = value; 59 | } 60 | }); 61 | 62 | return server; 63 | } 64 | 65 | function run(): void { 66 | const port = process.env.PORT || 4000; 67 | 68 | // Start up the Node server 69 | const server = app(); 70 | 71 | server.listen(port, () => { 72 | // tslint:disable-next-line:no-console 73 | console.log(`Node Express server listening on http://localhost:${port}`); 74 | }); 75 | } 76 | 77 | // Webpack will replace 'require' with '__webpack_require__' 78 | // '__non_webpack_require__' is a proxy to Node 'require' 79 | // The below code is to ensure that the server is run only when not requiring the bundle. 80 | declare const __non_webpack_require__: NodeRequire; 81 | 82 | const mainModule = __non_webpack_require__.main; 83 | const moduleFilename = (mainModule && mainModule.filename) || ''; 84 | 85 | if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { 86 | run(); 87 | } 88 | 89 | export * from './src/main.server'; 90 | 91 | /** 92 | * Workaround for the issue with ngx-highlightjs@5.0.0 not working in SSR mode. 93 | * Latest version potentially works with it (need to be verified). However, 94 | * version 5.0.0 seems to be most appropriate to use with ng v12. 95 | */ 96 | if (!global['requestAnimationFrame']) { 97 | global['requestAnimationFrame'] = (callback: any): any => { 98 | let lastTime = 0; 99 | const currTime = new Date().getTime(); 100 | const timeToCall = Math.max(0, 16 - (currTime - lastTime)); 101 | const id = setTimeout(() => { 102 | callback(currTime + timeToCall); 103 | }, timeToCall); 104 | 105 | lastTime = currTime + timeToCall; 106 | 107 | return id; 108 | }; 109 | 110 | // tslint:disable-next-line:arrow-parens 111 | global['cancelAnimationFrame'] = id => { 112 | clearTimeout(id); 113 | }; 114 | } 115 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ng-web-apis/geolocation", 3 | "version": "2.0.0", 4 | "description": "This is a library for declarative use of Geolocation API with Angular", 5 | "keywords": ["angular", "ng", "Geolocation api", "pwa", "progressive web app"], 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "start:ssr": "npm run build:demo:ssr && npm run serve:ssr", 10 | "start:prerender": "npm run build:demo:prerender && npm run serve:prerender", 11 | "build": "ng build", 12 | "build:demo:client": "ng run demo:build", 13 | "build:demo:server": "ng run demo:server", 14 | "build:demo:ssr": "npm run build:demo:client && npm run build:demo:server && npm run compile:server", 15 | "build:demo:prerender": "npm run build:demo:ssr && npm run generate:prerender", 16 | "serve:ssr": "node dist/demo/server/main.js", 17 | "serve:prerender": "cd dist/demo/browser && http-server", 18 | "compile:server": "tsc -p ./projects/demo/tsconfig.ssr.json", 19 | "generate:prerender": "node dist/demo/ssr/prerender", 20 | "test": "ng test", 21 | "postadd": "git add ./projects", 22 | "lint": "ng lint", 23 | "typecheck": "tsc --noEmit --skipLibCheck", 24 | "release": "standard-version", 25 | "release:patch": "npm run release -- --release-as patch", 26 | "release:minor": "npm run release -- --release-as minor", 27 | "release:major": "npm run release -- --release-as major", 28 | "build:all": "npm run build:geolocation", 29 | "publish:all": "npm run publish:geolocation", 30 | "build:geolocation": "ng run geolocation:build", 31 | "test:geolocation": "ng run geolocation:test", 32 | "test:geolocation:watch": "ng run geolocation:test --watch=true", 33 | "publish": "npm run build && npm publish ./dist/geolocation", 34 | "postbuild": "node scripts/postbuild.js", 35 | "dev:ssr": "ng run demo:serve-ssr", 36 | "build:ssr": "ng build --prod && ng run demo:server:production", 37 | "prerender": "ng run demo:prerender" 38 | }, 39 | "license": "MIT", 40 | "author": { 41 | "name": "Vladimir Potekhin", 42 | "email": "vladimir.potekh@gmail.com" 43 | }, 44 | "contributors": [ 45 | "Alex Inkin ", 46 | "Roman Sedov <79601794011@ya.ru>" 47 | ], 48 | "repository": "https://github.com/ng-web-apis/geolocation", 49 | "bugs": "https://github.com/ng-web-apis/geolocation/issues", 50 | "homepage": "https://github.com/ng-web-apis/geolocation#README", 51 | "dependencies": { 52 | "@angular/animations": "^12.2.16", 53 | "@angular/common": "^12.2.16", 54 | "@angular/compiler": "^12.2.16", 55 | "@angular/core": "^12.2.16", 56 | "@angular/forms": "^12.2.16", 57 | "@angular/platform-browser": "^12.2.16", 58 | "@angular/platform-browser-dynamic": "^12.2.16", 59 | "@angular/platform-server": "^12.2.16", 60 | "@angular/router": "^12.2.16", 61 | "@nguniversal/common": "^11.2.1", 62 | "@nguniversal/express-engine": "^11.2.1", 63 | "core-js": "^2.5.4", 64 | "express": "^4.15.2", 65 | "highlight.js": "^9.18.1", 66 | "ngx-highlightjs": "^5.0.0", 67 | "rxjs": "^6.6.7", 68 | "tslib": "^2.0.0", 69 | "zone.js": "~0.11.4" 70 | }, 71 | "devDependencies": { 72 | "@angular-devkit/build-angular": "~12.2.18", 73 | "@angular-devkit/core": "^12.2.18", 74 | "@angular/cli": "^12.2.18", 75 | "@angular/compiler-cli": "^12.2.16", 76 | "@angular/language-service": "^12.2.16", 77 | "@ng-web-apis/common": "^1.0.1", 78 | "@nguniversal/builders": "^11.2.1", 79 | "@tinkoff/linters": "^0.4.0", 80 | "@types/express": "4.16.1", 81 | "@types/express-serve-static-core": "4.16.2", 82 | "@types/highlight.js": "^9.12.4", 83 | "@types/jasmine": "~3.6.0", 84 | "@types/jasminewd2": "^2.0.6", 85 | "@types/node": "^12.11.1", 86 | "codelyzer": "^6.0.0", 87 | "coveralls": "^3.0.5", 88 | "ecstatic": "^4.1.2", 89 | "express": "^4.17.1", 90 | "http-server": "^0.11.1", 91 | "husky": "^3.0.2", 92 | "jasmine-core": "~3.6.0", 93 | "jasmine-spec-reporter": "~5.0.0", 94 | "karma": "~6.4.0", 95 | "karma-chrome-launcher": "~3.1.0", 96 | "karma-coverage": "^2.2.0", 97 | "karma-jasmine": "~4.0.0", 98 | "karma-jasmine-html-reporter": "^1.5.0", 99 | "lint-staged": "^9.2.1", 100 | "lodash": "^4.17.15", 101 | "ng-packagr": "^12.2.7", 102 | "prettier": "^1.18.2", 103 | "standard-version": "^8.0.1", 104 | "ts-node": "^8.3.0", 105 | "tslint": "~6.1.0", 106 | "tsutils": "^3.17.1", 107 | "typescript": "~4.3.5" 108 | }, 109 | "husky": { 110 | "hooks": { 111 | "pre-commit": "lint-staged && npm run typecheck" 112 | } 113 | }, 114 | "lint-staged": { 115 | "*.{js,ts,html,md,less,json}": ["prettier --write", "git add"], 116 | "*.ts": "tslint" 117 | }, 118 | "standard-version": { 119 | "scripts": { 120 | "postbump": "node scripts/syncVersions.js && git add **/package.json" 121 | } 122 | }, 123 | "engines": { 124 | "node": ">= 10", 125 | "npm": ">= 3" 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "demo": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "projects/demo", 10 | "sourceRoot": "projects/demo/src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "baseHref": "/geolocation/", 17 | "deployUrl": "/geolocation/", 18 | "outputPath": "dist/demo/browser", 19 | "index": "projects/demo/src/index.html", 20 | "main": "projects/demo/src/main.browser.ts", 21 | "polyfills": "projects/demo/src/polyfills.ts", 22 | "tsConfig": "tsconfig.json", 23 | "assets": [ 24 | { 25 | "glob": "**/*", 26 | "input": "projects/demo/src/assets/", 27 | "output": "./assets/" 28 | }, 29 | "projects/demo/src/favicon.ico" 30 | ], 31 | "styles": ["projects/demo/src/styles.css"], 32 | "scripts": [], 33 | "vendorChunk": true, 34 | "extractLicenses": false, 35 | "buildOptimizer": false, 36 | "sourceMap": true, 37 | "optimization": false, 38 | "namedChunks": true 39 | }, 40 | "configurations": { 41 | "production": { 42 | "baseHref": "/geolocation/", 43 | "deployUrl": "/geolocation/", 44 | "optimization": true, 45 | "outputHashing": "all", 46 | "sourceMap": false, 47 | "namedChunks": false, 48 | "extractLicenses": true, 49 | "vendorChunk": false, 50 | "buildOptimizer": true, 51 | "budgets": [ 52 | { 53 | "type": "initial", 54 | "maximumWarning": "2mb", 55 | "maximumError": "5mb" 56 | }, 57 | { 58 | "type": "anyComponentStyle", 59 | "maximumWarning": "6kb" 60 | } 61 | ] 62 | } 63 | }, 64 | "defaultConfiguration": "" 65 | }, 66 | "serve": { 67 | "builder": "@angular-devkit/build-angular:dev-server", 68 | "options": { 69 | "browserTarget": "demo:build" 70 | }, 71 | "configurations": { 72 | "production": { 73 | "browserTarget": "demo:build:production" 74 | } 75 | } 76 | }, 77 | "server": { 78 | "builder": "@angular-devkit/build-angular:server", 79 | "options": { 80 | "outputPath": "dist/demo/server", 81 | "main": "projects/demo/server.ts", 82 | "tsConfig": "projects/demo/tsconfig.server.json", 83 | "sourceMap": true, 84 | "optimization": false 85 | }, 86 | "defaultConfiguration": "" 87 | }, 88 | "lint": { 89 | "builder": "@angular-devkit/build-angular:tslint", 90 | "options": { 91 | "tsConfig": ["tsconfig.json"], 92 | "exclude": ["**/node_modules/**"] 93 | } 94 | }, 95 | "serve-ssr": { 96 | "builder": "@nguniversal/builders:ssr-dev-server", 97 | "options": { 98 | "browserTarget": "demo:build", 99 | "serverTarget": "demo:server" 100 | }, 101 | "configurations": { 102 | "production": { 103 | "browserTarget": "demo:build:production", 104 | "serverTarget": "demo:server:production" 105 | } 106 | } 107 | }, 108 | "prerender": { 109 | "builder": "@nguniversal/builders:prerender", 110 | "options": { 111 | "browserTarget": "demo:build:production", 112 | "serverTarget": "demo:server:production", 113 | "routes": ["/"] 114 | }, 115 | "configurations": { 116 | "production": {} 117 | } 118 | } 119 | } 120 | }, 121 | "geolocation": { 122 | "projectType": "library", 123 | "root": "projects/geolocation", 124 | "sourceRoot": "projects/geolocation/src", 125 | "architect": { 126 | "build": { 127 | "builder": "@angular-devkit/build-angular:ng-packagr", 128 | "options": { 129 | "tsConfig": "projects/geolocation/tsconfig.lib.json", 130 | "project": "projects/geolocation/ng-package.json" 131 | }, 132 | "configurations": { 133 | "production": { 134 | "tsConfig": "projects/geolocation/tsconfig.lib.prod.json" 135 | } 136 | } 137 | }, 138 | "test": { 139 | "builder": "@angular-devkit/build-angular:karma", 140 | "options": { 141 | "main": "projects/geolocation/src/test.ts", 142 | "tsConfig": "projects/geolocation/tsconfig.spec.json", 143 | "karmaConfig": "projects/geolocation/karma.conf.js", 144 | "codeCoverage": true, 145 | "browsers": "ChromeHeadless" 146 | } 147 | }, 148 | "lint": { 149 | "builder": "@angular-devkit/build-angular:tslint", 150 | "options": { 151 | "tsConfig": [ 152 | "projects/geolocation/tsconfig.lib.json", 153 | "projects/geolocation/tsconfig.spec.json" 154 | ], 155 | "exclude": ["**/node_modules/**"] 156 | } 157 | } 158 | } 159 | } 160 | }, 161 | "defaultProject": "geolocation" 162 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ___ 2 | ___ 3 | **Attention!** This repository is archived and the library has been moved to [tinkoff/ng-web-apis](https://github.com/Tinkoff/ng-web-apis) monorepository 4 | ___ 5 | ___ 6 | # ![ng-web-apis logo](projects/demo/src/assets/logo.svg) Geolocation API for Angular 7 | 8 | > Part of [Web APIs for Angular](https://ng-web-apis.github.io/) 9 | 10 | [![npm version](https://img.shields.io/npm/v/@ng-web-apis/geolocation.svg)](https://npmjs.com/package/@ng-web-apis/geolocation) 11 | ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@ng-web-apis/geolocation) 12 | [![.github/workflows/ci.yml](https://github.com/ng-web-apis/geolocation/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ng-web-apis/geolocation/actions/workflows/ci.yml) 13 | [![Coveralls github](https://img.shields.io/coveralls/github/ng-web-apis/geolocation)](https://coveralls.io/github/ng-web-apis/geolocation?branch=master) 14 | [![angular-open-source-starter](https://img.shields.io/badge/made%20with-angular--open--source--starter-d81676?logo=angular)](https://github.com/TinkoffCreditSystems/angular-open-source-starter) 15 | 16 | This is an `Observable` based abstraction over [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) to use with Angular 17 | 18 | ## Install 19 | 20 | If you do not have [@ng-web-apis/common](https://github.com/ng-web-apis/common): 21 | 22 | ``` 23 | npm i @ng-web-apis/common 24 | ``` 25 | 26 | Now install the package: 27 | 28 | ``` 29 | npm i @ng-web-apis/geolocation 30 | ``` 31 | 32 | ## How to use 33 | 34 | ### GeolocationService 35 | 36 | `GeolocationService` is an `Observable`, that emits [Position](https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPosition) object 37 | 38 | Import service in your component: 39 | 40 | ```js 41 | import {GeolocationService} from '@ng-web-apis/geolocation'; 42 | 43 | ... 44 | constructor(private readonly geolocation$: GeolocationService) {} 45 | ``` 46 | 47 | Now, to observe user position, you can subscribe to `geolocation$`: 48 | 49 | ```js 50 | geolocation$.subscribe(position => doSomethingWithPosition(position)); 51 | ``` 52 | 53 | If you need to get position just once and stop observing user location, you can subscribe to `geolocation$` and use `take(1)` RxJs operator: 54 | 55 | ```js 56 | geolocation$.pipe(take(1)).subscribe(position => doSomethingWithPosition(position)); 57 | ``` 58 | 59 | Or you can use async pipe to get position directly in template: 60 | 61 | ```html 62 |
63 | {{position.coords.latitude}} 64 |
65 | ``` 66 | 67 | Service is cold, meaning if there are no active subscriptions, it doesn't track position. 68 | 69 | ## Tokens 70 | 71 | The library also provides some tokens to simplify working with [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API): 72 | 73 | - `GEOLOCATION_SUPPORT` returns `true` if user's browser supports 74 | [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API) 75 | 76 | ```js 77 | export class YourComponent { 78 | constructor( 79 | @Inject(GEOLOCATION_SUPPORT) private readonly geolocationSupport: boolean 80 | ) {} 81 | ... 82 | ``` 83 | 84 | - You can provide [PositionOptions](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions) 85 | through `POSITION_OPTIONS` token with optional properties named `enableHighAccuracy`, `timeout` and `maximumAge`. 86 | It uses `{}` by default. 87 | 88 | ```js 89 | @NgModule({ 90 | ... 91 | providers: [ 92 | { 93 | provide: POSITION_OPTIONS, 94 | useValue: {enableHighAccuracy: true, timeout: 3000, maximumAge: 1000}, 95 | }, 96 | ], 97 | }) 98 | export class AppModule {} 99 | ``` 100 | 101 | - [navigator.geolocation](https://developer.mozilla.org/ru/docs/Web/API/Navigator/geolocation) 102 | can be injected through `GEOLOCATION` token. 103 | 104 | ## Browser support 105 | 106 | | [IE / Edge](http://godban.github.io/browsers-support-badges/)
| [Firefox](http://godban.github.io/browsers-support-badges/)
| [Chrome](http://godban.github.io/browsers-support-badges/)
| [Safari](http://godban.github.io/browsers-support-badges/)
| [iOS Safari](http://godban.github.io/browsers-support-badges/)
| 107 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 108 | | 9+ | 3.5+ | 5+ | 5+ | 3.2+ | 109 | 110 | ## Demo 111 | 112 | You can [try online demo here](https://ng-web-apis.github.io/geolocation) 113 | 114 | ## See also 115 | 116 | Other [Web APIs for Angular](https://ng-web-apis.github.io/) by [@ng-web-apis](https://github.com/ng-web-apis) 117 | 118 | ## Open-source 119 | 120 | Do you also want to open-source something, but hate the collateral work? 121 | Check out this [Angular Open-source Library Starter](https://github.com/TinkoffCreditSystems/angular-open-source-starter) 122 | we’ve created for our projects. It got you covered on continuous integration, 123 | pre-commit checks, linting, versioning + changelog, code coverage and all that jazz. 124 | --------------------------------------------------------------------------------