Skip to content

Commit

Permalink
feat: to-anchor.pipe
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphaël Balet committed Mar 27, 2024
1 parent a07ef17 commit 51f32ec
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 26 deletions.
37 changes: 31 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ A library that allows href to understand Angular's router while retaining its de
2. Support scroll with the `#` attributes and let you configure the [scrolling logic](#scroll-logic)
3. Automatically append `rel="nooepener"` & `target="_blank"` to external link [if wished so](#installation)
4. Support using `href` with the html `button` [attribute](#directive)
5. Enable easy `Scroll when ready` mechanism
6. Let you transform text to well formatted `anchor`

## Demo
- https://stackblitz.com/~/github.com/rbalet/ngx-href
Expand All @@ -32,6 +34,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
* defaultOffset="0"
* navbarOffset="0"
* rel=undefined
* retryTimeout=undefined
* target="_self"
**/
ngxHrefModule.forRoot({}),
Expand All @@ -43,6 +46,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
defaultOffset:"30",
navbarOffset:"60",
rel:"noopener nofollow",
retryTimeout: 300,
target:"_blank",
}),
],
Expand Down Expand Up @@ -99,6 +103,14 @@ ngAfterContentInit(): void {
}
```

### retryTimeout
**Default:** `undefined`
**Accepted value:** `number`

Trigger a second `scrollTo` event after `retryTimeout` milliseconds.

**Note:** This should be avoided, prefer playing with skeleton and fixed height


## External link
### Rel attribute
Expand All @@ -119,17 +131,15 @@ Can also be passed individually directly through html
<a href="https://my-external-url.com" target="_blank">
```

### target attribute


## Usage
Wherever you plan to use the href directive
Wherever you plan to use the href directive or pipe

```typescript
import { ngxHrefModule } from 'ngx-href'
import { NgxHrefDirective, ToAnchorPipe } from 'ngx-href'

imports: [
ngxHrefModule,
NgxHrefDirective,
NgxHrefPipe,
]
```

Expand Down Expand Up @@ -166,6 +176,20 @@ Normal use
</a>
```

### Pipe: _ToAnchorPipe_
The `toAnchor` pipe let you
1. transform an element ot a correct anchor
example: `my Title $%` will be transform to `my-title`

2. Emit that this anchor have been created, so that we can scroll to that element

```html
<!-- Just transform the title to anchor like string-->
<div [id]="my Title $%"| toAnchor : false"> </div>
<!-- If an href has been previously triggered, scroll to this element -->
<div [id]="my Title $%"| toAnchor"> </div>
```

### Service
```typescript
Expand All @@ -187,6 +211,7 @@ Normal use
<h2 id="myAnchor">A title</h2>
```


## Authors and acknowledgment
* maintainer [Raphaël Balet](https://github.com/rbalet)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-href",
"version": "17.1.2",
"version": "17.2.0",
"license": "MIT",
"author": "Raphael Balet",
"maintainers": [
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-href-tester/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const routes: Routes = [
defaultOffset: 100,
defaultRelAttr: '',
defaultTargetAttr: '_blank',
retryTimeout: 300,
}),
],
bootstrap: [AppComponent],
Expand Down
37 changes: 31 additions & 6 deletions projects/ngx-href/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ A library that allows href to understand Angular's router while retaining its de
2. Support scroll with the `#` attributes and let you configure the [scrolling logic](#scroll-logic)
3. Automatically append `rel="nooepener"` & `target="_blank"` to external link [if wished so](#installation)
4. Support using `href` with the html `button` [attribute](#directive)
5. Enable easy `Scroll when ready` mechanism
6. Let you transform text to well formatted `anchor`

## Demo
- https://stackblitz.com/~/github.com/rbalet/ngx-href
Expand All @@ -32,6 +34,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
* defaultOffset="0"
* navbarOffset="0"
* rel=undefined
* retryTimeout=undefined
* target="_self"
**/
ngxHrefModule.forRoot({}),
Expand All @@ -43,6 +46,7 @@ import { ngxHrefModule, ngxHrefService } from 'ngx-href'
defaultOffset:"30",
navbarOffset:"60",
rel:"noopener nofollow",
retryTimeout: 300,
target:"_blank",
}),
],
Expand Down Expand Up @@ -99,6 +103,14 @@ ngAfterContentInit(): void {
}
```

### retryTimeout
**Default:** `undefined`
**Accepted value:** `number`

Trigger a second `scrollTo` event after `retryTimeout` milliseconds.

**Note:** This should be avoided, prefer playing with skeleton and fixed height


## External link
### Rel attribute
Expand All @@ -119,17 +131,15 @@ Can also be passed individually directly through html
<a href="https://my-external-url.com" target="_blank">
```

### target attribute


## Usage
Wherever you plan to use the href directive
Wherever you plan to use the href directive or pipe

```typescript
import { ngxHrefModule } from 'ngx-href'
import { NgxHrefDirective, ToAnchorPipe } from 'ngx-href'

imports: [
ngxHrefModule,
NgxHrefDirective,
NgxHrefPipe,
]
```

Expand Down Expand Up @@ -166,6 +176,20 @@ Normal use
</a>
```

### Pipe: _ToAnchorPipe_
The `toAnchor` pipe let you
1. transform an element ot a correct anchor
example: `my Title $%` will be transform to `my-title`

2. Emit that this anchor have been created, so that we can scroll to that element

```html
<!-- Just transform the title to anchor like string-->
<div [id]="my Title $%"| toAnchor : false"> </div>
<!-- If an href has been previously triggered, scroll to this element -->
<div [id]="my Title $%"| toAnchor"> </div>
```

### Service
```typescript
Expand All @@ -187,6 +211,7 @@ Normal use
<h2 id="myAnchor">A title</h2>
```


## Authors and acknowledgment
* maintainer [Raphaël Balet](https://github.com/rbalet)

Expand Down
2 changes: 1 addition & 1 deletion projects/ngx-href/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-href",
"version": "17.1.2",
"version": "17.2.0",
"license": "MIT",
"author": {
"name": "Raphaël Balet",
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-href/src/lib/href.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface NgxHrefServiceConfig {
defaultOffset?: number
defaultRelAttr?: string
defaultTargetAttr?: string
retryTimeout?: number
}
41 changes: 29 additions & 12 deletions projects/ngx-href/src/lib/href.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import { NgxHrefServiceConfig } from './href.interface'
})
export class NgxHrefService {
anchor$: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null)
loadedAnchor$: BehaviorSubject<string | null> = new BehaviorSubject<string | null>(null) // Trigger the scrollTo mechanism from outside

avoidSpam?: boolean
behavior!: ScrollBehavior
defaultOffset!: number
navbarOffset!: number
defaultRelAttr?: string
defaultTargetAttr!: string
retryTimeout?: number

private _actualAnchor = ''
private _actualAnchor?: string

constructor(@Inject(NgxHrefServiceProvider) _config: NgxHrefServiceConfig) {
this.avoidSpam = _config.avoidSpam
Expand All @@ -25,24 +27,29 @@ export class NgxHrefService {
this.navbarOffset = typeof _config.navbarOffset === 'number' ? _config.navbarOffset : 0
this.defaultRelAttr = _config.defaultRelAttr
this.defaultTargetAttr = _config.defaultTargetAttr || '_self'
this.retryTimeout = _config.retryTimeout

this.loadedAnchor$.subscribe((anchor) => {
if (anchor === this._actualAnchor) {
this.scrollTo(anchor, 9) // 9: triggered only once
}
})
}

scrollTo(anchor?: string, counter = 0) {
if (!anchor) return

const newAnchor = anchor.replace(/ /g, '')

if (counter === 0) this.anchor$.next(newAnchor)

if (
!anchor ||
counter >= 10 || // Counter over, this element doesn't exist or the page is too slow
(newAnchor === this._actualAnchor && counter === 0) // Multiple click on the same url
(anchor === this._actualAnchor && counter === 0) // Multiple click on the same url
)
return

this._actualAnchor = newAnchor
if (counter === 0) {
this._actualAnchor = anchor
this.anchor$.next(anchor)
}

const anchorRef = document.getElementById(newAnchor)
const anchorRef = document.getElementById(anchor)

if (anchorRef) {
const offsetPosition =
Expand All @@ -55,11 +62,21 @@ export class NgxHrefService {
behavior: this.behavior,
})

this._actualAnchor = ''
if (this.retryTimeout)
setTimeout(() => {
window.scrollTo({
top: offsetPosition,
behavior: this.behavior,
})
}, this.retryTimeout)

this._actualAnchor = undefined
} else {
setTimeout(() => {
if (anchor !== this._actualAnchor) return

counter++
this.scrollTo(newAnchor, counter)
this.scrollTo(anchor, counter)
}, 200)
}
}
Expand Down
71 changes: 71 additions & 0 deletions projects/ngx-href/src/lib/to-anchor.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Pipe, PipeTransform } from '@angular/core'
import { NgxHrefService } from './href.service'

@Pipe({
standalone: true,
name: 'toAnchor',
})
export class ToAnchorPipe implements PipeTransform {
private _removedChars = [
';',
':',
'!',
'"',
'(',
')',
'[',
']',
'{',
'}',
'*',
'/',
'%',
'^',
'+',
'<',
'=',
'>',
'~',
]

private _replacedChars: { [key: string]: string } = {
' ': '-',
',': '-',
"'": '-',
à: 'a',
â: 'a',
ã: 'a',
ä: 'ae',
ç: 'c',
é: 'e',
è: 'e',
ê: 'e',
ë: 'e',
î: 'i',
ï: 'i',
ñ: 'n',
ô: 'o',
ö: 'oe',
ß: 'ss',
û: 'u',
ü: 'ue',
}

constructor(private _ngxHrefService: NgxHrefService) {}

transform(id: string, emit = true): string {
if (!id) return ''

let anchor = id.toLocaleLowerCase()
Object.entries(this._replacedChars).forEach(([specialChar, replacement]) => {
anchor = anchor.split(specialChar).join(replacement)
})
this._removedChars.forEach((char) => {
anchor = anchor.split(char).join('')
})

if (emit) this._ngxHrefService.loadedAnchor$.next(anchor)

return anchor
}
}
1 change: 1 addition & 0 deletions projects/ngx-href/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
export * from './lib/href.directive'
export * from './lib/href.module'
export * from './lib/href.service'
export * from './lib/to-anchor.pipe'

0 comments on commit 51f32ec

Please sign in to comment.