]> git.mxchange.org Git - friendica.git/blobdiff - view/js/autocomplete.js
Merge pull request #9882 from MrPetovan/bug/po2php-plural-conversion
[friendica.git] / view / js / autocomplete.js
index 219ad794bc86a4b18a34626ad4c691bf36a3b18b..d9fcddd7b855e649ec8f298c339b8bf5624eddd6 100644 (file)
@@ -1,5 +1,6 @@
+// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
 /**
- * @brief Friendica people autocomplete
+ * Friendica people autocomplete
  *
  * require jQuery, jquery.textcomplete
  *
@@ -77,6 +78,10 @@ function contact_format(item) {
                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;
@@ -192,6 +197,56 @@ function string2bb(element) {
  * 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
@@ -212,6 +267,23 @@ function string2bb(element) {
                        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,})$/,
@@ -222,14 +294,12 @@ function string2bb(element) {
                };
 
                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 = {
@@ -248,39 +318,24 @@ function string2bb(element) {
                        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;
@@ -295,20 +350,22 @@ function string2bb(element) {
                };
 
                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') {
+               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'];
                        var open_elements = ['*', 'hr'];
 
@@ -343,11 +400,12 @@ function string2bb(element) {
                };
 
                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) {
@@ -356,135 +414,8 @@ function string2bb(element) {
                                }
                        }
                });
+
+               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