discourse/plugins/emoji/assets/javascripts/emoji.js.erb

186 lines
5.9 KiB
Text

(function() {
var emoji = <%= Dir.glob(File.expand_path("../../../public/images/*.png", __FILE__)).map{|f| File.basename(f).split(".")[0]}.inspect %>;
var _extendedEmoji = {};
Discourse.Dialect.registerEmoji = function(code, url) {
_extendedEmoji[code] = url;
};
function urlFor(code) {
var url = _extendedEmoji[code];
if (!url && emoji.indexOf(code) !== -1) {
url = Discourse.getURL('/plugins/emoji/images/' + code + '.png');
}
return url;
}
function imageFor(code) {
var url = urlFor(code);
if (url) {
return ['img', {href: url, title: ':' + code + ':', 'class': 'emoji', alt: code}];
}
}
// Also support default emotions
var translations = {
':)' : 'smile',
':-)' : 'smile',
':(' : 'frowning',
':-(' : 'frowning',
';)' : 'wink',
';-)' : 'wink',
':\'(' : 'cry',
':\'-(' : 'cry',
':-\'(' : 'cry',
':p' : 'stuck_out_tongue',
':P' : 'stuck_out_tongue',
':-P' : 'stuck_out_tongue',
':O' : 'open_mouth',
':-O' : 'open_mouth',
':D' : 'smiley',
':-D' : 'smiley',
':|' : 'expressionless',
':-|' : 'expressionless',
";P" : 'stuck_out_tongue_winking_eye',
";-P" : 'stuck_out_tongue_winking_eye',
';)' : 'wink',
';-)' : 'wink',
":$" : 'blush',
":-$" : 'blush'
};
function checkPrev(prev) {
if (prev && prev.length) {
var lastToken = prev[prev.length-1];
if (lastToken && lastToken.charAt) {
var lastChar = lastToken.charAt(lastToken.length-1);
if (lastChar !== ' ' && lastChar !== "\n") return false;
}
}
return true;
}
var translationsWithColon = {};
Object.keys(translations).forEach(function (t) {
if (t[0] === ':') {
translationsWithColon[t] = translations[t];
} else {
var replacement = translations[t];
Discourse.Dialect.inlineReplace(t, function (token, match, prev) {
if (!Discourse.SiteSettings.enable_emoji) { return token; }
return checkPrev(prev) ? imageFor(replacement) : token;
});
}
});
function escapeRegExp(s) {
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}
var translationColonRegexp = new RegExp(Object.keys(translationsWithColon).map(function (t) {
return "(" + escapeRegExp(t) + ")";
}).join("|"));
Discourse.Dialect.registerInline(':', function(text, match, prev) {
if (!Discourse.SiteSettings.enable_emoji) { return; }
var endPos = text.indexOf(':', 1),
firstSpace = text.search(/\s/),
contents;
if (!checkPrev(prev)) { return; }
// If there is no trailing colon, check our translations that begin with colons
if (endPos === -1 || (firstSpace !== -1 && endPos > firstSpace)) {
translationColonRegexp.lastIndex = 0;
var m = translationColonRegexp.exec(text);
if (m && m[0] && text.indexOf(m[0]) === 0) {
// Check outer edge
var lastChar = text.charAt(m[0].length);
if (lastChar && (lastChar !== ' ' && lastChar !== "\n")) return;
contents = imageFor(translationsWithColon[m[0]]);
if (contents) {
return [m[0].length, contents];
}
}
return;
}
// Simple find and replace from our array
var between = text.slice(1, endPos);
contents = imageFor(between);
if (contents) {
return [endPos+1, contents];
}
});
// TODO: Make this a proper ES6 import
var ComposerView = (Discourse && Discourse.ComposerView) || (typeof require !== "undefined" && require('discourse/views/composer').default);
if (ComposerView) {
ComposerView.on("initWmdEditor", function(event){
if (!Discourse.SiteSettings.enable_emoji) { return; }
var baseUrl = Discourse.getURL("/");
template = Handlebars.compile("<div class='autocomplete'>" +
"<ul>" +
"{{#each options}}" +
"<li>" +
"<a href='#'>" +
"<img src='{{src}}' class='emoji'> " +
"{{code}}</a>" +
"</li>" +
"{{/each}}" +
"</ul>" +
"</div>");
var toSearch = emoji.concat(Object.keys(_extendedEmoji));
$('#wmd-input').autocomplete({
template: template,
key: ":",
transformComplete: function(v){ return v.code + ":"; },
dataSource: function(term){
return new Ember.RSVP.Promise(function(resolve) {
var full = ":" + term;
term = term.toLowerCase();
if (term === "") {
return resolve(["smile", "smiley", "wink", "sunny", "blush"]);
}
if (translations[full]) {
return resolve([translations[full]]);
}
var options = [];
var i;
for (i=0; i < toSearch.length; i++) {
if (toSearch[i].indexOf(term) === 0) {
options.push(toSearch[i]);
if(options.length > 4) { break; }
}
}
if (options.length <= 4) {
for (i=0; i < toSearch.length; i++) {
if (toSearch[i].indexOf(term) > 0) {
options.push(toSearch[i]);
if(options.length > 4) { break; }
}
}
}
return resolve(options);
}).then(function(list) {
return list.map(function(i) {
return {code: i, src: urlFor(i)};
});
});
}
});
});
}
Discourse.Markdown.whiteListTag('img', 'class', 'emoji');
}).call(this);