Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
How We Brought Advanced HTML5 Viewing to ADF
1. How We Brought Advanced
HTML5 Viewing To ADF
Sean Graham
Snowbound Software
2. Learn. Connect. Collaborate.
What is Snowbound?
• Over 20 years of document and imaging expertise
• Two main products:
– RasterMaster – Java and .NET document rendering and processing SDK
– VirtualViewer – Java and .NET viewer
3. Learn. Connect. Collaborate.
What is Snowbound?
• Over 20 years of document and imaging expertise
• Two main products:
– RasterMaster – Java and .NET document rendering and processing SDK
– VirtualViewer – Java and .NET viewer
4. Learn. Connect. Collaborate.
What is VirtualViewer
• VirtualViewer is a pure-browser document and image platform
– No plugins required
– Scores of formats
– Annotation, manipulation, redaction, etc.
• VirtualViewer has been integrated with Alfresco for years
• What would it take to integrate with ADF and Content App?
5. Learn. Connect. Collaborate.
What is VirtualViewer
• VirtualViewer is a pure-browser document and image platform
– No plugins required
– Scores of formats
– Annotation, manipulation, redaction, etc.
• VirtualViewer has been integrated with Alfresco for years
• What would it take to integrate with ADF and Content App?
1
6. Learn. Connect. Collaborate.
Goals
• Leverage as much existing work as sensible
• Ease deployment for ADF users
• Learn and embrace new technologies
7. Learn. Connect. Collaborate.
Goals
• Leverage as much existing work as sensible
• Ease deployment for ADF users
• Learn and embrace new technologies
8. Learn. Connect. Collaborate.
Goals
• Leverage as much existing work as sensible
• Ease deployment for ADF users
• Learn and embrace new technologies
9. Learn. Connect. Collaborate.
[…]
@Component({
selector: 'snbd-virtualviewer-alf',
templateUrl: './virtualviewer-alfresco.component.html'
})
export class VirtualViewerAlfrescoComponent implements OnInit {
@Input() node: MinimalNodeEntryEntity;
@Input() nodeId: string;
@Input() sharedLinkId: string;
documentId:string;
clientInstanceId: string;
constructor(private authService: AuthenticationService) {}
ngOnInit() {
if(this.node && this.node.id) {
this.documentId = this.node.id;
}
else {
this.documentId = this.sharedLinkId || this.nodeId;
}
this.clientInstanceId = this.generateClientInstanceId();
}
generateClientInstanceId():string {
var clientInstanceId = {
ticket: this.authService.getTicketEcm(),
username: this.authService.getEcmUsername()
};
return JSON.stringify(clientInstanceId);
}
}
Create ADF component
• Viewer component needs to
receive and process a
MinimalNodeEntryEntity.
From this we extract the node ID
for the document to be viewed.
• We extract the auth ticket and
EcmUserName from the
AuthenticationService
• This info is then passed to the VV
module so that the server can
retrieve the document from
Alfresco
2
10. Learn. Connect. Collaborate.
[…]
@Component({
selector: 'snbd-virtualviewer-alf',
templateUrl: './virtualviewer-alfresco.component.html'
})
export class VirtualViewerAlfrescoComponent implements OnInit {
@Input() node: MinimalNodeEntryEntity;
@Input() nodeId: string;
@Input() sharedLinkId: string;
documentId:string;
clientInstanceId: string;
constructor(private authService: AuthenticationService) {}
ngOnInit() {
if(this.node && this.node.id) {
this.documentId = this.node.id;
}
else {
this.documentId = this.sharedLinkId || this.nodeId;
}
this.clientInstanceId = this.generateClientInstanceId();
}
generateClientInstanceId():string {
var clientInstanceId = {
ticket: this.authService.getTicketEcm(),
username: this.authService.getEcmUsername()
};
return JSON.stringify(clientInstanceId);
}
}
Create ADF component
• Viewer component needs to
receive and process a
MinimalNodeEntryEntity.
From this we extract the node ID
for the document to be viewed.
• We extract the auth ticket and
EcmUserName from the
AuthenticationService
• This info is then passed to the VV
module so that the server can
retrieve the document from
Alfresco
11. Learn. Connect. Collaborate.
[…]
@Component({
selector: 'snbd-virtualviewer-alf',
templateUrl: './virtualviewer-alfresco.component.html'
})
export class VirtualViewerAlfrescoComponent implements OnInit {
@Input() node: MinimalNodeEntryEntity;
@Input() nodeId: string;
@Input() sharedLinkId: string;
documentId:string;
clientInstanceId: string;
constructor(private authService: AuthenticationService) {}
ngOnInit() {
if(this.node && this.node.id) {
this.documentId = this.node.id;
}
else {
this.documentId = this.sharedLinkId || this.nodeId;
}
this.clientInstanceId = this.generateClientInstanceId();
}
generateClientInstanceId():string {
var clientInstanceId = {
ticket: this.authService.getTicketEcm(),
username: this.authService.getEcmUsername()
};
return JSON.stringify(clientInstanceId);
}
}
Create ADF component
• Viewer component needs to
receive and process a
MinimalNodeEntryEntity.
From this we extract the node ID
for the document to be viewed.
• We extract the auth ticket and
EcmUserName from the
AuthenticationService
• This info is then passed to the VV
module so that the server can
retrieve the document from
Alfresco
12. Learn. Connect. Collaborate.
Register with Extension Service
• Let the system know there is a
new member of the namespace
• Set a custom ID for later
reference
import { ExtensionsModule, ExtensionService } from
'@alfresco/adf-extensions';
@NgModule({
imports: [ ExtensionsModule.forChild() ]
declarations: [ VirtualViewerAlfrescoComponent, MyLayout
],
entryComponents: [ VirtualViewerAlfrescoComponent,
MyLayout ]
})
export class MyExtensionModule {
constructor(extensions: ExtensionService) {
extensions.setComponents({
'snowbound.virtualviewer':
VirtualViewerAlfrescoComponent,
});
}
}
13. Learn. Connect. Collaborate.
Register with Extension Service
• Let the system know there is a
new member of the namespace
• Set a custom ID for later
reference
import { ExtensionsModule, ExtensionService } from
'@alfresco/adf-extensions';
@NgModule({
imports: [ ExtensionsModule.forChild() ]
declarations: [ VirtualViewerAlfrescoComponent, MyLayout
],
entryComponents: [ VirtualViewerAlfrescoComponent,
MyLayout ]
})
export class MyExtensionModule {
constructor(extensions: ExtensionService) {
extensions.setComponents({
'snowbound.virtualviewer':
VirtualViewerAlfrescoComponent,
});
}
}
3
14. Learn. Connect. Collaborate.
Viewer Extension Configuration
• While you could certainly include
your configuration values in the
app.extensions.json file,
don’t.
• Refer to an extension-specific
json configuration instead.
{
"$schema": "../../extension.schema.json",
"$id": "app.core",
"$name": "app.core",
"$version": "1.0.0",
"$vendor": "Alfresco Software, Ltd.",
"$license": "LGPL-3.0",
"$runtime": "1.5.0",
"$description": "Core application extensions and features",
"$references": ["virtualviewer.json"],
15. Learn. Connect. Collaborate.
Viewer Extension Configuration (Continued)
• You’ll need to associate at least
one filetype with your
component.
• To the right, we associate PDF
files with VV, but our actual
virtualviewer.json includes
scores of formats.
{
"$schema": "../extension.schema.json",
"$version": "0.1.0",
"$name": "virtualviewer",
"$description": "plugin for VirtualViewer in the content
app",
"features": {
"viewer": {
"content": [
{
"id": "snowbound",
"fileExtension": "pdf",
"component": "snowbound.virtualviewer"
}
]
}
}
}
16. Learn. Connect. Collaborate.
Viewer Extension Configuration (Continued)
• You’ll need to associate at least
one filetype with your
component.
• To the right, we associate PDF
files with VV, but our actual
virtualviewer.json includes
scores of formats.
{
"$schema": "../extension.schema.json",
"$version": "0.1.0",
"$name": "virtualviewer",
"$description": "plugin for VirtualViewer in the content
app",
"features": {
"viewer": {
"content": [
{
"id": "snowbound",
"fileExtension": "pdf",
"component": "snowbound.virtualviewer"
}
]
}
}
}
17. Learn. Connect. Collaborate.
The Whitespace Problem
• There seems to be a bug in the
current version of Content App
• A <span> is created for every
format you’ve registered support
for
• Those <span> are not zero-
height
4
18. Learn. Connect. Collaborate.
The Whitespace Problem
• There seems to be a bug in the
current version of Content App
• A <span> is created for every
format you’ve registered support
for
• Those <span> are not zero-
height
19. Learn. Connect. Collaborate.
The Whitespace Problem
• There seems to be a bug in the
current version of Content App
• A <span> is created for every
format you’ve registered support
for
• Those <span> are not zero-
height
20. Learn. Connect. Collaborate.
Questions
• Nathan and I will be at the Snowbound table during the 10:45a block on Thursday
• Alternatively, visit the table and coordinate a different time with JB
21. Learn. Connect. Collaborate.
Questions
• Nathan and I will be at the Snowbound table during the 10:45a block on Thursday
• Alternatively, visit the table and coordinate a different time with JB