').addClass('emoji-wysiwyg-editor').addClass($($textarea)[0].className);
this.$editor.data('self', this);
if ($textarea.attr('maxlength')) {
this.$editor.attr('maxlength', $textarea.attr('maxlength'));
}
this.$editor.height($textarea.outerHeight()); //auto adjust height
this.emojiPopup.appendUnicodeAsImageToElement(this.$editor, $textarea.val());
this.$editor.attr({
'data-id': id,
'data-type': 'input',
'placeholder': $textarea.attr('placeholder'),
'contenteditable': 'true',
});
/*
* ! MODIFICATION START Following code was modified by Igor Zhukov, in
* order to improve rich text paste
*/
var changeEvents = 'blur change';
if (!this.options.norealTime) {
changeEvents += ' keyup';
}
this.$editor.on(changeEvents, function(e) {
return self.onChange.apply(self, [ e ]);
});
/* ! MODIFICATION END */
this.$editor.on('mousedown focus', function() {
document.execCommand('enableObjectResizing', false, false);
});
this.$editor.on('blur', function() {
document.execCommand('enableObjectResizing', true, true);
});
var editorDiv = this.$editor;
this.$editor.on("change keydown keyup resize scroll", function(e) {
if(MAX_LENGTH_ALLOWED_KEYS.indexOf(e.which) == -1 &&
!((e.ctrlKey || e.metaKey) && e.which == 65) && // Ctrl + A
!((e.ctrlKey || e.metaKey) && e.which == 67) && // Ctrl + C
editorDiv.text().length + editorDiv.find('img').length >= editorDiv.attr('maxlength'))
{
e.preventDefault();
}
self.updateBodyPadding(editorDiv);
});
this.$editor.on("paste", function (e) {
e.preventDefault();
var content;
var charsRemaining = editorDiv.attr('maxlength') - (editorDiv.text().length + editorDiv.find('img').length);
if ((e.originalEvent || e).clipboardData) {
content = (e.originalEvent || e).clipboardData.getData('text/plain');
if (self.options.onPaste) {
content = self.options.onPaste(content);
}
if (charsRemaining < content.length) {
content = content.substring(0, charsRemaining);
}
document.execCommand('insertText', false, content);
}
else if (window.clipboardData) {
content = window.clipboardData.getData('Text');
if (self.options.onPaste) {
content = self.options.onPaste(content);
}
if (charsRemaining < content.length) {
content = content.substring(0, charsRemaining);
}
document.selection.createRange().pasteHTML(content);
}
editorDiv.scrollTop(editorDiv[0].scrollHeight);
});
$textarea.after("");
$textarea.hide().after(this.$editor);
this.setup();
/*
* MODIFICATION: Following line was modified by Igor Zhukov, in order to
* improve emoji insert behaviour
*/
$(document.body).on('mousedown', function() {
if (self.hasFocus) {
self.selection = util.saveSelection();
}
});
};
EmojiArea_WYSIWYG.prototype.updateBodyPadding = function(target) {
var emojiPicker = $('[data-id=' + this.id + '][data-type=picker]');
if ($(target).hasScrollbar()) {
if (!(emojiPicker.hasClass('parent-has-scroll')))
emojiPicker.addClass('parent-has-scroll');
if (!($(target).hasClass('parent-has-scroll')))
$(target).addClass('parent-has-scroll');
} else {
if ((emojiPicker.hasClass('parent-has-scroll')))
emojiPicker.removeClass('parent-has-scroll');
if (($(target).hasClass('parent-has-scroll')))
$(target).removeClass('parent-has-scroll');
}
};
EmojiArea_WYSIWYG.prototype.onChange = function(e) {
var event = new CustomEvent('input', { bubbles: true });
this.$textarea.val(this.val())[0].dispatchEvent(event);
};
EmojiArea_WYSIWYG.prototype.insert = function(emoji) {
var content;
/*
* MODIFICATION: Following line was modified by Andre Staltz, to use new
* implementation of createIcon function.
*/
var insertionContent = '';
if (this.options.inputMethod == 'unicode') {
insertionContent = this.emojiPopup.colonToUnicode(emoji);
} else {
var $img = $(EmojiArea.createIcon($.emojiarea.icons[emoji]));
if ($img[0].attachEvent) {
$img[0].attachEvent('onresizestart', function(e) {
e.returnValue = false;
}, false);
}
insertionContent = $img[0];
}
this.$editor.trigger('focus');
if (this.selection) {
util.restoreSelection(this.selection);
}
try {
util.replaceSelection(insertionContent);
} catch (e) {
}
/*
* MODIFICATION: Following line was added by Igor Zhukov, in order to
* save recent emojis
*/
util.emojiInserted(emoji, this.menu);
this.onChange();
};
EmojiArea_WYSIWYG.prototype.val = function() {
var lines = [];
var line = [];
var emojiPopup = this.emojiPopup;
var flush = function() {
lines.push(line.join(''));
line = [];
};
var sanitizeNode = function(node) {
if (node.nodeType === TEXT_NODE) {
line.push(node.nodeValue);
} else if (node.nodeType === ELEMENT_NODE) {
var tagName = node.tagName.toLowerCase();
var isBlock = TAGS_BLOCK.indexOf(tagName) !== -1;
if (isBlock && line.length)
flush();
if (tagName === 'img') {
var alt = node.getAttribute('alt') || '';
if (alt) {
line.push(alt);
}
return;
} else if (tagName === 'br') {
flush();
}
var children = node.childNodes;
for (var i = 0; i < children.length; i++) {
sanitizeNode(children[i]);
}
if (isBlock && line.length)
flush();
}
};
var children = this.$editor[0].childNodes;
for (var i = 0; i < children.length; i++) {
sanitizeNode(children[i]);
}
if (line.length)
flush();
var returnValue = lines.join('\n');
return emojiPopup.colonToUnicode(returnValue);
};
util.extend(EmojiArea_WYSIWYG.prototype, EmojiArea.prototype);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
jQuery.fn.hasScrollbar = function() {
var scrollHeight = this.get(0).scrollHeight;
//safari's scrollHeight includes padding
//if ($.browser.safari)
// scrollHeight -= parseInt(this.css('padding-top')) + parseInt(this.css('padding-bottom'));
if (this.outerHeight() < scrollHeight)
return true;
else
return false;
}
/**
* Emoji Dropdown Menu
*
* @constructor
* @param {object}
* emojiarea
*/
var EmojiMenu = function(emojiarea) {
var self = this;
self.id = emojiarea.id;
var $body = $(document.body);
var $window = $(window);
this.visible = false;
this.emojiarea = emojiarea;
EmojiMenu.menuZIndex = 5000;
this.$menu = $('
');
this.$menu.addClass('emoji-menu');
this.$menu.attr('data-id', self.id);
this.$menu.attr('data-type', 'menu');
this.$menu.hide();
this.$itemsTailWrap = $('
')
.appendTo(this.$menu);
this.$categoryTabs = $(
'').appendTo(this.$itemsTailWrap);
this.$itemsWrap = $(
'
')
.appendTo(this.$itemsTailWrap);
this.$items = $('
').appendTo(
this.$itemsWrap);
this.emojiarea.$editor.after(this.$menu)
$body.on('keydown', function(e) {
if (e.keyCode === KEY_ESC || e.keyCode === KEY_TAB) {
self.hide();
}
});
/*
* ! MODIFICATION: Following 3 lines were added by Igor Zhukov, in order
* to hide menu on message submit with keyboard
*/
$body.on('message_send', function(e) {
self.hide();
});
$body.on('mouseup', function(e) {
e = e.originalEvent || e;
var target = e.target || window;
if ($(target).hasClass(self.emojiarea.$dontHideOnClick)) {
return;
}
while (target && target != window) {
target = target.parentNode;
if (target == self.$menu[0] || self.emojiarea
&& target == self.emojiarea.$button[0]) {
return;
}
}
self.hide();
});
this.$menu.on('mouseup', 'a', function(e) {
e.stopPropagation();
return false;
});
this.$menu.on('click', 'a', function(e) {
self.emojiarea.updateBodyPadding(self.emojiarea.$editor);
if ($(this).hasClass('emoji-menu-tab')) {
if (self.getTabIndex(this) !== self.currentCategory) {
self.selectCategory(self.getTabIndex(this));
}
return false;
}
var emoji = $('.label', $(this)).text();
window.setTimeout(function() {
self.onItemSelected(emoji);
if (e.ctrlKey || e.metaKey) {
self.hide();
}
}, 0);
e.stopPropagation();
return false;
});
this.selectCategory(0);
};
/*
* ! MODIFICATION START Following code was added by Andre Staltz, to
* implement category selection.
*/
EmojiMenu.prototype.getTabIndex = function(tab) {
return this.$categoryTabs.find('.emoji-menu-tab').index(tab);
};
EmojiMenu.prototype.selectCategory = function(category) {
var self = this;
this.$categoryTabs.find('.emoji-menu-tab').each(function(index) {
if (index === category) {
this.className += '-selected';
} else {
this.className = this.className.replace('-selected', '');
}
});
this.currentCategory = category;
this.load(category);
};
/* ! MODIFICATION END */
EmojiMenu.prototype.onItemSelected = function(emoji) {
if(this.emojiarea.$editor.text().length + this.emojiarea.$editor.find('img').length >= this.emojiarea.$editor.attr('maxlength'))
{
return;
}
this.emojiarea.insert(emoji);
};
/*
* MODIFICATION: The following function argument was modified by Andre
* Staltz, in order to load only icons from a category. Also function was
* modified by Igor Zhukov in order to display recent emojis from
* localStorage
*/
EmojiMenu.prototype.load = function(category) {
var html = [];
var options = $.emojiarea.icons;
var path = $.emojiarea.assetsPath;
var self = this;
if (path.length && path.charAt(path.length - 1) !== '/') {
path += '/';
}
/*
* ! MODIFICATION: Following function was added by Igor Zhukov, in order
* to add scrollbars to EmojiMenu
*/
var updateItems = function() {
self.$items.html(html.join(''));
}
if (category > 0) {
for ( var key in options) {
/*
* MODIFICATION: The following 2 lines were modified by Andre
* Staltz, in order to load only icons from the specified
* category.
*/
if (options.hasOwnProperty(key)
&& options[key][0] === (category - 1)) {
html.push('
'
+ EmojiArea.createIcon(options[key], true)
+ '' + util.htmlEntities(key)
+ '');
}
}
updateItems();
} else {
ConfigStorage.get('emojis_recent', function(curEmojis) {
curEmojis = curEmojis || defaultRecentEmojis || [];
var key, i;
for (i = 0; i < curEmojis.length; i++) {
key = curEmojis[i]
if (options[key]) {
html.push('
'
+ EmojiArea.createIcon(options[key], true)
+ ''
+ util.htmlEntities(key) + '');
}
}
updateItems();
});
}
};
EmojiMenu.prototype.hide = function(callback) {
this.visible = false;
this.$menu.hide("fast");
};
EmojiMenu.prototype.show = function(emojiarea) {
/*
* MODIFICATION: Following line was modified by Igor Zhukov, in order to
* improve EmojiMenu behaviour
*/
if (this.visible)
return this.hide();
$(this.$menu).css('z-index', ++EmojiMenu.menuZIndex);
this.$menu.show("fast");
/*
* MODIFICATION: Following 3 lines were added by Igor Zhukov, in order
* to update EmojiMenu contents
*/
if (!this.currentCategory) {
this.load(0);
}
this.visible = true;
};
})(jQuery, window, document);