Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

angular2-emoji-picker

Package Overview
Dependencies
Maintainers
2
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

angular2-emoji-picker - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

lib-dist/lib/caret-event.d.ts

21

CHANGELOG.md

@@ -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)

19

demo/src/app/app.component.ts
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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc