+// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
/**
- * @brief Friendica people autocomplete
+ * Friendica people autocomplete
*
* require jQuery, jquery.textcomplete
*
return "<div>" + item.text + "</div>";
}
+function tag_format(item) {
+ return "<div class='dropdown-item'>" + '#' + item.text + "</div>";
+}
+
function editor_replace(item) {
if (typeof item.replace !== 'undefined') {
return '$1$2' + item.replace;
* jQuery plugin 'editor_autocomplete'
*/
(function( $ ) {
+ let textcompleteObjects = [];
+
+ // jQuery wrapper for yuku/old-textcomplete
+ // uses a local object directory to avoid recreating Textcomplete objects
+ $.fn.textcomplete = function (strategies, options) {
+ return this.each(function () {
+ let $this = $(this);
+ if (!($this.data('textcompleteId') in textcompleteObjects)) {
+ let editor = new Textcomplete.editors.Textarea($this.get(0));
+
+ $this.data('textcompleteId', textcompleteObjects.length);
+ textcompleteObjects.push(new Textcomplete(editor, options));
+ }
+
+ textcompleteObjects[$this.data('textcompleteId')].register(strategies);
+ });
+ };
+
+ /**
+ * This function should be called immediately after $.textcomplete() to prevent the escape key press to propagate
+ * after the autocompletion dropdown has closed.
+ * This avoids the input textarea to lose focus, the modal window to close, etc... when the expected behavior is
+ * to just close the autocomplete dropdown.
+ *
+ * The custom event listener name allows removing this specific event listener, the "real" event this listens to
+ * is the part before the first dot.
+ *
+ * @returns {*}
+ */
+ $.fn.fixTextcompleteEscape = function () {
+ if (this.data('textcompleteEscapeFixed')) {
+ return this;
+ }
+
+ this.data('textcompleteEscapeFixed', true);
+
+ return this.on({
+ 'textComplete:show': function (e) {
+ $(this).on('keydown.friendica.escape', function (e) {
+ if (e.key === 'Escape') {
+ e.stopPropagation();
+ }
+ });
+ },
+ 'textComplete:hide': function (e) {
+ $(this).off('keydown.friendica.escape');
+ },
+ });
+ }
+
$.fn.editor_autocomplete = function(backend_url) {
// Autocomplete contacts
template: contact_format,
};
+ // Autocomplete hashtags
+ tags = {
+ match: /(^|\s)(\#)([^ \n]{2,})$/,
+ index: 3,
+ search: function(term, callback) {
+ $.getJSON(baseurl + '/hashtag/' + '?t=' + term)
+ .done(function(data) {
+ callback($.map(data, function(entry) {
+ // .toLowerCase() enables case-insensitive search
+ return entry.text.toLowerCase().indexOf(term.toLowerCase()) === 0 ? entry : null;
+ }));
+ });
+ },
+ replace: function(item) { return "$1$2" + item.text + ' '; },
+ template: tag_format
+ };
+
// Autocomplete smilies e.g. ":like"
smilies = {
match: /(^|\s)(:[a-z]{2,})$/,
};
this.attr('autocomplete','off');
- this.textcomplete([contacts, forums, smilies], {className:'acpopup', zIndex:10000});
+ this.textcomplete([contacts, forums, smilies, tags], {dropdown: {className:'acpopup'}});
+ this.fixTextcompleteEscape();
+
+ return this;
};
-})( jQuery );
-/**
- * jQuery plugin 'search_autocomplete'
- */
-(function( $ ) {
$.fn.search_autocomplete = function(backend_url) {
// Autocomplete contacts
contacts = {
replace: webbie_replace,
template: contact_format,
};
- this.attr('autocomplete', 'off');
- var a = this.textcomplete([contacts, community], {className:'acpopup', maxCount:100, zIndex: 10000, appendTo:'nav'});
- a.on('textComplete:select', function(e, value, strategy) { submit_form(this); });
- };
-})( jQuery );
-
-(function( $ ) {
- $.fn.contact_autocomplete = function(backend_url, typ, autosubmit, onselect) {
- if(typeof typ === 'undefined') typ = '';
- if(typeof autosubmit === 'undefined') autosubmit = false;
- // Autocomplete contacts
- contacts = {
- match: /(^)([^\n]+)$/,
- index: 2,
- search: function(term, callback) { contact_search(term, callback, backend_url, typ); },
- replace: basic_replace,
- template: contact_format,
+ // Autocomplete hashtags
+ tags = {
+ match: /(^|\s)(\#)([^ \n]{2,})$/,
+ index: 3,
+ search: function(term, callback) { $.getJSON(baseurl + '/hashtag/' + '?t=' + term).done(function(data) { callback($.map(data, function(entry) { return entry.text.indexOf(term) === 0 ? entry : null; })); }); },
+ replace: function(item) { return "$1$2" + item.text; },
+ template: tag_format
};
- this.attr('autocomplete','off');
- var a = this.textcomplete([contacts], {className:'acpopup', zIndex:10000});
-
- if(autosubmit)
- a.on('textComplete:select', function(e,value,strategy) { submit_form(this); });
+ this.attr('autocomplete', 'off');
+ this.textcomplete([contacts, community, tags], {dropdown: {className:'acpopup', maxCount:100}});
+ this.fixTextcompleteEscape();
+ this.on('textComplete:select', function(e, value, strategy) { submit_form(this); });
- if(typeof onselect !== 'undefined')
- a.on('textComplete:select', function(e, value, strategy) { onselect(value); });
+ return this;
};
-})( jQuery );
-
-(function( $ ) {
$.fn.name_autocomplete = function(backend_url, typ, autosubmit, onselect) {
if(typeof typ === 'undefined') typ = '';
if(typeof autosubmit === 'undefined') autosubmit = false;
};
this.attr('autocomplete','off');
- var a = this.textcomplete([names], {className:'acpopup', zIndex:10000});
+ this.textcomplete([names], {dropdown: {className:'acpopup'}});
+ this.fixTextcompleteEscape();
- if(autosubmit)
- a.on('textComplete:select', function(e,value,strategy) { submit_form(this); });
+ if(autosubmit) {
+ this.on('textComplete:select', function(e,value,strategy) { submit_form(this); });
+ }
- if(typeof onselect !== 'undefined')
- a.on('textComplete:select', function(e, value, strategy) { onselect(value); });
+ if(typeof onselect !== 'undefined') {
+ this.on('textComplete:select', function(e, value, strategy) { onselect(value); });
+ }
+
+ return this;
};
-})( jQuery );
-(function( $ ) {
$.fn.bbco_autocomplete = function(type) {
-
- if(type=='bbcode') {
- var open_close_elements = ['bold', 'italic', 'underline', 'overline', 'strike', 'quote', 'code', 'spoiler', 'map', 'img', 'url', 'audio', 'video', 'embed', 'youtube', 'vimeo', 'list', 'ul', 'ol', 'li', 'table', 'tr', 'th', 'td', 'center', 'color', 'font', 'size', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'nobb', 'noparse', 'pre', 'abstract'];
+ if (type === 'bbcode') {
+ var open_close_elements = ['bold', 'italic', 'underline', 'overline', 'strike', 'quote', 'code', 'spoiler', 'map', 'img', 'url', 'audio', 'video', 'embed', 'youtube', 'vimeo', 'list', 'ul', 'ol', 'li', 'table', 'tr', 'th', 'td', 'center', 'color', 'font', 'size', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'nobb', 'noparse', 'pre', 'abstract', 'share'];
var open_elements = ['*', 'hr'];
var elements = open_close_elements.concat(open_elements);
};
this.attr('autocomplete','off');
- var a = this.textcomplete([bbco], {className:'acpopup', zIndex:10000});
+ this.textcomplete([bbco], {dropdown: {className:'acpopup'}});
+ this.fixTextcompleteEscape();
- a.on('textComplete:select', function(e, value, strategy) { value; });
+ this.on('textComplete:select', function(e, value, strategy) { value; });
- a.keypress(function(e){
+ this.keypress(function(e){
if (e.keyCode == 13) {
var x = listNewLineAutocomplete(this.id);
if(x) {
}
}
});
+
+ return this;
};
})( jQuery );
-
-/**
- * Friendica people autocomplete legacy code
- *
- * require jQuery, jquery.textareas
- */
-function ACPopup(elm, backend_url){
- this.idsel = -1;
- this.element = elm;
- this.searchText = '';
- this.ready = true;
- this.kp_timer = false;
- this.url = backend_url;
-
- this.conversation_id = null;
- var conv_id = this.element.id.match(/\d+$/);
- if (conv_id) {
- this.conversation_id = conv_id[0];
- }
-
- var w = $(elm).width();
- var h = $(elm).height();
-
- var style = $(elm).offset();
- style.top = style.top + h;
- style.width = w;
- style.position = 'absolute';
- style.display = 'none';
-
- this.cont = $('<div class="acpopup-mce"></div>');
- this.cont.css(style);
-
- $('body').append(this.cont);
-}
-
-ACPopup.prototype.close = function(){
- $(this.cont).remove();
- this.ready=false;
-}
-ACPopup.prototype.search = function(text){
- var that = this;
- this.searchText=text;
- if (this.kp_timer) clearTimeout(this.kp_timer);
- this.kp_timer = setTimeout( function(){that._search();}, 500);
-}
-
-ACPopup.prototype._search = function(){
- console.log("_search");
- var that = this;
- var postdata = {
- start:0,
- count:100,
- search:this.searchText,
- type:'c',
- conversation: this.conversation_id,
- }
-
- $.ajax({
- type:'POST',
- url: this.url,
- data: postdata,
- dataType: 'json',
- success:function(data){
- that.cont.html("");
- if (data.tot>0){
- that.cont.show();
- $(data.items).each(function(){
- var html = "<img src='{0}' height='16px' width='16px'>{1} ({2})".format(this.photo, this.name, this.nick);
- var nick = this.nick.replace(' ','');
- if (this.id!=='') nick += '+' + this.id;
- that.add(html, nick + ' - ' + this.link);
- });
- } else {
- that.cont.hide();
- }
- }
- });
-
-}
-
-ACPopup.prototype.add = function(label, value){
- var that = this;
- var elm = $('<div class="acpopupitem" title="' + value + '">' + label + '</div>');
- elm.click(function(e){
- t = $(this).attr('title').replace(new RegExp(' \- .*'), '');
- el = $(that.element);
- sel = el.getSelection();
- sel.start = sel.start - that.searchText.length;
- el.setSelection(sel.start, sel.end).replaceSelectedText(t + ' ').collapseSelection(false);
- that.close();
- });
- $(this.cont).append(elm);
-}
-
-ACPopup.prototype.onkey = function(event){
- if (event.keyCode == '13') {
- if(this.idsel > -1) {
- this.cont.children()[this.idsel].click();
- event.preventDefault();
- } else {
- this.close();
- }
- }
- if (event.keyCode == '38') { //cursor up
- var cmax = this.cont.children().size() - 1;
- this.idsel--;
- if (this.idsel < 0) {
- this.idsel = cmax;
- }
- event.preventDefault();
- }
- if (event.keyCode == '40' || event.keyCode == '9') { //cursor down
- var cmax = this.cont.children().size() - 1;
- this.idsel++;
- if (this.idsel > cmax) {
- this.idsel = 0;
- }
- event.preventDefault();
- }
-
- if (event.keyCode == '38' || event.keyCode == '40' || event.keyCode == '9') {
- this.cont.children().removeClass('selected');
- $(this.cont.children()[this.idsel]).addClass('selected');
- }
-
- if (event.keyCode == '27') { //ESC
- this.close();
- }
-}
-
+// @license-end