|
import { inject, bindable, observable, Container, ViewEngine, View, TaskQueue} from 'aurelia-framework'; |
|
|
|
@inject(Element, Container, ViewEngine, TaskQueue) |
|
export class TruncateCustomAttribute { |
|
@bindable max; |
|
@observable @bindable text; |
|
show = false; |
|
element; |
|
divElement; |
|
originalText; |
|
ellipsis; |
|
viewEngine; |
|
container; |
|
queue; |
|
|
|
constructor(element, container, viewEngine, queue) { |
|
this.element = element; |
|
this.container = container; |
|
this.viewEngine = viewEngine; |
|
this.ellipsis = document.createElement('span'); |
|
this.ellipsis.appendChild(document.createTextNode('\u2026')); |
|
this.ellipsis.addEventListener('click', this.handleClick); |
|
this.ellipsis.style.cursor ='pointer'; |
|
this.queue = queue; |
|
} |
|
|
|
bind() { |
|
this.originalText = this.text ? this.text : this.element.innerText; |
|
this.truncate(this.originalText); |
|
} |
|
|
|
truncate = (text) => { |
|
if (Number.isInteger(this.max) && text.length > this.max) { |
|
this.element.innerText = text.slice(0, this.max); |
|
this.element.appendChild(this.ellipsis); |
|
|
|
} |
|
} |
|
|
|
handleClick = e => { |
|
if (!this.show) { |
|
this.showFullText(); |
|
} |
|
if (this.show) { |
|
/* |
|
Remove if click is outside of it's client rectangle. |
|
*/ |
|
let containerRect = this.divElement.getBoundingClientRect(); |
|
let elementRect = this.element.getBoundingClientRect(); |
|
let inContainerRect = e.clientX > containerRect.left && e.clientX < containerRect.right && e.clientY > containerRect.top && e.clientY < containerRect.bottom; |
|
let inElementRect = e.clientX > elementRect.left && e.clientX < elementRect.right && e.clientY > elementRect.top && e.clientY < elementRect.bottom; |
|
if (!inContainerRect && !inElementRect) { |
|
this.hideFullText(); |
|
} |
|
} |
|
} |
|
|
|
showFullText = () => { |
|
this.viewEngine.loadViewFactory('./truncate.html').then(factory => { |
|
const childContainer = this.container.createChild(); |
|
const view = factory.create(childContainer); |
|
view.bind(this); |
|
this.addElement(view); |
|
document.addEventListener('mouseup', this.handleClick); |
|
window.setTimeout(() => { |
|
this.show = true; |
|
}, 0); |
|
}); |
|
} |
|
|
|
hideFullText = () => { |
|
this.show = false; |
|
document.removeEventListener('mouseup', this.handleClick); |
|
// Allow time to complete the transition |
|
window.setTimeout(() => { |
|
this.element.parentNode.removeChild(this.divElement); |
|
}, 200); |
|
} |
|
|
|
addElement(view) { |
|
//const body = document.querySelectorAll('body')[0]; |
|
|
|
this.divElement = document.createElement('div'); |
|
view.appendNodesTo(this.divElement); |
|
|
|
|
|
const elementRect = this.element.getBoundingClientRect(); |
|
const left = elementRect.left + window.scrollX; |
|
const height = this.divElement.getBoundingClientRect().height; |
|
var top = elementRect.top + elementRect.height; |
|
|
|
top = ((top+height) < window.innerHeight) ? top + window.scrollY : (elementRect.top - height + window.scrollY); |
|
|
|
this.divElement.style.top = top + 'px'; |
|
this.divElement.style.left = left + 'px'; |
|
this.divElement.style.position = 'absolute'; |
|
this.divElement.style.zIndex = '2001'; |
|
|
|
this.element.parentNode.insertBefore(this.divElement, this.element); |
|
} |
|
|
|
textChanged = (newVal, oldVal) => { |
|
if(newVal !== oldVal) { |
|
this.originalText = newVal; |
|
this.truncate(this.originalText); |
|
} |
|
} |
|
} |