diff --git a/package.json b/package.json index 74bb10bfed..2f74dd6cb8 100644 --- a/package.json +++ b/package.json @@ -105,8 +105,6 @@ "pem": "1.12.3", "reflect-metadata": "0.1.10", "rxjs": "5.4.3", - "shave": "^2.1.3", - "text-overflow-clamp": "^1.0.0", "ts-md5": "1.2.2", "webfontloader": "1.6.28", "zone.js": "0.8.18" diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 29be537891..00a3e56121 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,5 +1,4 @@ @import '../styles/variables.scss'; -@import '../styles/mixins.scss'; @import '../../node_modules/bootstrap/scss/bootstrap.scss'; @import "../../node_modules/font-awesome/scss/font-awesome.scss"; @@ -32,7 +31,3 @@ body { margin-top: $content-spacing; margin-bottom: $content-spacing; } - -.clamp-3 { - @include clamp(3); -} \ No newline at end of file diff --git a/src/app/app.reducer.ts b/src/app/app.reducer.ts index 72b29519de..117710e3c0 100644 --- a/src/app/app.reducer.ts +++ b/src/app/app.reducer.ts @@ -11,6 +11,7 @@ import { filterReducer, SearchFiltersState } from './+search-page/search-filters/search-filter/search-filter.reducer'; +import { truncatableReducer, TruncatablesState } from './shared/truncatable/truncatable.reducer'; export interface AppState { router: fromRouter.RouterReducerState; @@ -18,6 +19,7 @@ export interface AppState { header: HeaderState; searchSidebar: SearchSidebarState; searchFilter: SearchFiltersState; + truncatable: TruncatablesState; } export const appReducers: ActionReducerMap = { @@ -25,5 +27,6 @@ export const appReducers: ActionReducerMap = { hostWindow: hostWindowReducer, header: headerReducer, searchSidebar: sidebarReducer, - searchFilter: filterReducer + searchFilter: filterReducer, + truncatable: truncatableReducer }; diff --git a/src/app/core/cache/response-cache.service.ts b/src/app/core/cache/response-cache.service.ts index d734940496..eac76c519e 100644 --- a/src/app/core/cache/response-cache.service.ts +++ b/src/app/core/cache/response-cache.service.ts @@ -4,7 +4,7 @@ import { MemoizedSelector, Store } from '@ngrx/store'; import { Observable } from 'rxjs/Observable'; import { ResponseCacheEntry } from './response-cache.reducer'; -import { hasNoValue, hasValue } from '../../shared/empty.util'; +import { hasNoValue } from '../../shared/empty.util'; import { ResponseCacheRemoveAction, ResponseCacheAddAction } from './response-cache.actions'; import { RestResponse } from './response-cache.models'; import { CoreState } from '../core.reducers'; diff --git a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html index b1af777bcb..4e5d890b89 100644 --- a/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html +++ b/src/app/object-list/search-result-list-element/item-search-result/item-search-result-list-element.component.html @@ -9,6 +9,6 @@ (, )
-
+
\ No newline at end of file diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 89df25a38e..0a20938f5d 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -12,7 +12,6 @@ import { NgxPaginationModule } from 'ngx-pagination'; import { EnumKeysPipe } from './utils/enum-keys-pipe'; import { FileSizePipe } from './utils/file-size-pipe'; import { SafeUrlPipe } from './utils/safe-url-pipe'; -import { TruncatePipe } from './utils/truncate.pipe'; import { CollectionListElementComponent } from '../object-list/collection-list-element/collection-list-element.component'; import { ComcolPageContentComponent } from './comcol-page-content/comcol-page-content.component'; @@ -31,8 +30,9 @@ import { SearchFormComponent } from './search-form/search-form.component'; import { WrapperListElementComponent } from '../object-list/wrapper-list-element/wrapper-list-element.component'; import { ViewModeSwitchComponent } from './view-mode-switch/view-mode-switch.component'; import { VarDirective } from './utils/var.directive'; -import { ShaveDirective } from './utils/shave.directive'; - +import { TruncatePipe } from './utils/truncate.pipe'; +import { TruncatableComponent } from './truncatable/truncatable.component'; +import { TruncatableService } from './truncatable/truncatable.service'; const MODULES = [ // Do NOT include UniversalModule, HttpModule, or JsonpModule here @@ -67,6 +67,7 @@ const COMPONENTS = [ ThumbnailComponent, WrapperListElementComponent, ViewModeSwitchComponent, + TruncatableComponent ]; const ENTRY_COMPONENTS = [ @@ -77,9 +78,12 @@ const ENTRY_COMPONENTS = [ SearchResultListElementComponent ]; +const PROVIDERS = [ + TruncatableService +]; + const DIRECTIVES = [ - VarDirective, - ShaveDirective + VarDirective ]; @NgModule({ @@ -93,6 +97,9 @@ const DIRECTIVES = [ ...ENTRY_COMPONENTS, ...DIRECTIVES ], + providers: [ + ...PROVIDERS + ], exports: [ ...MODULES, ...PIPES, diff --git a/src/app/shared/truncatable/truncatable.actions.ts b/src/app/shared/truncatable/truncatable.actions.ts new file mode 100644 index 0000000000..bc9a7e2258 --- /dev/null +++ b/src/app/shared/truncatable/truncatable.actions.ts @@ -0,0 +1,29 @@ +import { Action } from '@ngrx/store'; +import { type } from '../ngrx/type'; + +/** + * For each action type in an action group, make a simple + * enum object for all of this group's action types. + * + * The 'type' utility function coerces strings into string + * literal types and runs a simple check to guarantee all + * action types in the application are unique. + */ +export const TruncatableActionTypes = { + TOGGLE: type('dspace/truncatable/TOGGLE'), +}; + +export class TruncatableAction implements Action { + id: string; + type; + constructor(name: string) { + this.id = name; + } +} + +/* tslint:disable:max-classes-per-file */ +export class TruncatableToggleAction extends TruncatableAction { + type = TruncatableActionTypes.TOGGLE; +} + +/* tslint:enable:max-classes-per-file */ diff --git a/src/app/shared/truncatable/truncatable.component.html b/src/app/shared/truncatable/truncatable.component.html new file mode 100644 index 0000000000..bf03d73eca --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/src/app/shared/truncatable/truncatable.component.scss b/src/app/shared/truncatable/truncatable.component.scss new file mode 100644 index 0000000000..b68bfd1d6e --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.scss @@ -0,0 +1,41 @@ +@import '../../../styles/_variables.scss'; +@import '../../../styles/_mixins.scss'; + +@mixin clamp($lines) { + max-height: $lines * $line-height-base * $font-size-base; + position: relative; + overflow: hidden; + line-height: $line-height-base; + overflow-wrap: break-word; + + &:after { + content: "..."; + color: $link-color; + text-align: right; + position: absolute; + padding-right: 15px; + top: ($lines - 1) * $line-height-base * $font-size-base; + right: 0; + width: 30%; + min-width: 75px; + max-width: 150px; + height: $line-height-base * $font-size-base; + background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); + } + + +} +.clamp-1 { +@include clamp(1); +} +.clamp-2 { + @include clamp(2); + } +.clamp-3 { +@include clamp(3); +} +.clamp-15 { +@include clamp(15); +} + + diff --git a/src/app/shared/truncatable/truncatable.component.ts b/src/app/shared/truncatable/truncatable.component.ts new file mode 100644 index 0000000000..88185140ed --- /dev/null +++ b/src/app/shared/truncatable/truncatable.component.ts @@ -0,0 +1,42 @@ +import { + Component, Input +} from '@angular/core'; +import { TruncatableService } from './truncatable.service'; + +@Component({ + selector: 'ds-truncatable', + templateUrl: './truncatable.component.html', + styleUrls: ['./truncatable.component.scss'] +}) +export class TruncatableComponent { + @Input() minLines: number; + @Input() maxLines: number; + @Input() initialExpand = false; + @Input() id: string; + @Input() content; + private lines: number; + + public constructor(private service: TruncatableService) { + + } + + ngOnInit() { + if (this.initialExpand) { + this.service.toggle(this.id); + } + this.setLines(); + } + + public toggleCollapse() { + this.service.toggle(this.id); + this.setLines(); + } + + private setLines() { + if (this.service.isCollapsed(this.id)) { + this.lines = this.minLines; + } else { + this.lines = this.maxLines; + } + } +} diff --git a/src/app/shared/truncatable/truncatable.reducer.ts b/src/app/shared/truncatable/truncatable.reducer.ts new file mode 100644 index 0000000000..f48d92f49c --- /dev/null +++ b/src/app/shared/truncatable/truncatable.reducer.ts @@ -0,0 +1,31 @@ +import { TruncatableAction, TruncatableActionTypes } from './truncatable.actions'; + +export interface TruncatableState { + collapsed: boolean; +} + +export interface TruncatablesState { + [id: string]: TruncatableState +} + +const initialState: TruncatablesState = Object.create(null); + +export function truncatableReducer(state = initialState, action: TruncatableAction): TruncatablesState { + + switch (action.type) { + + case TruncatableActionTypes.TOGGLE: { + if (!state[action.id]) { + state[action.id] = {collapsed: false}; + } + return Object.assign({}, state, { + [action.id]: { + collapsed: !state[action.id].collapsed, + } + }); + } + default: { + return state; + } + } +} diff --git a/src/app/shared/truncatable/truncatable.service.ts b/src/app/shared/truncatable/truncatable.service.ts new file mode 100644 index 0000000000..e2851a8a3b --- /dev/null +++ b/src/app/shared/truncatable/truncatable.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; +import { createSelector, MemoizedSelector, Store } from '@ngrx/store'; +import { Observable } from 'rxjs/Observable'; +import { TruncatablesState, TruncatableState } from './truncatable.reducer'; +import { TruncatableToggleAction } from './truncatable.actions'; +import { hasValue } from '../empty.util'; + +const truncatableStateSelector = (state: TruncatablesState) => state.truncatable; + +@Injectable() +export class TruncatableService { + + constructor(private store: Store) { + } + + isCollapsed(id: string): Observable { + return this.store.select(truncatableByIdSelector(id)) + .map((object: TruncatableState) => { + console.log(object); + if (object) { + return object.collapsed; + } else { + return false; + } + }); + } + + public toggle(id: string): void { + this.store.dispatch(new TruncatableToggleAction(id)); + } +} + +function truncatableByIdSelector(id: string): MemoizedSelector { + return keySelector(id); +} + +export function keySelector(key: string): MemoizedSelector { + return createSelector(truncatableStateSelector, (state: TruncatableState) => { + console.log(state, 'test'); + + if (hasValue(state)) { + return state[key]; + } else { + return undefined; + } + }); +} diff --git a/src/app/shared/utils/shave.directive.ts b/src/app/shared/utils/shave.directive.ts deleted file mode 100644 index df37a9a8c5..0000000000 --- a/src/app/shared/utils/shave.directive.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { - Directive, ElementRef, Inject, Input, OnChanges, OnDestroy, - OnInit -} from '@angular/core'; -import { default as shave } from 'shave'; -import { NativeWindowRef, NativeWindowService } from '../window.service'; -import { Observable } from 'rxjs/Observable'; - -@Directive({ - selector: '[dsShave]' -}) -export class ShaveDirective implements OnDestroy, OnChanges { - - @Input() shave: IShaveOptions = {}; - - @Input() - set shaveHeight(value) { - if (value > 0) { - console.log(value); - this._shaveHeight = value; - } - }; - - get shaveHeight() { - return this._shaveHeight; - } - - private _shaveHeight = 72; - private sub; - - constructor(private ele: ElementRef, @Inject(NativeWindowService) private _window: NativeWindowRef) { - } - - ngOnChanges(): void { - if (this.shaveHeight > 0) { - this.runShave(); - } - this.subscribeForResizeEvent(); - } - - subscribeForResizeEvent() { - const obs = Observable.fromEvent(this._window.nativeWindow, 'resize'); - this.sub = obs.subscribe((e) => this.runShave()); - } - - private runShave() { - shave(this.ele.nativeElement, this.shaveHeight, this.shave); - } - - ngOnDestroy(): void { - if (this.sub) { - this.sub.unsubscribe(); - } - } - -} diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss index 6c773e34a3..564ffc7755 100644 --- a/src/styles/_mixins.scss +++ b/src/styles/_mixins.scss @@ -1,26 +1,3 @@ @import '../../node_modules/bootstrap/scss/functions.scss'; @import '../../node_modules/bootstrap/scss/mixins.scss'; -@import '../../node_modules/bootstrap/scss/variables.scss'; - -@mixin clamp($lines) { - max-height: $lines * $line-height-base * $font-size-base; - position: relative; - overflow: hidden; - line-height: $line-height-base; - overflow-wrap: break-word; - - &:after { - content: "..."; - color: $link-color; - text-align: right; - position: absolute; - padding-right: 15px; - top: ($lines - 1) * $line-height-base * $font-size-base; - right: 0; - width: 30%; - min-width: 75px; - max-width: 150px; - height: $line-height-base * $font-size-base; - background: linear-gradient(to right, rgba(255, 255, 255, 0), $body-bg 50%); - } -} \ No newline at end of file +@import '../../node_modules/bootstrap/scss/variables.scss'; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 53cd4a6b72..91b2a787e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1942,10 +1942,6 @@ dom-serializer@0: domelementtype "~1.1.1" entities "~1.1.1" -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -2795,13 +2791,6 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, gl once "^1.3.0" path-is-absolute "^1.0.0" -global@^4.3.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4443,12 +4432,6 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - dependencies: - dom-walk "^0.1.0" - minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -5798,10 +5781,6 @@ process@^0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -6668,10 +6647,6 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -shave@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/shave/-/shave-2.1.3.tgz#89c7df997d35a95bc31703c9150161bc98d3fa3b" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -7165,12 +7140,6 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -text-overflow-clamp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/text-overflow-clamp/-/text-overflow-clamp-1.0.0.tgz#9327faec1b85bf0b293d8c8df32243cbee5c050e" - dependencies: - global "^4.3.1" - throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c"