mirror of
https://github.com/flarum/core.git
synced 2025-08-07 08:56:38 +02:00
@@ -3,5 +3,8 @@ var gulp = require('flarum-gulp');
|
|||||||
gulp({
|
gulp({
|
||||||
modules: {
|
modules: {
|
||||||
'flarum/emoji': 'src/**/*.js'
|
'flarum/emoji': 'src/**/*.js'
|
||||||
}
|
},
|
||||||
|
files: [
|
||||||
|
'bower_components/textarea-caret-position/index.js'
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
6
extensions/emoji/js/forum/bower.json
Normal file
6
extensions/emoji/js/forum/bower.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "flarum-emoji",
|
||||||
|
"devDependencies": {
|
||||||
|
"textarea-caret-position": "~3.0.0"
|
||||||
|
}
|
||||||
|
}
|
456
extensions/emoji/js/forum/dist/extension.js
vendored
456
extensions/emoji/js/forum/dist/extension.js
vendored
File diff suppressed because one or more lines are too long
137
extensions/emoji/js/forum/src/addComposerAutocomplete.js
Normal file
137
extensions/emoji/js/forum/src/addComposerAutocomplete.js
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,95 @@
|
|||||||
|
import Component from 'flarum/Component';
|
||||||
|
|
||||||
|
export default class AutocompleteDropdown extends Component {
|
||||||
|
init() {
|
||||||
|
this.active = false;
|
||||||
|
this.index = 0;
|
||||||
|
this.keyWasJustPressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
view() {
|
||||||
|
return (
|
||||||
|
<ul className="Dropdown-menu EmojiDropdown">
|
||||||
|
{this.props.items.map(item => <li>{item}</li>)}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
show(left, top) {
|
||||||
|
this.$().show().css({
|
||||||
|
left: left + 'px',
|
||||||
|
top: top + 'px'
|
||||||
|
});
|
||||||
|
this.active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.$().hide();
|
||||||
|
this.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(e) {
|
||||||
|
if (!this.active) return;
|
||||||
|
|
||||||
|
switch (e.which) {
|
||||||
|
case 40: case 38: // Down/Up
|
||||||
|
this.keyWasJustPressed = true;
|
||||||
|
this.setIndex(this.index + (e.which === 40 ? 1 : -1), true);
|
||||||
|
clearTimeout(this.keyWasJustPressedTimeout);
|
||||||
|
this.keyWasJustPressedTimeout = setTimeout(() => this.keyWasJustPressed = false, 500);
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13: case 9: // Enter/Tab
|
||||||
|
this.$('li').eq(this.index).find('button').click();
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 27: // Escape
|
||||||
|
this.hide();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// no default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIndex(index, scrollToItem) {
|
||||||
|
if (this.keyWasJustPressed && !scrollToItem) return;
|
||||||
|
|
||||||
|
const $dropdown = this.$();
|
||||||
|
const $items = $dropdown.find('li');
|
||||||
|
let rangedIndex = index;
|
||||||
|
|
||||||
|
if (rangedIndex < 0) {
|
||||||
|
rangedIndex = $items.length - 1;
|
||||||
|
} else if (rangedIndex >= $items.length) {
|
||||||
|
rangedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.index = rangedIndex;
|
||||||
|
|
||||||
|
const $item = $items.removeClass('active').eq(rangedIndex).addClass('active');
|
||||||
|
|
||||||
|
if (scrollToItem) {
|
||||||
|
const dropdownScroll = $dropdown.scrollTop();
|
||||||
|
const dropdownTop = $dropdown.offset().top;
|
||||||
|
const dropdownBottom = dropdownTop + $dropdown.outerHeight();
|
||||||
|
const itemTop = $item.offset().top;
|
||||||
|
const itemBottom = itemTop + $item.outerHeight();
|
||||||
|
|
||||||
|
let scrollTop;
|
||||||
|
if (itemTop < dropdownTop) {
|
||||||
|
scrollTop = dropdownScroll - dropdownTop + itemTop - parseInt($dropdown.css('padding-top'), 10);
|
||||||
|
} else if (itemBottom > dropdownBottom) {
|
||||||
|
scrollTop = dropdownScroll - dropdownBottom + itemBottom + parseInt($dropdown.css('padding-bottom'), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof scrollTop !== 'undefined') {
|
||||||
|
$dropdown.stop(true).animate({scrollTop}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,7 +1,11 @@
|
|||||||
/*global twemoji, s9e*/
|
|
||||||
|
|
||||||
import { override } from 'flarum/extend';
|
import { override } from 'flarum/extend';
|
||||||
import app from 'flarum/app';
|
import app from 'flarum/app';
|
||||||
import Post from 'flarum/models/Post';
|
import Post from 'flarum/models/Post';
|
||||||
|
|
||||||
app.initializers.add('flarum-emoji', () => {});
|
import addComposerAutocomplete from 'flarum/emoji/addComposerAutocomplete';
|
||||||
|
|
||||||
|
app.initializers.add('flarum-emoji', () => {
|
||||||
|
// After typing ':' in the composer, show a dropdown suggesting a bunch of
|
||||||
|
// emoji that the user could use.
|
||||||
|
addComposerAutocomplete();
|
||||||
|
});
|
||||||
|
@@ -3,3 +3,38 @@ img.emoji {
|
|||||||
margin: 0 .05em 0 .1em;
|
margin: 0 .05em 0 .1em;
|
||||||
vertical-align: -0.3em;
|
vertical-align: -0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.EmojiDropdown {
|
||||||
|
max-width: 500px;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
position: absolute;
|
||||||
|
margin: 5px 0 !important;
|
||||||
|
|
||||||
|
> li > a {
|
||||||
|
white-space: normal;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li > a:hover {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.PostPreview {
|
||||||
|
color: @text-color;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.PostPreview-content {
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: 1.7em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ComposerBody-emojiWrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user