Skip to content
Snippets Groups Projects
Commit 146d2bab authored by Xiao Gui's avatar Xiao Gui
Browse files

angular elements export complete. introduced animation. markdown converter now...

angular elements export complete. introduced animation. markdown converter now also uses inner content, added highlight to regions search by text, added bigbrain citation
parent 2af52b3f
No related branches found
No related tags found
No related merge requests found
Showing
with 480 additions and 54 deletions
...@@ -3,25 +3,29 @@ ...@@ -3,25 +3,29 @@
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"scripts": { "scripts": {
"dev-server-export": "webpack-dev-server --config webpack.export.js",
"build-export": "webpack --config webpack.export.js",
"build-aot": "webpack --config webpack.aot.js", "build-aot": "webpack --config webpack.aot.js",
"build-min": "webpack --config webpack.prod.js", "build-min": "webpack --config webpack.prod.js",
"build": "webpack --config webpack.dev.js", "build": "webpack --config webpack.dev.js",
"dev-server": "webpack-dev-server --config webpack.dev.js --mode development", "dev-server": "webpack-dev-server --config webpack.dev.js --mode development",
"serve-plugins" : "node src/plugin_examples/server.js", "serve-plugins": "node src/plugin_examples/server.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@angular/common": "^6.0.3", "@angular/animations": "^6.0.7",
"@angular/compiler": "^6.0.3", "@angular/common": "^6.0.7",
"@angular/compiler": "^6.0.7",
"@angular/compiler-cli": "^6.0.3", "@angular/compiler-cli": "^6.0.3",
"@angular/core": "^6.0.3", "@angular/core": "^6.0.7",
"@angular/forms": "^6.0.3", "@angular/elements": "^6.0.7",
"@angular/http": "^6.0.3", "@angular/forms": "^6.0.7",
"@angular/platform-browser": "^6.0.3", "@angular/http": "^6.0.7",
"@angular/platform-browser-dynamic": "^6.0.3", "@angular/platform-browser": "^6.0.7",
"@angular/platform-browser-dynamic": "^6.0.7",
"@ngrx/store": "^6.0.1", "@ngrx/store": "^6.0.1",
"@ngtools/webpack": "^6.0.5", "@ngtools/webpack": "^6.0.5",
"@types/chart.js": "^2.7.20", "@types/chart.js": "^2.7.20",
......
import { Injectable, Renderer2 } from "@angular/core"; import { Injectable } from "@angular/core";
import { Store, select } from "@ngrx/store"; import { Store, select } from "@ngrx/store";
import { ViewerStateInterface, safeFilter } from "../services/stateStore.service"; import { ViewerStateInterface, safeFilter } from "../services/stateStore.service";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
......
...@@ -18,6 +18,7 @@ import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service"; ...@@ -18,6 +18,7 @@ import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service";
import { PluginServices } from "./atlasViewer.pluginService.service"; import { PluginServices } from "./atlasViewer.pluginService.service";
import '../res/css/extra_styles.css' import '../res/css/extra_styles.css'
import { NehubaContainer } from "../ui/nehubaContainer/nehubaContainer.component";
@Component({ @Component({
selector: 'atlas-viewer', selector: 'atlas-viewer',
...@@ -33,16 +34,14 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ...@@ -33,16 +34,14 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
@ViewChild('floatingContainer', { read: ViewContainerRef }) floatingContainer: ViewContainerRef @ViewChild('floatingContainer', { read: ViewContainerRef }) floatingContainer: ViewContainerRef
@ViewChild('databrowser', { read: ElementRef }) databrowser: ElementRef @ViewChild('databrowser', { read: ElementRef }) databrowser: ElementRef
@ViewChild('temporaryContainer', { read: ViewContainerRef }) temporaryContainer: ViewContainerRef @ViewChild('temporaryContainer', { read: ViewContainerRef }) temporaryContainer: ViewContainerRef
@ViewChild('toastContainer', { read: ViewContainerRef }) toastContainer: ViewContainerRef @ViewChild('toastContainer', { read: ViewContainerRef }) toastContainer: ViewContainerRef
@ViewChild('dedicatedViewerToast', { read: TemplateRef }) dedicatedViewerToast: TemplateRef<any> @ViewChild('dedicatedViewerToast', { read: TemplateRef }) dedicatedViewerToast: TemplateRef<any>
@ViewChild('floatingMouseContextualContainer', { read: ViewContainerRef }) floatingMouseContextualContainer: ViewContainerRef @ViewChild('floatingMouseContextualContainer', { read: ViewContainerRef }) floatingMouseContextualContainer: ViewContainerRef
@ViewChild('pluginFactory', { read: ViewContainerRef }) pluginViewContainerRef: ViewContainerRef @ViewChild('pluginFactory', { read: ViewContainerRef }) pluginViewContainerRef: ViewContainerRef
@ViewChild(LayoutMainSide) layoutMainSide: LayoutMainSide @ViewChild(LayoutMainSide) layoutMainSide: LayoutMainSide
@ViewChild(NehubaContainer) nehubaContainer: NehubaContainer
@HostBinding('attr.darktheme') @HostBinding('attr.darktheme')
darktheme: boolean = false darktheme: boolean = false
...@@ -325,6 +324,24 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ...@@ -325,6 +324,24 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
}) })
} }
rafId : number | null
panelAnimationFlag(flag:boolean){
const redraw = ()=>{
if( this.nehubaContainer && this.nehubaContainer.nehubaViewer && this.nehubaContainer.nehubaViewer.nehubaViewer )
this.nehubaContainer.nehubaViewer.nehubaViewer.redraw()
this.rafId = requestAnimationFrame(()=>redraw())
}
if( flag ){
if(this.rafId)
cancelAnimationFrame(this.rafId)
this.rafId = requestAnimationFrame(()=>redraw())
}else{
cancelAnimationFrame(this.rafId)
this.rafId = null
}
}
clearDedicatedView() { clearDedicatedView() {
this.store.dispatch({ this.store.dispatch({
type: UNLOAD_DEDICATED_LAYER type: UNLOAD_DEDICATED_LAYER
......
<div *ngIf = "meetsRequirement" class = "atlas-container"> <div *ngIf = "meetsRequirement" class = "atlas-container">
<layout-mainside <layout-mainside
(panelShowStateChanged)="manualPanelToggle($event)"> (panelAnimationFlag) = "panelAnimationFlag($event)"
(panelShowStateChanged) = "manualPanelToggle($event)">
<div maincontent> <div maincontent>
<ui-nehuba-container> <ui-nehuba-container>
</ui-nehuba-container> </ui-nehuba-container>
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=720, initial-scale=1.0">
<title>Interactive Viewer Exported Components</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src = "https://unpkg.com/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"></script>
<script src = "export.js"></script>
<script>
document.addEventListener('DOMContentLoaded',()=>{
const script = `
const inputItem = {
"name" : "drinks",
"children" : [{
"name":"coffee",
"children":[{
"name":"flatwhite",
"children":[]
},{
"name":"espresso",
"children":[]
}]
},{
"name" : "tea",
"children" : [{
"name" : "green tea",
"children" : [],
},{
"name" : "black tea",
"children" : []
}]
}]
}
const tree = document.getElementById('tree-element')
tree.setAttribute('input-item',JSON.stringify(inputItem))
`
const treeSampleBox = document.getElementById('tree-element-sample-box')
treeSampleBox.setAttribute('script-input',script)
eval(script);
const markdownIncludeString = `
You will also need \`bootstrap 3.3.7\` for formatting and \`custom-elements-es5-adapter\` for es5 shim:
\`\`\`
<${''}script src = "https://unpkg.com/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js"><${''}/script>
<${''}link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
\`\`\`
To use any of the components, include \`export.js\` in the header:
\`\`\`
<${''}script src = "third_party/atlasViewer/dist/export/export.js"></${''}script>
\`\`\`
`
const markdownInclude = document.getElementById('markdown-include')
markdownInclude.setAttribute('markdown',markdownIncludeString)
const correctMarkDown = `
\`\`\`
const correctMarkDown = \`
<\$\{''\}script>
console.log('NOT GOTCHA')
<\$\{''\}/script>
\`
const markdownCorrect = document.getElementById('markdown-id')
markdownCorrect.setAttribute('markdown',correctmarkDown)
\`\`\`
`
const markdownCorrect = document.getElementById('markdown-correct')
markdownCorrect.setAttribute('markdown',correctMarkDown)
})
</script>
</head>
<body>
<div class = "jumbotron">
<div class = "container">
<div class = "row">
<h1>interactive viewer components</h1>
</div>
<div class = "row">
<markdown-element id = "markdown-include">
</markdown-element>
</div>
</div>
</div>
<div id = "container" class = "container-fluid">
<div class = "row">
<div class = "col-md-3">
<sample-box sample-box-title = "readmore component">
<readmore-element>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</readmore-element>
</sample-box>
</div>
<div class = "col-md-3">
<sample-box sample-box-title = "markdown component">
<markdown-element>
# Heading1
## Heading2
### Heading3
this is a paragraph
- a dot point
- a second dot point
</markdown-element>
</sample-box>
<h3>
n.b.
</h3>
<p>
<markdown-element>
- first attempts to parse `element.getAttribute('markdown')` then `element.innerHTML`, if non-empty.
- major gotcha: if markdown is rendered as a part of innerHTML, the dom will be rendered briefly. As a result, triple ticked script tags **will** will be evaluated. For example, the following script, if enclosed between `markdown-element` tags, will still be evaluated:
```
<script>
console.log('GOTCHA')
</script>
```
- To include script tags, pass it as an attribute instead:
</markdown-element>
<markdown-element id = "markdown-correct">
</markdown-element>
<markdown-element>
- The `${''}` is required to breakup the `&lt;/script&gt;` tag, or the script tag will be terminated prematurely.
</markdown-element>
</p>
</div>
<div class = "col-md-3">
<sample-box sample-box-title = "panel component">
<panel-element body-collapsable = "true" show-footer = "true">
<div style = "padding: 0.5em;" heading>
panel heading
</div>
<div style = "padding: 0.5em;" body>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div style = "opacity:0.7;padding: 0.5em;" footer>
panel footer
</div>
</panel-element>
</sample-box>
</div>
<div class = "col-md-3">
<sample-box sample-box-title = "tree component" id = "tree-element-sample-box">
<tree-element id = 'tree-element'>
</tree-element>
</sample-box>
</div>
</div>
</div>
</body>
<footer>
</footer>
</html>
\ No newline at end of file
import { NgModule, Injector } from "@angular/core";
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { createCustomElement } from '@angular/elements'
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { BsDropdownModule } from "ngx-bootstrap/dropdown";
import { ReadmoreComponent } from "../components/readmoore/readmore.component";
import { MarkdownDom } from '../components/markdown/markdown.component'
import { SafeHtmlPipe } from "../util/pipes/safeHtml.pipe";
import { SampleBoxUnit } from "./sampleBox/sampleBox.component";
import { PanelComponent } from "../components/panel/panel.component";
import { HoverableBlockDirective } from "../components/hoverableBlock.directive";
import { TreeComponent } from "../components/tree/tree.component";
import { TreeSearchPipe } from "../util/pipes/treeSearch.pipe";
@NgModule({
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
BsDropdownModule.forRoot()
],
declarations : [
SampleBoxUnit,
ReadmoreComponent,
MarkdownDom,
PanelComponent,
TreeComponent,
SafeHtmlPipe,
HoverableBlockDirective,
TreeSearchPipe
],
entryComponents : [
SampleBoxUnit,
ReadmoreComponent,
MarkdownDom,
TreeComponent,
PanelComponent
]
})
export class ExportModule{
constructor(public injector:Injector){
const SampleBox = createCustomElement(SampleBoxUnit,{injector:this.injector})
customElements.define('sample-box',SampleBox)
const ReadMore = createCustomElement(ReadmoreComponent,{ injector : this.injector })
customElements.define('readmore-element',ReadMore)
const MarkDown = createCustomElement(MarkdownDom,{injector : this.injector })
customElements.define('markdown-element',MarkDown)
const Panel = createCustomElement(PanelComponent,{injector : this.injector })
customElements.define('panel-element',Panel)
const Tree = createCustomElement(TreeComponent,{injector : this.injector })
customElements.define('tree-element',Tree)
}
ngDoBootstrap(){
}
}
\ No newline at end of file
import 'zone.js'
import 'reflect-metadata'
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { ExportModule } from "./export.module";
platformBrowserDynamic().bootstrapModule(ExportModule)
\ No newline at end of file
import {
Component,
Input,
ViewChild,
ElementRef,
OnInit,
OnChanges,
Renderer2
} from '@angular/core'
@Component({
selector : 'sample-box',
templateUrl : './sampleBox.template.html',
styleUrls : [
'./sampleBox.style.css'
]
})
export class SampleBoxUnit implements OnInit, OnChanges{
@Input() sampleBoxTitle = ``
@Input() scriptInput
@ViewChild('ngContent',{read:ElementRef}) ngContent : ElementRef
escapedHtml : string = ``
escapedScript : string = ``
private scriptEl : HTMLScriptElement
constructor(private rd2:Renderer2){
this.scriptEl = this.rd2.createElement('script')
}
ngOnInit(){
this.escapedHtml = this.ngContent.nativeElement.innerHTML
}
ngOnChanges(){
this.escapedScript = this.scriptInput
if( this.scriptInput ){
this.scriptEl.innerText = this.scriptInput
}
}
}
\ No newline at end of file
<h2>
{{ sampleBoxTitle }}
</h2>
<hr />
<h3>
Result:
</h3>
<div class = "well" #ngContent>
<ng-content>
</ng-content>
</div>
<h3>
HTML:
</h3>
<pre>{{ escapedHtml }}</pre>
<h3 *ngIf = "scriptInput">
Script:
</h3>
<pre *ngIf = "scriptInput">{{ escapedScript }}</pre>
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
...@@ -22,6 +23,7 @@ import { TreeSearchPipe } from '../util/pipes/treeSearch.pipe'; ...@@ -22,6 +23,7 @@ import { TreeSearchPipe } from '../util/pipes/treeSearch.pipe';
imports : [ imports : [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
BrowserAnimationsModule,
BsDropdownModule.forRoot(), BsDropdownModule.forRoot(),
], ],
declarations : [ declarations : [
...@@ -44,6 +46,8 @@ import { TreeSearchPipe } from '../util/pipes/treeSearch.pipe'; ...@@ -44,6 +46,8 @@ import { TreeSearchPipe } from '../util/pipes/treeSearch.pipe';
TreeSearchPipe TreeSearchPipe
], ],
exports : [ exports : [
BrowserAnimationsModule,
MarkdownDom, MarkdownDom,
ReadmoreComponent, ReadmoreComponent,
DropdownComponent, DropdownComponent,
......
import { Component, OnChanges, Input, ChangeDetectionStrategy } from '@angular/core' import { Component, OnChanges, Input, ChangeDetectionStrategy, ViewChild, ElementRef, OnInit } from '@angular/core'
import * as showdown from 'showdown' import * as showdown from 'showdown'
@Component({ @Component({
...@@ -10,15 +10,26 @@ import * as showdown from 'showdown' ...@@ -10,15 +10,26 @@ import * as showdown from 'showdown'
changeDetection : ChangeDetectionStrategy.OnPush changeDetection : ChangeDetectionStrategy.OnPush
}) })
export class MarkdownDom implements OnChanges{ export class MarkdownDom implements OnChanges,OnInit{
@Input() markdown : string = `` @Input() markdown : string = ``
public innerHtml : string = `` public innerHtml : string = ``
private converter = new showdown.Converter() private converter = new showdown.Converter()
constructor(){ constructor(){
this.converter.setFlavor('github') this.converter.setFlavor('github')
} }
ngOnChanges(){ ngOnChanges(){
this.innerHtml = this.converter.makeHtml(this.markdown) this.innerHtml = this.converter.makeHtml(this.markdown)
} }
ngOnInit(){
if(this.contentWrapper.nativeElement.innerHTML.replace(/\w|\n/g,'') !== '')
this.innerHtml = this.converter.makeHtml(this.contentWrapper.nativeElement.innerHTML)
}
@ViewChild('ngContentWrapper', {read : ElementRef})
contentWrapper : ElementRef
} }
<div [innerHTML] = "innerHtml | safeHtml"> <div [innerHTML] = "innerHtml | safeHtml">
</div>
<div class = "hidden" #ngContentWrapper>
<ng-content>
</ng-content>
</div> </div>
\ No newline at end of file
import { trigger, state, style, transition, animate } from "@angular/animations";
export const panelAnimations = trigger('collapseState',[
state('collapsed',
style({
'margin-top' : '-{{ fullHeight }}px'
}),
{ params : { fullHeight : 9999 } }
),
state('visible',
style({
'margin-top' : '0px'
}),
{ params : { fullHeight : 0 } }
),
transition('collapsed => visible',[
animate('250ms ease-out')
]),
transition('visible => collapsed',[
animate('250ms ease-in')
])
])
\ No newline at end of file
import { Component, Input, ChangeDetectionStrategy } from "@angular/core"; import { Component, Input, ViewChild, ElementRef, AfterContentChecked } from "@angular/core";
import { panelAnimations } from "./panel.animation";
@Component({ @Component({
selector : 'panel', selector : 'panel',
templateUrl : './panel.template.html', templateUrl : './panel.template.html',
styleUrls : [ styleUrls : [
`./panel.style.css` `./panel.style.css`
],
animations : [
panelAnimations
] ]
}) })
export class PanelComponent{ export class PanelComponent implements AfterContentChecked{
@Input() showHeading : boolean = true @Input() showHeading : boolean = true
@Input() showBody : boolean = true @Input() showBody : boolean = true
...@@ -19,9 +23,30 @@ export class PanelComponent{ ...@@ -19,9 +23,30 @@ export class PanelComponent{
@Input() containerClass : string = '' @Input() containerClass : string = ''
@ViewChild('panelBody',{ read : ElementRef }) efPanelBody : ElementRef
@ViewChild('panelFooter',{ read : ElementRef }) efPanelFooter : ElementRef
_fullHeight : number = 0
ngAfterContentChecked(){
this.fullHeight = (this.efPanelBody ? this.efPanelBody.nativeElement.offsetHeight : 0) +
(this.efPanelFooter ? this.efPanelFooter.nativeElement.offsetHeight : 0)
}
set fullHeight(num:number){
this._fullHeight = num
}
get fullHeight(){
return this._fullHeight
}
toggleCollapseBody(event:Event){ toggleCollapseBody(event:Event){
if(this.bodyCollapsable){ if(this.bodyCollapsable){
this.collapseBody = !this.collapseBody this.collapseBody = !this.collapseBody
this.fullHeight = (this.efPanelBody ? this.efPanelBody.nativeElement.offsetHeight : 0) +
(this.efPanelFooter ? this.efPanelFooter.nativeElement.offsetHeight : 0)
} }
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
......
...@@ -12,6 +12,11 @@ ...@@ -12,6 +12,11 @@
margin:0; margin:0;
} }
[bodyFooterContainer]
{
overflow:hidden;
}
.panel > .panel-heading .panel > .panel-heading
{ {
border-radius : 0; border-radius : 0;
...@@ -20,17 +25,14 @@ ...@@ -20,17 +25,14 @@
border:none; border:none;
} }
.panel > .panel-body, .panel > [bodyFooterContainer] > .panel-body,
.panel > .panel-footer .panel > [bodyFooterContainer] > .panel-footer
{ {
margin-top:0px;
padding: 0px;
border:none; border:none;
} }
.panel > .panel-body
{
padding: 0;
}
div.panel div.panel
{ {
background:none; background:none;
......
...@@ -10,22 +10,26 @@ ...@@ -10,22 +10,26 @@
</ng-content> </ng-content>
</div> </div>
<div <div bodyFooterContainer>
*ngIf = "showBody" <div
class = "panel-body" *ngIf = "showBody"
[hidden] = "collapseBody"> class = "panel-body"
[@collapseState] = "{ value : collapseBody ? 'collapsed' : 'visible', params : { fullHeight : fullHeight } }"
#panelBody>
<ng-content select="[body]"> <ng-content select="[body]">
</ng-content> </ng-content>
</div> </div>
<div <div
*ngIf = "showFooter" *ngIf = "showFooter"
[hidden] = "collapseBody" class = "panel-footer"
class = "panel-footer"> [@collapseState] = "{ value : collapseBody ? 'collapsed' : 'visible', params : { fullHeight : fullHeight } }"
#panelFooter>
<ng-content select="[footer]">
</ng-content> <ng-content select="[footer]">
</ng-content>
</div>
</div> </div>
</div> </div>
\ No newline at end of file
import {
trigger,
state,
style,
transition,
animate,
AnimationTriggerMetadata
} from '@angular/animations'
export const readmoreAnimations : AnimationTriggerMetadata = trigger('collapseState',[
state('collapsed',
style({ 'height' : '{{ collapsedHeight }}px' }),
{ params : { collapsedHeight : 45, fullHeight : 200 } }
),
state('visible',
style({ 'height' : '{{ fullHeight }}px' }),
{ params : { collapsedHeight : 45, fullHeight : 200 } }
),
transition('collapsed => visible',[
animate('180ms')
]),
transition('visible => collapsed',[
animate('180ms')
])
])
\ No newline at end of file
import { Component, Input, OnChanges, ViewChild, ElementRef } from "@angular/core"; import { Component, Input, OnChanges, ViewChild, ElementRef, AfterContentChecked } from "@angular/core";
import { readmoreAnimations } from "./readmore.animations";
@Component({ @Component({
selector : 'readmore', selector : 'readmore',
templateUrl : './readmore.template.html', templateUrl : './readmore.template.html',
styleUrls : [ styleUrls : [
'./readmore.style.css' './readmore.style.css'
] ],
animations : [ readmoreAnimations ]
}) })
export class ReadmoreComponent implements OnChanges{ export class ReadmoreComponent implements OnChanges, AfterContentChecked{
@Input() collapsedHeight : number = 45 @Input() collapsedHeight : number = 45
@Input() show : boolean = false @Input() show : boolean = false
@ViewChild('content') contentContainer : ElementRef @ViewChild('contentContainer') contentContainer : ElementRef
public fullHeight : number = 200
ngAfterContentChecked(){
this.fullHeight = this.contentContainer.nativeElement.offsetHeight
}
ngOnChanges(){ ngOnChanges(){
this.fullHeight = this.contentContainer.nativeElement.offsetHeight
} }
public toggle(event:MouseEvent){ public toggle(event:MouseEvent){
this.show = !this.show this.show = !this.show
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
} }
get contentContainerMaxHeight(){
return this.show ?
`9999px` :
`${this.collapsedHeight}px`
}
} }
\ No newline at end of file
<div <div
[style.maxHeight]="contentContainerMaxHeight" [@collapseState] = "{ value : show ? 'visible' : 'collapsed', params : { collapsedHeight : collapsedHeight, fullHeight : fullHeight } }"
#content
content> content>
<ng-content> <div #contentContainer>
</ng-content> <ng-content>
</ng-content>
</div>
</div> </div>
<div <div
(click)="toggle($event)" (click)="toggle($event)"
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment