+
{{ property.displayValue }}
- create
+ create
diff --git a/lib/core/card-view/card-view-textitem.component.scss b/lib/core/card-view/card-view-textitem.component.scss
index 11a585165a..a803682fad 100644
--- a/lib/core/card-view/card-view-textitem.component.scss
+++ b/lib/core/card-view/card-view-textitem.component.scss
@@ -1,4 +1,5 @@
@mixin adf-card-view-textitem-theme($theme) {
+ $foreground: map-get($theme, foreground);
.adf {
&-textitem-icon {
@@ -6,9 +7,9 @@
width: 16px;
height: 16px;
position: relative;
- top: 3px;
+ top: 4px;
padding-left: 8px;
- opacity: 0.5;
+ opacity: 0.3;
}
&-update-icon {
@@ -42,7 +43,7 @@
input:focus,
textarea:focus {
- border: 1px solid #EEE;
+ border: 1px solid mat-color($foreground, text, 0.15);
}
}
@@ -72,13 +73,13 @@
&-textitem-editable .mat-input-element {
font-family: inherit;
position: relative;
- padding-top: 3px;
+ padding-top: 6px;
}
&-textitem-editable .mat-input-element:focus {
padding: 5px;
left: -6px;
- top: -6px;
+ top: 0;
}
&-textitem-editable input.mat-input-element {
diff --git a/lib/core/card-view/card-view-textitem.component.spec.ts b/lib/core/card-view/card-view-textitem.component.spec.ts
index d3ac3b37f7..ff73e6fdbc 100644
--- a/lib/core/card-view/card-view-textitem.component.spec.ts
+++ b/lib/core/card-view/card-view-textitem.component.spec.ts
@@ -215,4 +215,19 @@ describe('CardViewTextItemComponent', () => {
let updateInput = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-update-${component.property.key}"]`));
updateInput.triggerEventHandler('click', null);
});
+
+ it('should switch back to readonly mode after an update attempt', async(() => {
+ component.editable = true;
+ component.property.editable = true;
+ component.inEdit = true;
+ component.editedValue = 'updated-value';
+ fixture.detectChanges();
+
+ component.update();
+
+ fixture.whenStable().then(() => {
+ expect(component.property.value).toBe(component.editedValue);
+ expect(component.inEdit).toBeFalsy();
+ });
+ }));
});
diff --git a/lib/core/card-view/card-view-textitem.component.ts b/lib/core/card-view/card-view-textitem.component.ts
index 955e5a8fe6..6e9aea1826 100644
--- a/lib/core/card-view/card-view-textitem.component.ts
+++ b/lib/core/card-view/card-view-textitem.component.ts
@@ -64,7 +64,9 @@ export class CardViewTextItemComponent implements OnChanges {
}
update(): void {
- this.cardViewUpdateService.update(this.property, { [this.property.key]: this.editedValue });
+ this.cardViewUpdateService.update(this.property, this.editedValue );
+ this.property.value = this.editedValue;
+ this.setEditMode(false);
}
clicked(): void {
diff --git a/lib/core/card-view/card-view.module.ts b/lib/core/card-view/card-view.module.ts
index e062e3960d..4941131289 100644
--- a/lib/core/card-view/card-view.module.ts
+++ b/lib/core/card-view/card-view.module.ts
@@ -19,6 +19,7 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule, MatDatepickerModule, MatIconModule, MatInputModule, MatNativeDateModule } from '@angular/material';
+import { FlexLayoutModule } from '@angular/flex-layout';
import { TranslateModule } from '@ngx-translate/core';
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
@@ -37,6 +38,7 @@ import { CardViewComponent } from './card-view.component';
MatIconModule,
MatButtonModule,
FormsModule,
+ FlexLayoutModule,
TranslateModule
],
declarations: [
diff --git a/lib/core/i18n/en.json b/lib/core/i18n/en.json
index d285fe72d7..7cd077d03f 100644
--- a/lib/core/i18n/en.json
+++ b/lib/core/i18n/en.json
@@ -71,6 +71,20 @@
"BACK": "Back",
"APPLY": "APPLY",
"NOT_VALID": "http(s)://host|ip:port(/path) not recognized, try a different URL."
+ },
+ "METADATA": {
+ "BASIC": {
+ "NAME": "Name",
+ "TITLE": "Title",
+ "DESCRIPTION": "Description",
+ "AUTHOR": "Author",
+ "MIMETYPE": "Mimetype",
+ "SIZE": "Size",
+ "CREATOR": "Creator",
+ "CREATED_DATE": "Created Date",
+ "MODIFIER": "Modifier",
+ "MODIFIED_DATE": "Modified Date"
+ }
}
},
"LOGIN": {
@@ -146,6 +160,12 @@
"OF": "of"
},
"LOADING": "Loading",
- "UNKNOWN_FORMAT": "Couldn't load preview"
+ "UNKNOWN_FORMAT": "Couldn't load preview",
+ "SIDEBAR": {
+ "METADATA": {
+ "MORE_INFORMATION": "More information",
+ "LESS_INFORMATION": "Less information"
+ }
+ }
}
}
diff --git a/lib/core/models/card-view-textitem.model.spec.ts b/lib/core/models/card-view-textitem.model.spec.ts
new file mode 100644
index 0000000000..240dc17803
--- /dev/null
+++ b/lib/core/models/card-view-textitem.model.spec.ts
@@ -0,0 +1,78 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { PipeTransform } from '@angular/core';
+import { CardViewTextItemModel, CardViewTextItemProperties } from './card-view-textitem.model';
+
+class TestPipe implements PipeTransform {
+ transform(value: string, pipeParam: string): string {
+ const paramPostFix = pipeParam ? `-${pipeParam}` : '';
+ return `testpiped-${value}${paramPostFix}`;
+ }
+}
+
+describe('CardViewTextItemModel', () => {
+
+ let properties: CardViewTextItemProperties;
+
+ beforeEach(() => {
+ properties = {
+ label: 'Tribe',
+ value: 'Banuk',
+ key: 'tribe'
+ };
+ });
+
+ describe('displayValue', () => {
+
+ it('should return the extension if file has it', () => {
+ const file = new CardViewTextItemModel(properties);
+
+ expect(file.displayValue).toBe('Banuk');
+ });
+
+ it('should apply a pipe on the value if it is present', () => {
+ properties.pipes = [
+ { pipe: new TestPipe() }
+ ];
+ const file = new CardViewTextItemModel(properties);
+
+ expect(file.displayValue).toBe('testpiped-Banuk');
+ });
+
+ it('should apply a pipe on the value with parameters if those are present', () => {
+ properties.pipes = [
+ { pipe: new TestPipe(), params: ['withParams'] }
+ ];
+ const file = new CardViewTextItemModel(properties);
+
+ expect(file.displayValue).toBe('testpiped-Banuk-withParams');
+ });
+
+ it('should apply more pipes on the value with parameters if those are present', () => {
+ const pipe: PipeTransform = new TestPipe();
+ properties.pipes = [
+ { pipe, params: ['1'] },
+ { pipe, params: ['2'] },
+ { pipe, params: ['3'] }
+ ];
+ const file = new CardViewTextItemModel(properties);
+
+ expect(file.displayValue).toBe('testpiped-testpiped-testpiped-Banuk-1-2-3');
+ });
+ });
+});
diff --git a/lib/core/models/card-view-textitem.model.ts b/lib/core/models/card-view-textitem.model.ts
index f9d8f1156b..48eea977dc 100644
--- a/lib/core/models/card-view-textitem.model.ts
+++ b/lib/core/models/card-view-textitem.model.ts
@@ -23,24 +23,41 @@
* @returns {CardViewTextItemModel} .
*/
+import { PipeTransform } from '@angular/core';
import { CardViewItem } from '../interface/card-view-item.interface';
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
+export interface CardViewTextItemPipeProperty {
+ pipe: PipeTransform;
+ params?: Array;
+}
export interface CardViewTextItemProperties extends CardViewItemProperties {
multiline?: boolean;
+ pipes?: Array;
}
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
type: string = 'text';
- multiline: boolean;
+ multiline?: boolean;
+ pipes?: Array;
constructor(obj: CardViewTextItemProperties) {
super(obj);
this.multiline = !!obj.multiline ;
+ this.pipes = obj.pipes || [];
}
get displayValue() {
- return this.value;
+ return this.applyPipes(this.value);
}
+ private applyPipes(displayValue) {
+ if (this.pipes.length) {
+ displayValue = this.pipes.reduce((accumulator, { pipe, params }) => {
+ return pipe.transform(accumulator, ...params);
+ }, displayValue);
+ }
+
+ return displayValue;
+ }
}
diff --git a/lib/core/services/card-view-update.service.spec.ts b/lib/core/services/card-view-update.service.spec.ts
new file mode 100644
index 0000000000..d57bd863bc
--- /dev/null
+++ b/lib/core/services/card-view-update.service.spec.ts
@@ -0,0 +1,94 @@
+/*!
+ * @license
+ * Copyright 2016 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { async, TestBed } from '@angular/core/testing';
+import { CardViewBaseItemModel } from '../models/card-view-baseitem.model';
+import { CardViewUpdateService, transformKeyToObject } from './card-view-update.service';
+
+describe('CardViewUpdateService', () => {
+
+ describe('transformKeyToObject', () => {
+
+ it('should return the proper constructed value object for "dotless" keys', () => {
+ const valueObject = transformKeyToObject('property-key', 'property-value');
+
+ expect(valueObject).toEqual({
+ 'property-key': 'property-value'
+ });
+ });
+
+ it('should return the proper constructed value object for dot contained keys', () => {
+ const valueObject = transformKeyToObject('level:0.level:1.level:2.level:3', 'property-value');
+
+ expect(valueObject).toEqual({
+ 'level:0': {
+ 'level:1': {
+ 'level:2': {
+ 'level:3': 'property-value'
+ }
+ }
+ }
+ });
+ });
+ });
+
+ describe('Service', () => {
+
+ let cardViewUpdateService: CardViewUpdateService;
+ const property: CardViewBaseItemModel = {
+ label: 'property-label',
+ value: 'property-value',
+ key: 'property-key',
+ default: 'property-default',
+ editable: false,
+ clickable: false
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ providers: [
+ CardViewUpdateService
+ ]
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ cardViewUpdateService = TestBed.get(CardViewUpdateService);
+ });
+
+ it('should send updated message with proper parameters', async(() => {
+
+ cardViewUpdateService.itemUpdated$.subscribe(
+ ( { target, changed } ) => {
+ expect(target).toBe(property);
+ expect(changed).toEqual({ 'property-key': 'changed-property-value' });
+ }
+ );
+ cardViewUpdateService.update(property, 'changed-property-value');
+ }));
+
+ it('should send clicked message with proper parameters', async(() => {
+
+ cardViewUpdateService.itemClicked$.subscribe(
+ ( { target } ) => {
+ expect(target).toBe(property);
+ }
+ );
+ cardViewUpdateService.clicked(property);
+ }));
+ });
+});
diff --git a/lib/core/services/card-view-update.service.ts b/lib/core/services/card-view-update.service.ts
index e2e2be4bb2..107a601cfe 100644
--- a/lib/core/services/card-view-update.service.ts
+++ b/lib/core/services/card-view-update.service.ts
@@ -16,7 +16,7 @@
*/
import { Injectable } from '@angular/core';
-import { Subject } from 'rxjs/Subject';
+import { Observable, Subject } from 'rxjs/Rx';
import { CardViewBaseItemModel } from '../models/card-view-baseitem.model';
export interface UpdateNotification {
@@ -28,26 +28,34 @@ export interface ClickNotification {
target: any;
}
+export function transformKeyToObject(key: string, value): Object {
+ const objectLevels: string[] = key.split('.').reverse();
+
+ return objectLevels.reduce<{}>((previousValue, currentValue) => {
+ return { [currentValue]: previousValue};
+ }, value);
+}
+
@Injectable()
export class CardViewUpdateService {
// Observable sources
private itemUpdatedSource = new Subject();
+ private itemClickedSource = new Subject();
// Observable streams
- public itemUpdated$ = this.itemUpdatedSource.asObservable();
+ public itemUpdated$ = > this.itemUpdatedSource.asObservable();
+ public itemClicked$ = > this.itemClickedSource.asObservable();
- public itemClicked$: Subject = new Subject();
-
- update(property: CardViewBaseItemModel, changed: any) {
+ update(property: CardViewBaseItemModel, newValue: any) {
this.itemUpdatedSource.next({
target: property,
- changed
+ changed: transformKeyToObject(property.key, newValue)
});
}
clicked(property: CardViewBaseItemModel) {
- this.itemClicked$.next({
+ this.itemClickedSource.next({
target: property
});
}
diff --git a/lib/core/styles/_index.scss b/lib/core/styles/_index.scss
index 1f6b98dd8f..745a318548 100644
--- a/lib/core/styles/_index.scss
+++ b/lib/core/styles/_index.scss
@@ -14,6 +14,7 @@
@import '../login/components/login.component';
@import '../datatable/components/datatable/datatable.component';
@import '../form/components/widgets/form';
+@import '../viewer/components/viewer.component';
@mixin adf-core-theme($theme) {
@include adf-form-theme($theme);
@@ -30,6 +31,7 @@
@include adf-userinfo-theme($theme);
@include adf-login-theme($theme);
@include adf-datatable-theme($theme);
+ @include adf-viewer-theme($theme);
}
diff --git a/lib/core/viewer/components/viewer.component.html b/lib/core/viewer/components/viewer.component.html
index 1fc190ad84..378008bab9 100644
--- a/lib/core/viewer/components/viewer.component.html
+++ b/lib/core/viewer/components/viewer.component.html
@@ -150,10 +150,10 @@
diff --git a/lib/core/viewer/components/viewer.component.scss b/lib/core/viewer/components/viewer.component.scss
index 7ae9ac19c5..cb11d12633 100644
--- a/lib/core/viewer/components/viewer.component.scss
+++ b/lib/core/viewer/components/viewer.component.scss
@@ -1,95 +1,99 @@
-$adf-viewer-background-color: #f5f5f5;
+@mixin adf-viewer-theme($theme) {
+ $background: map-get($theme, background);
+ $foreground: map-get($theme, foreground);
+ $adf-viewer-background-color: mat-color($background, card);
-@mixin full-screen() {
- width: 100%;
- height: 100%;
- background-color: $adf-viewer-background-color;
-}
-
-.adf-viewer {
-
- &__mimeicon {
- vertical-align: middle;
+ .full-screen {
+ width: 100%;
+ height: 100%;
+ background-color: $adf-viewer-background-color;
}
- &-container {
- .adf-viewer-layout-content {
- @include full-screen();
- position: relative;
- overflow-y: auto;
- overflow-x: hidden;
- z-index: 1;
+ .adf-viewer {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- flex: 1;
+ &__mimeicon {
+ vertical-align: middle;
+ }
+
+ &-container {
+ .adf-viewer-layout-content {
+ @extend .full-screen;
+ position: relative;
+ overflow-y: auto;
+ overflow-x: hidden;
+ z-index: 1;
- & > div {
display: flex;
- flex-flow: row wrap;
- margin: 0 auto;
- align-items: stretch;
+ flex-direction: row;
+ flex-wrap: wrap;
+ flex: 1;
+
+ & > div {
+ display: flex;
+ flex-flow: row wrap;
+ margin: 0 auto;
+ align-items: stretch;
+ }
+ }
+
+ .adf-viewer-layout {
+ @extend .full-screen;
+
+ display: flex;
+ flex-direction: row;
+ overflow-y: auto;
+ overflow-x: hidden;
+ position: relative;
+ }
+
+ .adf-viewer-content {
+ @extend .full-screen;
+ flex: 1;
}
}
- .adf-viewer-layout {
- @include full-screen();
+ &-overlay-container {
+ .adf-viewer-content {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ z-index: 1000;
+ }
+ }
+ &-inline-container {
+ @extend .full-screen;
+ }
+
+ &-content-container {
display: flex;
- flex-direction: row;
- overflow-y: auto;
- overflow-x: hidden;
- position: relative;
+ justify-content: center;
}
- .adf-viewer-content {
- @include full-screen();
- flex: 1;
+ &-unknown-content {
+ align-items: center;
+ display: flex;
}
- }
- &-overlay-container {
- .adf-viewer-content {
- position: fixed;
- top: 0px;
- left: 0px;
- z-index: 1000;
+ &__loading-screen {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ height: 85vh;
+
+ .mat-spinner {
+ margin: 0 auto;
+ }
}
- }
- &-inline-container {
- @include full-screen();
- }
-
- &-content-container {
- display: flex;
- justify-content: center;
- }
-
- &-unknown-content {
- align-items: center;
- display: flex;
- }
-
- &__loading-screen {
- display: flex;
- align-items: center;
- justify-content: center;
- flex-direction: column;
- height: 85vh;
-
- .mat-spinner {
- margin: 0 auto;
+ &__sidebar {
+ width: 350px;
+ display: block;
+ padding: 0;
+ background-color: #fafafa;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.27);
+ border-left: 1px solid mat-color($foreground, text, 0.07);
}
}
-
- &__sidebar {
- width: 350px;
- display: block;
- padding: 8px 0;
- background-color: #fafafa;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.27);
- border-left: 1px solid rgba(0, 0, 0, 0.07);
- }
}
diff --git a/lib/core/viewer/components/viewer.component.ts b/lib/core/viewer/components/viewer.component.ts
index 79b3aa0115..0501603f63 100644
--- a/lib/core/viewer/components/viewer.component.ts
+++ b/lib/core/viewer/components/viewer.component.ts
@@ -23,7 +23,6 @@ import {
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
import { BaseEvent } from '../../events';
import { AlfrescoApiService, LogService, RenditionsService } from '../../services';
-
import { ViewerMoreActionsComponent } from './viewer-more-actions.component';
import { ViewerOpenWithComponent } from './viewer-open-with.component';
import { ViewerSidebarComponent } from './viewer-sidebar.component';
@@ -92,6 +91,9 @@ export class ViewerComponent implements OnDestroy, OnChanges {
@Input()
sidebarPosition = 'right';
+ @Input()
+ sidebarTemplate: TemplateRef
= null;
+
@Output()
goBack = new EventEmitter>();
@@ -114,6 +116,7 @@ export class ViewerComponent implements OnDestroy, OnChanges {
downloadUrl: string = null;
fileName = 'document';
isLoading = false;
+ node: MinimalNodeEntryEntity;
extensionTemplates: { template: TemplateRef, isVisible: boolean }[] = [];
externalExtensions: string[] = [];
@@ -121,6 +124,7 @@ export class ViewerComponent implements OnDestroy, OnChanges {
otherMenu: any;
extension: string;
mimeType: string;
+ sidebarTemplateContext: { node: MinimalNodeEntryEntity } = { node: null };
private extensions = {
image: ['png', 'jpg', 'jpeg', 'gif', 'bpm'],
@@ -203,6 +207,7 @@ export class ViewerComponent implements OnDestroy, OnChanges {
}
this.extensionChange.emit(this.extension);
+ this.sidebarTemplateContext.node = data;
this.scrollTop();
resolve();
},