Merge pull request #7454 from opf/feature/30501-Render-text-field-links-in-the-backend-independently-of-the-user
[30501] Render text field links in the backend independently of the user [ci skip]pull/7449/head
commit
7ce157e5c2
@ -0,0 +1,24 @@ |
|||||||
|
<div class="preview-modal--container" *ngIf="workPackage"> |
||||||
|
<span class="type" |
||||||
|
[ngClass]="highlightingColor(workPackage.type)" |
||||||
|
[textContent]="workPackage.type.name"> |
||||||
|
</span> |
||||||
|
|
||||||
|
<span class="subject -bold" |
||||||
|
[textContent]="workPackage.subject"> |
||||||
|
</span> |
||||||
|
|
||||||
|
<span class="author -italic -small-font" |
||||||
|
[textContent]="'Created by ' + workPackage.author.name"> |
||||||
|
</span> |
||||||
|
|
||||||
|
<div [ngClass]="'status ' + highlightingColor(workPackage.status, true)" > |
||||||
|
<span [textContent]="workPackage.status.name"></span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="assignee" *ngIf="workPackage.assignee"> |
||||||
|
<user-avatar [user]="workPackage.assignee" |
||||||
|
data-class-list="avatar-mini"> |
||||||
|
</user-avatar> |
||||||
|
</div> |
||||||
|
</div> |
@ -0,0 +1,36 @@ |
|||||||
|
@import "helpers" |
||||||
|
|
||||||
|
.preview-modal--container |
||||||
|
position: absolute |
||||||
|
z-index: 5000 |
||||||
|
min-width: 200px |
||||||
|
max-width: 400px |
||||||
|
min-height: 100px |
||||||
|
max-height: 300px |
||||||
|
background: white |
||||||
|
padding: 15px |
||||||
|
border: 1px solid lightgrey |
||||||
|
border-radius: 3px |
||||||
|
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5) |
||||||
|
|
||||||
|
display: grid |
||||||
|
grid-template: auto auto auto / auto auto 1fr 1fr |
||||||
|
grid-column-gap: 5px |
||||||
|
grid-row-gap: 10px |
||||||
|
grid-template-areas: "type subject subject subject" "author author author author" "status status . assignee" |
||||||
|
|
||||||
|
.status |
||||||
|
grid-area: status |
||||||
|
padding: 0px 10px |
||||||
|
|
||||||
|
.type |
||||||
|
grid-area: type |
||||||
|
|
||||||
|
.author |
||||||
|
grid-area: author |
||||||
|
|
||||||
|
.subject |
||||||
|
grid-area: subject |
||||||
|
|
||||||
|
.assignee |
||||||
|
grid-area: assignee |
@ -0,0 +1,80 @@ |
|||||||
|
// -- copyright
|
||||||
|
// OpenProject is a project management system.
|
||||||
|
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License version 3.
|
||||||
|
//
|
||||||
|
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||||
|
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||||
|
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// See doc/COPYRIGHT.rdoc for more details.
|
||||||
|
// ++
|
||||||
|
|
||||||
|
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Inject, OnInit} from "@angular/core"; |
||||||
|
import {OpModalComponent} from "core-components/op-modals/op-modal.component"; |
||||||
|
import {OpModalLocalsToken, OpModalService} from "core-components/op-modals/op-modal.service"; |
||||||
|
import {OpModalLocalsMap} from "core-components/op-modals/op-modal.types"; |
||||||
|
import {I18nService} from "core-app/modules/common/i18n/i18n.service"; |
||||||
|
import {WorkPackageResource} from "core-app/modules/hal/resources/work-package-resource"; |
||||||
|
import {WorkPackageDmService} from "core-app/modules/hal/dm-services/work-package-dm.service"; |
||||||
|
import {HalResource} from "core-app/modules/hal/resources/hal-resource"; |
||||||
|
import {Highlighting} from "core-components/wp-fast-table/builders/highlighting/highlighting.functions"; |
||||||
|
|
||||||
|
@Component({ |
||||||
|
templateUrl: './wp-preview.modal.html', |
||||||
|
styleUrls: ['./wp-preview.modal.sass'], |
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush, |
||||||
|
}) |
||||||
|
export class WpPreviewModal extends OpModalComponent implements OnInit { |
||||||
|
public workPackage:WorkPackageResource; |
||||||
|
|
||||||
|
public text = { |
||||||
|
created_by: this.i18n.t('js.label_created_by'), |
||||||
|
}; |
||||||
|
|
||||||
|
constructor(readonly elementRef:ElementRef, |
||||||
|
@Inject(OpModalLocalsToken) readonly locals:OpModalLocalsMap, |
||||||
|
readonly cdRef:ChangeDetectorRef, |
||||||
|
readonly i18n:I18nService, |
||||||
|
readonly workPackageDmService:WorkPackageDmService, |
||||||
|
readonly opModalService:OpModalService) { |
||||||
|
super(locals, cdRef, elementRef); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
ngOnInit() { |
||||||
|
super.ngOnInit(); |
||||||
|
const workPackageLink = this.locals.workPackageLink; |
||||||
|
const workPackageId = HalResource.idFromLink(workPackageLink); |
||||||
|
|
||||||
|
this.workPackageDmService.loadWorkPackageById(workPackageId) |
||||||
|
.then((workPackage:WorkPackageResource) => { |
||||||
|
this.workPackage = workPackage; |
||||||
|
this.cdRef.detectChanges(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
highlightingColor(resource:HalResource, background:boolean = false) { |
||||||
|
if (background) { |
||||||
|
return Highlighting.backgroundClass(resource.$halType.toLowerCase(), resource.id!); |
||||||
|
} else { |
||||||
|
return Highlighting.inlineClass(resource.$halType.toLowerCase(), resource.id!); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
// -- copyright
|
||||||
|
// OpenProject is a project management system.
|
||||||
|
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License version 3.
|
||||||
|
//
|
||||||
|
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||||
|
// Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||||
|
// Copyright (C) 2010-2013 the ChiliProject Team
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; either version 2
|
||||||
|
// of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
//
|
||||||
|
// See doc/COPYRIGHT.rdoc for more details.
|
||||||
|
// ++
|
||||||
|
|
||||||
|
|
||||||
|
import {Injectable, Injector} from "@angular/core"; |
||||||
|
import {OpModalService} from "core-components/op-modals/op-modal.service"; |
||||||
|
import {WpPreviewModal} from "core-components/modals/preview-modal/wp-preview-modal/wp-preview.modal"; |
||||||
|
import {OpModalComponent} from "core-components/op-modals/op-modal.component"; |
||||||
|
|
||||||
|
@Injectable() |
||||||
|
export class PreviewTriggerService { |
||||||
|
private previewModal:OpModalComponent; |
||||||
|
private modalElement:HTMLElement; |
||||||
|
|
||||||
|
constructor(readonly opModalService:OpModalService, |
||||||
|
readonly injector:Injector) { |
||||||
|
} |
||||||
|
|
||||||
|
setupListener() { |
||||||
|
jQuery(document.body).on('mouseenter', '.preview-trigger', (e) => { |
||||||
|
e.preventDefault(); |
||||||
|
e.stopPropagation(); |
||||||
|
const el = jQuery(e.target); |
||||||
|
|
||||||
|
this.previewModal = this.opModalService.show(WpPreviewModal, this.injector, { workPackageLink: el.attr("href") }); |
||||||
|
this.modalElement = this.previewModal.elementRef.nativeElement; |
||||||
|
jQuery(this.modalElement).position({ |
||||||
|
my: 'left top', |
||||||
|
at: 'left bottom', |
||||||
|
of: el, |
||||||
|
collision: 'flipfit' |
||||||
|
}); |
||||||
|
|
||||||
|
jQuery(this.modalElement).addClass('-no-width -no-height'); |
||||||
|
}); |
||||||
|
|
||||||
|
jQuery(document.body).on('mouseleave', '.preview-trigger', (e:JQueryEventObject) => { |
||||||
|
e.preventDefault(); |
||||||
|
e.stopPropagation(); |
||||||
|
|
||||||
|
if (this.isMouseOverPreview(e)) { |
||||||
|
jQuery(this.modalElement).on('mouseleave', () => { |
||||||
|
this.opModalService.close(); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
this.opModalService.close(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private isMouseOverPreview(evt:JQueryEventObject) { |
||||||
|
const previewElement = jQuery(this.modalElement.children[0]); |
||||||
|
if (previewElement && previewElement.offset()) { |
||||||
|
let horizontalHover = evt.pageX >= Math.floor(previewElement.offset()!.left) && |
||||||
|
evt.pageX < previewElement.offset()!.left + previewElement.width()!; |
||||||
|
let verticalHover = evt.pageY >= Math.floor(previewElement.offset()!.top) && |
||||||
|
evt.pageY < previewElement.offset()!.top + previewElement.height()!; |
||||||
|
return horizontalHover && verticalHover; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue