mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
parent
eff9ce13f7
commit
e97c8b703c
@ -817,6 +817,14 @@ on how to register your own entries to be re-used at runtime.
|
|||||||
| disabled | Toggles disabled state. Can be assigned from other plugins. |
|
| disabled | Toggles disabled state. Can be assigned from other plugins. |
|
||||||
| order | The order of the element. |
|
| order | The order of the element. |
|
||||||
|
|
||||||
|
#### Tab components
|
||||||
|
|
||||||
|
Every component you assign for the tab content receives the following additional properties at runtime:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| node | MinimalNodeEntryEntity | Node entry to be displayed. |
|
||||||
|
|
||||||
### Toolbar
|
### Toolbar
|
||||||
|
|
||||||
The toolbar extension point is represented by an array of Content Action references.
|
The toolbar extension point is represented by an array of Content Action references.
|
||||||
@ -920,6 +928,7 @@ declared in the `rules` section:
|
|||||||
|
|
||||||
Viewer component in ACA supports the following extension points:
|
Viewer component in ACA supports the following extension points:
|
||||||
|
|
||||||
|
* Content Viewers
|
||||||
* `More` toolbar actions
|
* `More` toolbar actions
|
||||||
* `Open With` actions
|
* `Open With` actions
|
||||||
|
|
||||||
@ -931,6 +940,7 @@ Viewer component in ACA supports the following extension points:
|
|||||||
|
|
||||||
"features": {
|
"features": {
|
||||||
"viewer": {
|
"viewer": {
|
||||||
|
"content": [],
|
||||||
"toolbar:": [],
|
"toolbar:": [],
|
||||||
"openWith": []
|
"openWith": []
|
||||||
}
|
}
|
||||||
@ -938,6 +948,46 @@ Viewer component in ACA supports the following extension points:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Content View
|
||||||
|
|
||||||
|
You can provide custom components that render particular type of the content based on extensions.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"$schema": "../../../extension.schema.json",
|
||||||
|
"$version": "1.0.0",
|
||||||
|
"$name": "plugin1",
|
||||||
|
|
||||||
|
"features": {
|
||||||
|
"viewer": {
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"id": "app.viewer.pdf",
|
||||||
|
"fileExtension": "pdf",
|
||||||
|
"component": "app.components.tabs.metadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.viewer.docx",
|
||||||
|
"fileExtension": "docx",
|
||||||
|
"component": "app.components.tabs.comments"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the example above we replace `PDF` view with the `metadata` tab
|
||||||
|
and `DOCX` view with the `comments` tab.
|
||||||
|
|
||||||
|
Every custom component receives the following properties at runtime:
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| node | MinimalNodeEntryEntity | Node entry to be displayed. |
|
||||||
|
| url | string | File content URL. |
|
||||||
|
| extension | string | File name extension. |
|
||||||
|
|
||||||
#### Toolbar actions
|
#### Toolbar actions
|
||||||
|
|
||||||
The ADF Viewer component allows providing custom entries for the `More` menu button on the toolbar.
|
The ADF Viewer component allows providing custom entries for the `More` menu button on the toolbar.
|
||||||
|
@ -268,6 +268,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"viewerExtensionRef": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "component", "fileExtension"],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "Unique identifier for the navigation group",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"description": "Component id",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fileExtension": {
|
||||||
|
"description": "Target file extension",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"description": "Group order",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"description": "Toggles the disabled state",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -337,6 +363,12 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "$ref": "#/definitions/contentActionRef" },
|
"items": { "$ref": "#/definitions/contentActionRef" },
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"description": "Viewer content extensions",
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "#/definitions/viewerExtensionRef" },
|
||||||
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
105
src/app/components/preview/preview-extension.component.ts
Normal file
105
src/app/components/preview/preview-extension.component.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco Example Content Application.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
Input,
|
||||||
|
ComponentRef,
|
||||||
|
OnInit,
|
||||||
|
ComponentFactoryResolver,
|
||||||
|
ViewChild,
|
||||||
|
ViewContainerRef,
|
||||||
|
OnDestroy,
|
||||||
|
OnChanges
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ExtensionService } from '../../extensions/extension.service';
|
||||||
|
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-preview-extension',
|
||||||
|
template: `<div #content></div>`
|
||||||
|
})
|
||||||
|
export class PreviewExtensionComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
@ViewChild('content', { read: ViewContainerRef })
|
||||||
|
content: ViewContainerRef;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
url: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
extension: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
node: MinimalNodeEntryEntity;
|
||||||
|
|
||||||
|
private componentRef: ComponentRef<any>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private extensions: ExtensionService,
|
||||||
|
private componentFactoryResolver: ComponentFactoryResolver
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (!this.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const componentType = this.extensions.getComponentById(this.id);
|
||||||
|
if (componentType) {
|
||||||
|
const factory = this.componentFactoryResolver.resolveComponentFactory(
|
||||||
|
componentType
|
||||||
|
);
|
||||||
|
if (factory) {
|
||||||
|
this.content.clear();
|
||||||
|
this.componentRef = this.content.createComponent(factory, 0);
|
||||||
|
this.updateInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges() {
|
||||||
|
this.updateInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.componentRef) {
|
||||||
|
this.componentRef.destroy();
|
||||||
|
this.componentRef = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateInstance() {
|
||||||
|
if (this.componentRef && this.componentRef.instance) {
|
||||||
|
const instance = this.componentRef.instance;
|
||||||
|
|
||||||
|
instance.node = this.node;
|
||||||
|
instance.url = this.url;
|
||||||
|
instance.extension = this.extension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,5 +28,19 @@
|
|||||||
<aca-toolbar-action type="menu-item" [entry]="action"></aca-toolbar-action>
|
<aca-toolbar-action type="menu-item" [entry]="action"></aca-toolbar-action>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</adf-viewer-more-actions>
|
</adf-viewer-more-actions>
|
||||||
|
|
||||||
|
<ng-container *ngFor="let ext of contentExtensions">
|
||||||
|
<adf-viewer-extension [supportedExtensions]="[ext.fileExtension]">
|
||||||
|
<ng-template let-url="urlFileContent" let-extension="extension">
|
||||||
|
<app-preview-extension
|
||||||
|
[id]="ext.component"
|
||||||
|
[node]="selection.file?.entry"
|
||||||
|
[url]="url"
|
||||||
|
[extension]="extension">
|
||||||
|
</app-preview-extension>
|
||||||
|
</ng-template>
|
||||||
|
</adf-viewer-extension>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
</adf-viewer>
|
</adf-viewer>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -35,6 +35,7 @@ import { ExtensionService } from '../../extensions/extension.service';
|
|||||||
import { ContentManagementService } from '../../services/content-management.service';
|
import { ContentManagementService } from '../../services/content-management.service';
|
||||||
import { ContentActionRef } from '../../extensions/action.extensions';
|
import { ContentActionRef } from '../../extensions/action.extensions';
|
||||||
import { ViewUtilService } from './view-util.service';
|
import { ViewUtilService } from './view-util.service';
|
||||||
|
import { ViewerExtensionRef } from '../../extensions/viewer.extensions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-preview',
|
selector: 'app-preview',
|
||||||
@ -55,6 +56,7 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
nextNodeId: string;
|
nextNodeId: string;
|
||||||
navigateMultiple = false;
|
navigateMultiple = false;
|
||||||
openWith: Array<ContentActionRef> = [];
|
openWith: Array<ContentActionRef> = [];
|
||||||
|
contentExtensions: Array<ViewerExtensionRef> = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private contentApi: ContentApiService,
|
private contentApi: ContentApiService,
|
||||||
@ -97,6 +99,7 @@ export class PreviewComponent extends PageComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.openWith = this.extensions.openWithActions;
|
this.openWith = this.extensions.openWithActions;
|
||||||
|
this.contentExtensions = this.extensions.viewerContentExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +35,7 @@ import { PreviewComponent } from './preview.component';
|
|||||||
import { ViewUtilService } from './view-util.service';
|
import { ViewUtilService } from './view-util.service';
|
||||||
|
|
||||||
import * as pdfjsLib from 'pdfjs-dist';
|
import * as pdfjsLib from 'pdfjs-dist';
|
||||||
|
import { PreviewExtensionComponent } from './preview-extension.component';
|
||||||
pdfjsLib.PDFJS.workerSrc = 'pdf.worker.js';
|
pdfjsLib.PDFJS.workerSrc = 'pdf.worker.js';
|
||||||
pdfjsLib.PDFJS.disableFontFace = true;
|
pdfjsLib.PDFJS.disableFontFace = true;
|
||||||
|
|
||||||
@ -57,6 +58,7 @@ const routes: Routes = [
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
PreviewComponent,
|
PreviewComponent,
|
||||||
|
PreviewExtensionComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ViewUtilService
|
ViewUtilService
|
||||||
|
@ -28,6 +28,7 @@ import { RouteRef } from './routing.extensions';
|
|||||||
import { RuleRef } from './rule.extensions';
|
import { RuleRef } from './rule.extensions';
|
||||||
import { ActionRef, ContentActionRef } from './action.extensions';
|
import { ActionRef, ContentActionRef } from './action.extensions';
|
||||||
import { SidebarTabRef } from './sidebar.extensions';
|
import { SidebarTabRef } from './sidebar.extensions';
|
||||||
|
import { ViewerExtensionRef } from './viewer.extensions';
|
||||||
|
|
||||||
export interface ExtensionConfig {
|
export interface ExtensionConfig {
|
||||||
$name: string;
|
$name: string;
|
||||||
@ -43,6 +44,7 @@ export interface ExtensionConfig {
|
|||||||
viewer?: {
|
viewer?: {
|
||||||
openWith?: Array<ContentActionRef>;
|
openWith?: Array<ContentActionRef>;
|
||||||
toolbar?: Array<ContentActionRef>;
|
toolbar?: Array<ContentActionRef>;
|
||||||
|
content?: Array<ViewerExtensionRef>;
|
||||||
};
|
};
|
||||||
navbar?: Array<NavBarGroupRef>;
|
navbar?: Array<NavBarGroupRef>;
|
||||||
sidebar?: Array<SidebarTabRef>;
|
sidebar?: Array<SidebarTabRef>;
|
||||||
|
@ -39,6 +39,7 @@ import * as core from './evaluators/core.evaluators';
|
|||||||
import { NodePermissionService } from '../services/node-permission.service';
|
import { NodePermissionService } from '../services/node-permission.service';
|
||||||
import { SidebarTabRef } from './sidebar.extensions';
|
import { SidebarTabRef } from './sidebar.extensions';
|
||||||
import { ProfileResolver } from '../services/profile.resolver';
|
import { ProfileResolver } from '../services/profile.resolver';
|
||||||
|
import { ViewerExtensionRef } from './viewer.extensions';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExtensionService implements RuleContext {
|
export class ExtensionService implements RuleContext {
|
||||||
@ -56,6 +57,7 @@ export class ExtensionService implements RuleContext {
|
|||||||
|
|
||||||
toolbarActions: Array<ContentActionRef> = [];
|
toolbarActions: Array<ContentActionRef> = [];
|
||||||
viewerToolbarActions: Array<ContentActionRef> = [];
|
viewerToolbarActions: Array<ContentActionRef> = [];
|
||||||
|
viewerContentExtensions: Array<ViewerExtensionRef> = [];
|
||||||
contextMenuActions: Array<ContentActionRef> = [];
|
contextMenuActions: Array<ContentActionRef> = [];
|
||||||
openWithActions: Array<ContentActionRef> = [];
|
openWithActions: Array<ContentActionRef> = [];
|
||||||
createActions: Array<ContentActionRef> = [];
|
createActions: Array<ContentActionRef> = [];
|
||||||
@ -136,6 +138,7 @@ export class ExtensionService implements RuleContext {
|
|||||||
this.routes = this.loadRoutes(config);
|
this.routes = this.loadRoutes(config);
|
||||||
this.toolbarActions = this.loadToolbarActions(config);
|
this.toolbarActions = this.loadToolbarActions(config);
|
||||||
this.viewerToolbarActions = this.loadViewerToolbarActions(config);
|
this.viewerToolbarActions = this.loadViewerToolbarActions(config);
|
||||||
|
this.viewerContentExtensions = this.loadViewerContentExtensions(config);
|
||||||
this.contextMenuActions = this.loadContextMenuActions(config);
|
this.contextMenuActions = this.loadContextMenuActions(config);
|
||||||
this.openWithActions = this.loadViewerOpenWith(config);
|
this.openWithActions = this.loadViewerOpenWith(config);
|
||||||
this.createActions = this.loadCreateActions(config);
|
this.createActions = this.loadCreateActions(config);
|
||||||
@ -187,6 +190,15 @@ export class ExtensionService implements RuleContext {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected loadViewerContentExtensions(config: ExtensionConfig): Array<ViewerExtensionRef> {
|
||||||
|
if (config && config.features && config.features.viewer) {
|
||||||
|
return (config.features.viewer.content || [])
|
||||||
|
.filter(entry => !entry.disabled)
|
||||||
|
.sort(this.sortByOrder);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
protected loadContextMenuActions(config: ExtensionConfig): Array<ContentActionRef> {
|
protected loadContextMenuActions(config: ExtensionConfig): Array<ContentActionRef> {
|
||||||
if (config && config.features && config.features.contextMenu) {
|
if (config && config.features && config.features.contextMenu) {
|
||||||
return (config.features.contextMenu || [])
|
return (config.features.contextMenu || [])
|
||||||
|
33
src/app/extensions/viewer.extensions.ts
Normal file
33
src/app/extensions/viewer.extensions.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco Example Content Application.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface ViewerExtensionRef {
|
||||||
|
id: string;
|
||||||
|
fileExtension: string;
|
||||||
|
component: string;
|
||||||
|
|
||||||
|
disabled?: boolean;
|
||||||
|
order?: number;
|
||||||
|
}
|
@ -725,6 +725,20 @@
|
|||||||
"visible": "app.toolbar.permissions"
|
"visible": "app.toolbar.permissions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"id": "app.viewer.pdf",
|
||||||
|
"disabled": true,
|
||||||
|
"fileExtension": "pdf",
|
||||||
|
"component": "app.components.tabs.metadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.viewer.docx",
|
||||||
|
"disabled": true,
|
||||||
|
"fileExtension": "docx",
|
||||||
|
"component": "app.components.tabs.comments"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"sidebar": [
|
"sidebar": [
|
||||||
|
@ -268,6 +268,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"viewerExtensionRef": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["id", "component", "fileExtension"],
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "Unique identifier for the navigation group",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"description": "Component id",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"fileExtension": {
|
||||||
|
"description": "Target file extension",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"description": "Group order",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"description": "Toggles the disabled state",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -337,6 +363,12 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "$ref": "#/definitions/contentActionRef" },
|
"items": { "$ref": "#/definitions/contentActionRef" },
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"description": "Viewer content extensions",
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "#/definitions/viewerExtensionRef" },
|
||||||
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user