angular2-emoji-picker
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -0,1 +1,22 @@ | ||
<a name="1.2.0"></a> | ||
# [1.2.0](https://github.com/angular/angular/compare/v1.1.0...v1.2.0) (2017-04-20) | ||
### Bug Fixes | ||
* **EmojiPickerCaret directive:** added support for input elements | ||
### Performance Improvements | ||
* **EmojiPickerApi directive:** properly unsubscribing to event emitters | ||
* **EmojiPickerCaret directive:** improved event management, smart caret preserving event emitting when content of an editable div changes through DOM mutation. | ||
## What's New | ||
* **(emojiPickerCaretEmitter):** emits the element textContent upon changes | ||
* **CaretEvent:** New caret event class available for use | ||
* **EmojiEvent:** New caret event class available for use | ||
### BREAKING CHANGES | ||
* **(emojiPickerSelect) emitter:** the picker now emits an EmojiEvent object containing a char and label properties. Change usage accordingly (previous => now: event[0] => event.char, event[1] => event.label) | ||
<a name="1.1.0"></a> | ||
@@ -2,0 +23,0 @@ # [1.1.0](https://github.com/angular/angular/compare/v1.0.5...v1.1.0) (2017-04-19) |
import { Component, ViewChild } from '@angular/core'; | ||
import { CaretEvent, EmojiEvent } from "../../../src"; | ||
@@ -11,14 +12,18 @@ @Component({ | ||
public eventPosMock; | ||
public direction = Math.random() > 0.5 ? (Math.random() > 0.5 ? 'top' : 'bottom') : (Math.random() > 0.5 ? 'right' : 'left'); | ||
public toggled; | ||
public toggled = false; | ||
public content = 'Type letters, enter emojis, go nuts...'; | ||
handleSelection(e) { | ||
this.eventMock = JSON.stringify(e); | ||
console.log('Emoji event: ' + this.eventMock); | ||
private _lastCaretEvent: CaretEvent; | ||
handleSelection(event: EmojiEvent) { | ||
this.content = this.content.slice(0, this._lastCaretEvent.caretOffset) + event.char + this.content.slice(this._lastCaretEvent.caretOffset); | ||
this.eventMock = JSON.stringify(event); | ||
} | ||
handleCurrentCaret(e) { | ||
this.eventPosMock = `{ caretOffset : ${e.caretOffset}, caretRange: Range{...} }`; | ||
console.log('Caret position: ' + this.eventPosMock); | ||
handleCurrentCaret(event: CaretEvent) { | ||
this._lastCaretEvent = event; | ||
this.eventPosMock = `{ caretOffset : ${event.caretOffset}, caretRange: Range{...}, textContent: ${event.textContent} }`; | ||
} | ||
} |
@@ -0,1 +1,22 @@ | ||
<a name="1.2.0"></a> | ||
# [1.2.0](https://github.com/angular/angular/compare/v1.1.0...v1.2.0) (2017-04-20) | ||
### Bug Fixes | ||
* **EmojiPickerCaret directive:** added support for input elements | ||
### Performance Improvements | ||
* **EmojiPickerApi directive:** properly unsubscribing to event emitters | ||
* **EmojiPickerCaret directive:** improved event management, smart caret preserving event emitting when content of an editable div changes through DOM mutation. | ||
## What's New | ||
* **(emojiPickerCaretEmitter):** emits the element textContent upon changes | ||
* **CaretEvent:** New caret event class available for use | ||
* **EmojiEvent:** New caret event class available for use | ||
### BREAKING CHANGES | ||
* **(emojiPickerSelect) emitter:** the picker now emits an EmojiEvent object containing a char and label properties. Change usage accordingly (previous => now: event[0] => event.char, event[1] => event.label) | ||
<a name="1.1.0"></a> | ||
@@ -2,0 +23,0 @@ # [1.1.0](https://github.com/angular/angular/compare/v1.0.5...v1.1.0) (2017-04-19) |
@@ -17,2 +17,3 @@ import { ComponentFactoryResolver, ViewContainerRef, ElementRef, EventEmitter } from '@angular/core'; | ||
private _emojiPickerRef; | ||
private _emojiSubs; | ||
constructor(_cfr: ComponentFactoryResolver, _vcr: ViewContainerRef, _el: ElementRef); | ||
@@ -19,0 +20,0 @@ openPicker(): void; |
@@ -7,2 +7,3 @@ import { Directive, Input, ComponentFactoryResolver, ViewContainerRef, ElementRef, EventEmitter, Output } from '@angular/core'; | ||
import { DIRECTIONS } from '../lib/picker-directions'; | ||
import { EmojiEvent } from "../"; | ||
var EmojiPickerApiDirective = (function () { | ||
@@ -19,2 +20,3 @@ function EmojiPickerApiDirective(_cfr, _vcr, _el) { | ||
this._destroyed = new Subject(); | ||
this._emojiSubs = []; | ||
this._emojiPickerOpenState | ||
@@ -57,4 +59,3 @@ .takeUntil(this._destroyed) | ||
this._emojiPickerRef.instance.setPosition(this._el, this._directionCode); | ||
this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(function (event) { return _this.emojiPickerIfEmitter.emit(false); }); | ||
this._emojiPickerRef.instance.selectionEmitter.subscribe(function (event) { return _this.selectEmitter.emit(event); }); | ||
this._emojiSubs.push(this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(function (event) { return _this.emojiPickerIfEmitter.emit(false); }), this._emojiPickerRef.instance.selectionEmitter.subscribe(function (event) { return _this.selectEmitter.emit(EmojiEvent.fromArray(event)); })); | ||
}; | ||
@@ -65,3 +66,5 @@ EmojiPickerApiDirective.prototype.closePicker = function () { | ||
} | ||
this._emojiSubs.forEach(function (subscription) { return subscription.unsubscribe(); }); | ||
this._emojiPickerRef.destroy(); | ||
this._emojiSubs = []; | ||
delete this._emojiPickerRef; | ||
@@ -68,0 +71,0 @@ }; |
@@ -18,2 +18,4 @@ import { | ||
import { DIRECTIONS } from '../lib/picker-directions'; | ||
import { Subscription } from "rxjs/Subscription"; | ||
import { EmojiEvent } from "../"; | ||
@@ -50,2 +52,3 @@ @Directive({ | ||
private _emojiPickerRef: ComponentRef<EmojiPickerComponent>; | ||
private _emojiSubs: Subscription[] = []; | ||
@@ -74,4 +77,6 @@ constructor( | ||
this._emojiPickerRef.instance.setPosition(this._el, this._directionCode); | ||
this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(event => this.emojiPickerIfEmitter.emit(false)); | ||
this._emojiPickerRef.instance.selectionEmitter.subscribe(event => this.selectEmitter.emit(event)); | ||
this._emojiSubs.push( | ||
this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(event => this.emojiPickerIfEmitter.emit(false)), | ||
this._emojiPickerRef.instance.selectionEmitter.subscribe(event => this.selectEmitter.emit(EmojiEvent.fromArray(event))) | ||
); | ||
} | ||
@@ -84,3 +89,6 @@ | ||
this._emojiSubs.forEach((subscription: Subscription) => subscription.unsubscribe()); | ||
this._emojiPickerRef.destroy(); | ||
this._emojiSubs = []; | ||
delete this._emojiPickerRef; | ||
@@ -87,0 +95,0 @@ } |
import { EventEmitter, ElementRef } from '@angular/core'; | ||
import 'rxjs/add/operator/takeUntil'; | ||
import 'rxjs/add/operator/distinctUntilChanged'; | ||
import { CaretEvent } from "../../src"; | ||
export declare class EmojiPickerCaretDirective { | ||
private _el; | ||
caretEmitter: EventEmitter<{}>; | ||
private _position; | ||
private _destroyed; | ||
caretEmitter: EventEmitter<CaretEvent>; | ||
private _caretEvent$; | ||
private _destroyed$; | ||
private _lastCaretEvent; | ||
private _win; | ||
@@ -15,9 +17,5 @@ private _doc; | ||
ngOnInit(): void; | ||
compareRangeObject(r1: any, r2: any): boolean; | ||
ngOnDestroy(): void; | ||
updateCaretPosition(): void; | ||
getCaretCharacterOffsetWithin(win: any, doc: any, element: any): { | ||
caretOffset: number; | ||
caretRange: any; | ||
}; | ||
updateCaretDueMutation(): void; | ||
} |
@@ -5,8 +5,20 @@ import { Directive, Output, EventEmitter, ElementRef } from '@angular/core'; | ||
import 'rxjs/add/operator/distinctUntilChanged'; | ||
import { CaretEvent } from "../../src"; | ||
var EmojiPickerCaretDirective = (function () { | ||
function EmojiPickerCaretDirective(_el) { | ||
var _this = this; | ||
this._el = _el; | ||
this.caretEmitter = new EventEmitter(); | ||
this._position = new Subject(); | ||
this._destroyed = new Subject(); | ||
this._caretEvent$ = new Subject(); | ||
this._destroyed$ = new Subject(); | ||
this._lastCaretEvent = CaretEvent.generateNullEvent(); | ||
this._caretEvent$ | ||
.takeUntil(this._destroyed$) | ||
.distinctUntilChanged(function (event1, event2) { | ||
return CaretEvent.compare(event1, event2); | ||
}) | ||
.subscribe(function (event) { | ||
_this.caretEmitter.emit(event); | ||
_this._lastCaretEvent = event.clone(); | ||
}); | ||
} | ||
@@ -34,70 +46,26 @@ Object.defineProperty(EmojiPickerCaretDirective.prototype, "doc", { | ||
EmojiPickerCaretDirective.prototype.ngOnInit = function () { | ||
var _this = this; | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName !== 'INPUT') { | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName.toLowerCase() !== 'input') { | ||
throw new Error('(emojiPickerPositionEmitter) should only work on contenteditable enabled or input elements'); | ||
} | ||
this._position | ||
.takeUntil(this._destroyed) | ||
.distinctUntilChanged(function (event1, event2) { | ||
if ( | ||
/** if range suddenly exists or disappears */ | ||
!event1.caretRange && event2.caretRange || | ||
event1.caretRange && !event2.caretRange || | ||
/** if caret offset has changed */ | ||
event1.caretOffset !== event2.caretOffset || | ||
/** if caret range has changed in these properties */ | ||
!_this.compareRangeObject(event1.caretRange, event2.caretRange)) { | ||
return false; | ||
} | ||
return true; | ||
}) | ||
.subscribe(function (event) { return _this.caretEmitter.emit(event); }); | ||
}; | ||
EmojiPickerCaretDirective.prototype.compareRangeObject = function (r1, r2) { | ||
for (var k in r1) { | ||
if (r1[k] !== r2[k]) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
EmojiPickerCaretDirective.prototype.ngOnDestroy = function () { | ||
this._destroyed.next(true); | ||
this._destroyed$.next(true); | ||
}; | ||
EmojiPickerCaretDirective.prototype.updateCaretPosition = function () { | ||
var position = this.getCaretCharacterOffsetWithin(this.win, this.doc, this._el.nativeElement); | ||
this._position.next(position); | ||
var cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
this._caretEvent$.next(cEvent); | ||
}; | ||
EmojiPickerCaretDirective.prototype.getCaretCharacterOffsetWithin = function (win, doc, element) { | ||
var caretOffset = 0, sel, caretRange; | ||
if (typeof win.getSelection != "undefined") { | ||
sel = win.getSelection(); | ||
if (sel.rangeCount > 0) { | ||
var range = win.getSelection().getRangeAt(0); | ||
var preCaretRange = range.cloneRange(); | ||
preCaretRange.selectNodeContents(element); | ||
preCaretRange.setEnd(range.endContainer, range.endOffset); | ||
caretOffset = preCaretRange.toString().length; | ||
/** Keeping a reference of the range to emit */ | ||
caretRange = range.cloneRange(); | ||
} | ||
} | ||
else if ((sel = doc.selection) && sel.type != "Control") { | ||
var textRange = sel.createRange(); | ||
var preCaretTextRange = doc.body.createTextRange(); | ||
preCaretTextRange.moveToElementText(element); | ||
preCaretTextRange.setEndPoint("EndToEnd", textRange); | ||
caretOffset = preCaretTextRange.text.length; | ||
/** Keeping a reference of the range to emit and making it compatible */ | ||
caretRange = textRange.duplicate(); | ||
caretRange.insertNode = function (e) { | ||
var container = document.createElement("div"); | ||
container.appendChild(e); | ||
caretRange.pasteHTML(container.innerHTML); | ||
}; | ||
} | ||
return { | ||
caretOffset: caretOffset, | ||
caretRange: caretRange | ||
}; | ||
EmojiPickerCaretDirective.prototype.updateCaretDueMutation = function () { | ||
var _this = this; | ||
var cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
var textMovement = cEvent.textContent.length - this._lastCaretEvent.textContent.length; | ||
cEvent.caretOffset = this._lastCaretEvent.caretOffset + textMovement; | ||
/** change detection after DOMSubtreeModified event is weird | ||
* ChangeDetectorRef.detectChanges(), ChangeDetectorRef.markForCheck(), ApplicationRef.tick(), NgZone.run() | ||
* all of those methods did not work as expected. | ||
* As a temporary hack I am emitting an event after a short timeout, which is fine due to the _caretEvent$ smart stream | ||
*/ | ||
setTimeout(function () { | ||
_this._caretEvent$.next(cEvent); | ||
}); | ||
}; | ||
@@ -113,4 +81,5 @@ return EmojiPickerCaretDirective; | ||
'(mouseup)': 'updateCaretPosition()', | ||
'(selectstart)': 'updateCaretPosition()', | ||
'(focus)': 'updateCaretPosition()', | ||
'(DOMSubtreeModified)': 'updateCaretPosition($event)' | ||
'(DOMSubtreeModified)': 'updateCaretDueMutation($event)' | ||
} | ||
@@ -117,0 +86,0 @@ },] }, |
@@ -1,1 +0,1 @@ | ||
[{"__symbolic":"module","version":3,"metadata":{"EmojiPickerCaretDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive"},"arguments":[{"selector":"[emojiPickerCaretEmitter]","host":{"(keyup)":"updateCaretPosition()","(mouseup)":"updateCaretPosition()","(focus)":"updateCaretPosition()","(DOMSubtreeModified)":"updateCaretPosition($event)","$quoted$":["(keyup)","(mouseup)","(focus)","(DOMSubtreeModified)"]}}]}],"members":{"caretEmitter":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"},"arguments":["emojiPickerCaretEmitter"]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}]}],"ngOnInit":[{"__symbolic":"method"}],"compareRangeObject":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"updateCaretPosition":[{"__symbolic":"method"}],"getCaretCharacterOffsetWithin":[{"__symbolic":"method"}]}}}},{"__symbolic":"module","version":1,"metadata":{"EmojiPickerCaretDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive"},"arguments":[{"selector":"[emojiPickerCaretEmitter]","host":{"(keyup)":"updateCaretPosition()","(mouseup)":"updateCaretPosition()","(focus)":"updateCaretPosition()","(DOMSubtreeModified)":"updateCaretPosition($event)"}}]}],"members":{"caretEmitter":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"},"arguments":["emojiPickerCaretEmitter"]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}]}],"ngOnInit":[{"__symbolic":"method"}],"compareRangeObject":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"updateCaretPosition":[{"__symbolic":"method"}],"getCaretCharacterOffsetWithin":[{"__symbolic":"method"}]}}}}] | ||
[{"__symbolic":"module","version":3,"metadata":{"EmojiPickerCaretDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive"},"arguments":[{"selector":"[emojiPickerCaretEmitter]","host":{"(keyup)":"updateCaretPosition()","(mouseup)":"updateCaretPosition()","(selectstart)":"updateCaretPosition()","(focus)":"updateCaretPosition()","(DOMSubtreeModified)":"updateCaretDueMutation($event)","$quoted$":["(keyup)","(mouseup)","(selectstart)","(focus)","(DOMSubtreeModified)"]}}]}],"members":{"caretEmitter":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"},"arguments":["emojiPickerCaretEmitter"]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"updateCaretPosition":[{"__symbolic":"method"}],"updateCaretDueMutation":[{"__symbolic":"method"}]}}}},{"__symbolic":"module","version":1,"metadata":{"EmojiPickerCaretDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive"},"arguments":[{"selector":"[emojiPickerCaretEmitter]","host":{"(keyup)":"updateCaretPosition()","(mouseup)":"updateCaretPosition()","(selectstart)":"updateCaretPosition()","(focus)":"updateCaretPosition()","(DOMSubtreeModified)":"updateCaretDueMutation($event)"}}]}],"members":{"caretEmitter":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output"},"arguments":["emojiPickerCaretEmitter"]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef"}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"updateCaretPosition":[{"__symbolic":"method"}],"updateCaretDueMutation":[{"__symbolic":"method"}]}}}}] |
@@ -1,2 +0,2 @@ | ||
import { Directive, Output, EventEmitter, ElementRef } from '@angular/core'; | ||
import { Directive, Output, EventEmitter, ElementRef, ChangeDetectorRef, ApplicationRef, NgZone } from '@angular/core'; | ||
import { Subject } from "rxjs/Subject"; | ||
@@ -6,3 +6,5 @@ import 'rxjs/add/operator/takeUntil'; | ||
@Directive({ | ||
import { CaretEvent } from "../../src"; | ||
@Directive({ | ||
selector: '[emojiPickerCaretEmitter]', | ||
@@ -12,12 +14,15 @@ host: { | ||
'(mouseup)': 'updateCaretPosition()', | ||
'(selectstart)': 'updateCaretPosition()', | ||
'(focus)': 'updateCaretPosition()', | ||
'(DOMSubtreeModified)': 'updateCaretPosition($event)' | ||
'(DOMSubtreeModified)': 'updateCaretDueMutation($event)' | ||
} | ||
}) | ||
export class EmojiPickerCaretDirective { | ||
@Output('emojiPickerCaretEmitter') caretEmitter = new EventEmitter(); | ||
@Output('emojiPickerCaretEmitter') caretEmitter = new EventEmitter<CaretEvent>(); | ||
private _position = new Subject<{ caretOffset, caretRange }>(); | ||
private _destroyed = new Subject<boolean>(); | ||
private _caretEvent$ = new Subject<CaretEvent>(); | ||
private _destroyed$ = new Subject<boolean>(); | ||
private _lastCaretEvent: CaretEvent = CaretEvent.generateNullEvent(); | ||
private _win; | ||
@@ -42,85 +47,47 @@ private _doc; | ||
constructor(private _el: ElementRef) { } | ||
ngOnInit() { | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName !== 'INPUT') { | ||
throw new Error('(emojiPickerPositionEmitter) should only work on contenteditable enabled or input elements'); | ||
} | ||
this._position | ||
.takeUntil(this._destroyed) | ||
constructor( | ||
private _el: ElementRef | ||
) { | ||
this._caretEvent$ | ||
.takeUntil(this._destroyed$) | ||
.distinctUntilChanged((event1, event2) => { | ||
if ( | ||
/** if range suddenly exists or disappears */ | ||
!event1.caretRange && event2.caretRange || | ||
event1.caretRange && !event2.caretRange || | ||
/** if caret offset has changed */ | ||
event1.caretOffset !== event2.caretOffset || | ||
/** if caret range has changed in these properties */ | ||
!this.compareRangeObject(event1.caretRange, event2.caretRange) | ||
) { | ||
return false; | ||
} | ||
return true; | ||
return CaretEvent.compare(event1, event2); | ||
}) | ||
.subscribe(event => this.caretEmitter.emit(event)) | ||
.subscribe((event: CaretEvent) => { | ||
this.caretEmitter.emit(event); | ||
this._lastCaretEvent = event.clone() | ||
}) | ||
; | ||
} | ||
compareRangeObject(r1, r2) { | ||
for (let k in r1) { | ||
if (r1[k] !== r2[k]) { | ||
return false | ||
} | ||
ngOnInit() { | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName.toLowerCase() !== 'input') { | ||
throw new Error('(emojiPickerPositionEmitter) should only work on contenteditable enabled or input elements'); | ||
} | ||
return true; | ||
} | ||
ngOnDestroy() { | ||
this._destroyed.next(true); | ||
this._destroyed$.next(true); | ||
} | ||
updateCaretPosition() { | ||
const position = this.getCaretCharacterOffsetWithin(this.win, this.doc, this._el.nativeElement); | ||
this._position.next(position); | ||
const cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
this._caretEvent$.next(cEvent); | ||
} | ||
getCaretCharacterOffsetWithin(win, doc, element) { | ||
let caretOffset = 0, sel, caretRange; | ||
updateCaretDueMutation() { | ||
const cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
let textMovement = cEvent.textContent.length - this._lastCaretEvent.textContent.length; | ||
cEvent.caretOffset = this._lastCaretEvent.caretOffset + textMovement; | ||
if (typeof win.getSelection != "undefined") { | ||
sel = win.getSelection(); | ||
if (sel.rangeCount > 0) { | ||
const range = win.getSelection().getRangeAt(0); | ||
const preCaretRange = range.cloneRange(); | ||
preCaretRange.selectNodeContents(element); | ||
preCaretRange.setEnd(range.endContainer, range.endOffset); | ||
caretOffset = preCaretRange.toString().length; | ||
/** change detection after DOMSubtreeModified event is weird | ||
* ChangeDetectorRef.detectChanges(), ChangeDetectorRef.markForCheck(), ApplicationRef.tick(), NgZone.run() | ||
* all of those methods did not work as expected. | ||
* As a temporary hack I am emitting an event after a short timeout, which is fine due to the _caretEvent$ smart stream | ||
*/ | ||
/** Keeping a reference of the range to emit */ | ||
caretRange = range.cloneRange(); | ||
} | ||
} else if ((sel = doc.selection) && sel.type != "Control") { | ||
const textRange = sel.createRange(); | ||
const preCaretTextRange = doc.body.createTextRange(); | ||
preCaretTextRange.moveToElementText(element); | ||
preCaretTextRange.setEndPoint("EndToEnd", textRange); | ||
caretOffset = preCaretTextRange.text.length; | ||
/** Keeping a reference of the range to emit and making it compatible */ | ||
caretRange = textRange.duplicate(); | ||
caretRange.insertNode = (e) => { | ||
const container = document.createElement("div"); | ||
container.appendChild(e); | ||
caretRange.pasteHTML(container.innerHTML); | ||
}; | ||
} | ||
return { | ||
caretOffset, | ||
caretRange | ||
}; | ||
setTimeout(() => { | ||
this._caretEvent$.next(cEvent); | ||
}); | ||
} | ||
} |
export * from './emoji-picker.module'; | ||
export * from './lib'; |
export * from './emoji-picker.module'; | ||
export * from './lib'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
[{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./emoji-picker.module"}]},{"__symbolic":"module","version":1,"metadata":{},"exports":[{"from":"./emoji-picker.module"}]}] | ||
[{"__symbolic":"module","version":3,"metadata":{},"exports":[{"from":"./emoji-picker.module"},{"from":"./lib"}]},{"__symbolic":"module","version":1,"metadata":{},"exports":[{"from":"./emoji-picker.module"},{"from":"./lib"}]}] |
export * from './emoji-picker.module'; | ||
export * from './lib'; |
{ | ||
"name": "angular2-emoji-picker", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Emoji picker for angular2+", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -0,1 +1,3 @@ | ||
[![npm version](https://badge.fury.io/js/angular2-emoji-picker.svg)](https://badge.fury.io/js/angular2-emoji-picker) | ||
# Emoji picker for Angular | ||
@@ -10,3 +12,3 @@ | ||
###Usage: | ||
### Usage: | ||
@@ -27,3 +29,3 @@ ``` | ||
###Directive API: | ||
### Directive API: | ||
@@ -34,3 +36,3 @@ ``` | ||
[(emojiPickerIf)]="toggled" | ||
[emojiPickerPosition]="'bottom' || 'top' || 'left' || 'right'" | ||
[emojiPickerDirection]="'bottom' || 'top' || 'left' || 'right'" | ||
(emojiPickerSelect)="handleSelection($event)">😄</i> | ||
@@ -42,11 +44,15 @@ ``` | ||
``` | ||
$event = ["😌", "relieved"] | ||
$event = EmojiEvent{ char : "😌", label : "relieved" } | ||
``` | ||
## EmojiPickerCaretEmitter | ||
added for your convenience, emits information regarding a contenteditable enabled element | ||
### Emitter `(emojiPickerCaretEmitter)="handleCaretChange($event)"` | ||
``` | ||
$event = { caretOffset: 13, caretRange: Range{...} } | ||
$event = CaretEvent{ caretOffset: 13, caretRange: Range{...}, textContent: 'content of div or input' } | ||
``` | ||
Emoji Picker will get placed relative the element chosen via the directive api, centered and within window borders |
{ | ||
"name": "angular2-emoji-picker", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Emoji picker for angular2+", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -0,1 +1,3 @@ | ||
[![npm version](https://badge.fury.io/js/angular2-emoji-picker.svg)](https://badge.fury.io/js/angular2-emoji-picker) | ||
# Emoji picker for Angular | ||
@@ -10,3 +12,3 @@ | ||
###Usage: | ||
### Usage: | ||
@@ -27,3 +29,3 @@ ``` | ||
###Directive API: | ||
### Directive API: | ||
@@ -34,3 +36,3 @@ ``` | ||
[(emojiPickerIf)]="toggled" | ||
[emojiPickerPosition]="'bottom' || 'top' || 'left' || 'right'" | ||
[emojiPickerDirection]="'bottom' || 'top' || 'left' || 'right'" | ||
(emojiPickerSelect)="handleSelection($event)">😄</i> | ||
@@ -42,11 +44,15 @@ ``` | ||
``` | ||
$event = ["😌", "relieved"] | ||
$event = EmojiEvent{ char : "😌", label : "relieved" } | ||
``` | ||
## EmojiPickerCaretEmitter | ||
added for your convenience, emits information regarding a contenteditable enabled element | ||
### Emitter `(emojiPickerCaretEmitter)="handleCaretChange($event)"` | ||
``` | ||
$event = { caretOffset: 13, caretRange: Range{...} } | ||
$event = CaretEvent{ caretOffset: 13, caretRange: Range{...}, textContent: 'content of div or input' } | ||
``` | ||
Emoji Picker will get placed relative the element chosen via the directive api, centered and within window borders |
@@ -18,2 +18,4 @@ import { | ||
import { DIRECTIONS } from '../lib/picker-directions'; | ||
import { Subscription } from "rxjs/Subscription"; | ||
import { EmojiEvent } from "../"; | ||
@@ -50,2 +52,3 @@ @Directive({ | ||
private _emojiPickerRef: ComponentRef<EmojiPickerComponent>; | ||
private _emojiSubs: Subscription[] = []; | ||
@@ -74,4 +77,6 @@ constructor( | ||
this._emojiPickerRef.instance.setPosition(this._el, this._directionCode); | ||
this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(event => this.emojiPickerIfEmitter.emit(false)); | ||
this._emojiPickerRef.instance.selectionEmitter.subscribe(event => this.selectEmitter.emit(event)); | ||
this._emojiSubs.push( | ||
this._emojiPickerRef.instance.pickerCloseEmitter.subscribe(event => this.emojiPickerIfEmitter.emit(false)), | ||
this._emojiPickerRef.instance.selectionEmitter.subscribe(event => this.selectEmitter.emit(EmojiEvent.fromArray(event))) | ||
); | ||
} | ||
@@ -84,3 +89,6 @@ | ||
this._emojiSubs.forEach((subscription: Subscription) => subscription.unsubscribe()); | ||
this._emojiPickerRef.destroy(); | ||
this._emojiSubs = []; | ||
delete this._emojiPickerRef; | ||
@@ -87,0 +95,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { Directive, Output, EventEmitter, ElementRef } from '@angular/core'; | ||
import { Directive, Output, EventEmitter, ElementRef, ChangeDetectorRef, ApplicationRef, NgZone } from '@angular/core'; | ||
import { Subject } from "rxjs/Subject"; | ||
@@ -6,3 +6,5 @@ import 'rxjs/add/operator/takeUntil'; | ||
@Directive({ | ||
import { CaretEvent } from "../../src"; | ||
@Directive({ | ||
selector: '[emojiPickerCaretEmitter]', | ||
@@ -12,12 +14,15 @@ host: { | ||
'(mouseup)': 'updateCaretPosition()', | ||
'(selectstart)': 'updateCaretPosition()', | ||
'(focus)': 'updateCaretPosition()', | ||
'(DOMSubtreeModified)': 'updateCaretPosition($event)' | ||
'(DOMSubtreeModified)': 'updateCaretDueMutation($event)' | ||
} | ||
}) | ||
export class EmojiPickerCaretDirective { | ||
@Output('emojiPickerCaretEmitter') caretEmitter = new EventEmitter(); | ||
@Output('emojiPickerCaretEmitter') caretEmitter = new EventEmitter<CaretEvent>(); | ||
private _position = new Subject<{ caretOffset, caretRange }>(); | ||
private _destroyed = new Subject<boolean>(); | ||
private _caretEvent$ = new Subject<CaretEvent>(); | ||
private _destroyed$ = new Subject<boolean>(); | ||
private _lastCaretEvent: CaretEvent = CaretEvent.generateNullEvent(); | ||
private _win; | ||
@@ -42,85 +47,47 @@ private _doc; | ||
constructor(private _el: ElementRef) { } | ||
ngOnInit() { | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName !== 'INPUT') { | ||
throw new Error('(emojiPickerPositionEmitter) should only work on contenteditable enabled or input elements'); | ||
} | ||
this._position | ||
.takeUntil(this._destroyed) | ||
constructor( | ||
private _el: ElementRef | ||
) { | ||
this._caretEvent$ | ||
.takeUntil(this._destroyed$) | ||
.distinctUntilChanged((event1, event2) => { | ||
if ( | ||
/** if range suddenly exists or disappears */ | ||
!event1.caretRange && event2.caretRange || | ||
event1.caretRange && !event2.caretRange || | ||
/** if caret offset has changed */ | ||
event1.caretOffset !== event2.caretOffset || | ||
/** if caret range has changed in these properties */ | ||
!this.compareRangeObject(event1.caretRange, event2.caretRange) | ||
) { | ||
return false; | ||
} | ||
return true; | ||
return CaretEvent.compare(event1, event2); | ||
}) | ||
.subscribe(event => this.caretEmitter.emit(event)) | ||
.subscribe((event: CaretEvent) => { | ||
this.caretEmitter.emit(event); | ||
this._lastCaretEvent = event.clone() | ||
}) | ||
; | ||
} | ||
compareRangeObject(r1, r2) { | ||
for (let k in r1) { | ||
if (r1[k] !== r2[k]) { | ||
return false | ||
} | ||
ngOnInit() { | ||
if (!this._el.nativeElement.getAttribute('contenteditable') && this._el.nativeElement.tagName.toLowerCase() !== 'input') { | ||
throw new Error('(emojiPickerPositionEmitter) should only work on contenteditable enabled or input elements'); | ||
} | ||
return true; | ||
} | ||
ngOnDestroy() { | ||
this._destroyed.next(true); | ||
this._destroyed$.next(true); | ||
} | ||
updateCaretPosition() { | ||
const position = this.getCaretCharacterOffsetWithin(this.win, this.doc, this._el.nativeElement); | ||
this._position.next(position); | ||
const cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
this._caretEvent$.next(cEvent); | ||
} | ||
getCaretCharacterOffsetWithin(win, doc, element) { | ||
let caretOffset = 0, sel, caretRange; | ||
updateCaretDueMutation() { | ||
const cEvent = CaretEvent.generateCaretEvent(this.win, this.doc, this._el.nativeElement); | ||
let textMovement = cEvent.textContent.length - this._lastCaretEvent.textContent.length; | ||
cEvent.caretOffset = this._lastCaretEvent.caretOffset + textMovement; | ||
if (typeof win.getSelection != "undefined") { | ||
sel = win.getSelection(); | ||
if (sel.rangeCount > 0) { | ||
const range = win.getSelection().getRangeAt(0); | ||
const preCaretRange = range.cloneRange(); | ||
preCaretRange.selectNodeContents(element); | ||
preCaretRange.setEnd(range.endContainer, range.endOffset); | ||
caretOffset = preCaretRange.toString().length; | ||
/** change detection after DOMSubtreeModified event is weird | ||
* ChangeDetectorRef.detectChanges(), ChangeDetectorRef.markForCheck(), ApplicationRef.tick(), NgZone.run() | ||
* all of those methods did not work as expected. | ||
* As a temporary hack I am emitting an event after a short timeout, which is fine due to the _caretEvent$ smart stream | ||
*/ | ||
/** Keeping a reference of the range to emit */ | ||
caretRange = range.cloneRange(); | ||
} | ||
} else if ((sel = doc.selection) && sel.type != "Control") { | ||
const textRange = sel.createRange(); | ||
const preCaretTextRange = doc.body.createTextRange(); | ||
preCaretTextRange.moveToElementText(element); | ||
preCaretTextRange.setEndPoint("EndToEnd", textRange); | ||
caretOffset = preCaretTextRange.text.length; | ||
/** Keeping a reference of the range to emit and making it compatible */ | ||
caretRange = textRange.duplicate(); | ||
caretRange.insertNode = (e) => { | ||
const container = document.createElement("div"); | ||
container.appendChild(e); | ||
caretRange.pasteHTML(container.innerHTML); | ||
}; | ||
} | ||
return { | ||
caretOffset, | ||
caretRange | ||
}; | ||
setTimeout(() => { | ||
this._caretEvent$.next(cEvent); | ||
}); | ||
} | ||
} |
export * from './emoji-picker.module'; | ||
export * from './lib'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
585588
271
15243
55
1