changeset 7467:2e7ffb755d4f

front-end: use At.js for MentionsAutoComplete We want to get rid of YUI, and select2 is not well suited for this purpose. So use At.js, which is made just for this use case. Original implementation was modified by Mads Kiilerich.
author domruf <dominikruf@gmail.com>
date Mon, 10 Dec 2018 22:54:04 +0100
parents bf514091b27f
children 1f3b311e865f
files .hgignore LICENSE.md kallithea/bin/kallithea_cli_front_end.py kallithea/front-end/package.json kallithea/public/js/base.js kallithea/public/less/main.less kallithea/public/less/style.less kallithea/templates/base/root.html
diffstat 8 files changed, 73 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Dec 10 23:32:39 2018 +0100
+++ b/.hgignore	Mon Dec 10 22:54:04 2018 +0100
@@ -32,6 +32,8 @@
 ^kallithea/public/css/style\.css\.map$
 ^kallithea/public/js/bootstrap\.js$
 ^kallithea/public/js/dataTables\.bootstrap\.js$
+^kallithea/public/js/jquery\.atwho\.min\.js$
+^kallithea/public/js/jquery\.caret\.min\.js$
 ^kallithea/public/js/jquery\.dataTables\.js$
 ^kallithea/public/js/jquery\.flot\.js$
 ^kallithea/public/js/jquery\.flot\.selection\.js$
--- a/LICENSE.md	Mon Dec 10 23:32:39 2018 +0100
+++ b/LICENSE.md	Mon Dec 10 22:54:04 2018 +0100
@@ -84,6 +84,38 @@
 
 
 
+At.js
+-----
+
+Kallithea uses the Javascript system called
+[At.js](http://ichord.github.com/At.js),
+which can be found together with its Corresponding Source in
+https://github.com/ichord/At.js at tag v1.5.4.
+
+It is Copyright 2013 chord.luo@gmail.com and is under an
+[MIT-permissive license](MIT-Permissive-License.txt).
+
+It is not distributed with Kallithea, but will be downloaded
+using the ''kallithea-cli front-end-build'' command.
+
+
+
+Caret.js
+--------
+
+Kallithea uses the Javascript system called
+[Caret.js](http://ichord.github.com/Caret.js/),
+which can be found together with its Corresponding Source in
+https://github.com/ichord/Caret.js at tag v0.3.1.
+
+It is Copyright 2013 chord.luo@gmail.com and is under an
+[MIT-permissive license](MIT-Permissive-License.txt).
+
+It is not distributed with Kallithea, but will be downloaded
+using the ''kallithea-cli front-end-build'' command.
+
+
+
 DataTables
 ----------
 
--- a/kallithea/bin/kallithea_cli_front_end.py	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/bin/kallithea_cli_front_end.py	Mon Dec 10 22:54:04 2018 +0100
@@ -66,11 +66,13 @@
         click.echo("Preparing Bootstrap JS")
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'bootstrap', 'dist', 'js', 'bootstrap.js'), os.path.join(public_dir, 'js', 'bootstrap.js'))
 
-        click.echo("Preparing jQuery JS with Flot")
+        click.echo("Preparing jQuery JS with Flot, Caret and Atwho")
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'jquery', 'dist', 'jquery.min.js'), os.path.join(public_dir, 'js', 'jquery.min.js'))
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'jquery.flot', 'jquery.flot.js'), os.path.join(public_dir, 'js', 'jquery.flot.js'))
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'jquery.flot', 'jquery.flot.selection.js'), os.path.join(public_dir, 'js', 'jquery.flot.selection.js'))
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'jquery.flot', 'jquery.flot.time.js'), os.path.join(public_dir, 'js', 'jquery.flot.time.js'))
+        shutil.copy(os.path.join(front_end_dir, 'node_modules', 'jquery.caret', 'dist', 'jquery.caret.min.js'), os.path.join(public_dir, 'js', 'jquery.caret.min.js'))
+        shutil.copy(os.path.join(front_end_dir, 'node_modules', 'at.js', 'dist', 'js', 'jquery.atwho.min.js'), os.path.join(public_dir, 'js', 'jquery.atwho.min.js'))
 
         click.echo("Preparing DataTables JS")
         shutil.copy(os.path.join(front_end_dir, 'node_modules', 'datatables.net', 'js', 'jquery.dataTables.js'), os.path.join(public_dir, 'js', 'jquery.dataTables.js'))
--- a/kallithea/front-end/package.json	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/front-end/package.json	Mon Dec 10 22:54:04 2018 +0100
@@ -2,11 +2,13 @@
   "name": "kallithea",
   "private": true,
   "dependencies": {
+    "at.js": "1.5.4",
     "bootstrap": "3.3.7",
     "codemirror": "4.7",
     "datatables.net": "1.10.13",
     "datatables.net-bs": "1.10.13",
     "jquery": "1.12.3",
+    "jquery.caret": "0.3.1",
     "jquery.flot": "0.8.3",
     "select2": "3.5.1",
     "select2-bootstrap-css": "1.2.4"
--- a/kallithea/public/js/base.js	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/public/js/base.js	Mon Dec 10 22:54:04 2018 +0100
@@ -751,7 +751,7 @@
 
     tooltip_activate();
     if ($textarea.length > 0) {
-        MentionsAutoComplete($textarea, _USERS_AC_DATA);
+        MentionsAutoComplete($textarea);
     }
     if (f_path) {
         $textarea.focus();
@@ -1155,65 +1155,30 @@
     });
 }
 
-var MentionsAutoComplete = function ($inputElement, users_list) {
-    var $container = $('<div/>').insertAfter($inputElement);
-
-    var matchUsers = function (sQuery) {
-            // use the search string from $inputElement instead of sQuery
-            if(!$container.data('search')){
-                // return empty list so the input list isn't shown
-                return []
-            }
-            return autocompleteMatchUsers($container.data('search'), users_list);
-    }
-
-    var datasource = new YAHOO.util.FunctionDataSource(matchUsers);
-    var mentionsAC = new YAHOO.widget.AutoComplete($inputElement[0], $container[0], datasource);
-    mentionsAC.useShadow = false;
-    mentionsAC.resultTypeList = false;
-    mentionsAC.animVert = false;
-    mentionsAC.animHoriz = false;
-    mentionsAC.animSpeed = 0.1;
-    mentionsAC.suppressInputUpdate = true;
-    mentionsAC.formatResult = function (oResultData, sQuery, sResultMatch) {
-        // use the search string from $inputElement instead of sQuery
-        return autocompleteFormatter(oResultData, $container.data('search'), sResultMatch);
-    }
-
-    // Handler for selection of an entry
-    if(mentionsAC.itemSelectEvent){
-        mentionsAC.itemSelectEvent.subscribe(function (sType, aArgs) {
-            var myAC = aArgs[0]; // reference back to the AC instance
-            var elLI = aArgs[1]; // reference to the selected LI element
-            var oData = aArgs[2]; // object literal of selected item's result data
-            myAC.getInputEl().value = $container.data('before') + oData.nname + ' ' + $container.data('after');
-            _setCaretPosition($(myAC.getInputEl()), myAC.dataSource.before.length + oData.nname.length + 1);
-        });
-    }
-
-    // Must match utils2.py MENTIONS_REGEX.
-    // Operates on a string from char before @ up to cursor.
-    // Check that the char before @ doesn't look like an email address, and match to end of string.
-    var mentionRe = new RegExp('(?:^|[^a-zA-Z0-9])@([a-zA-Z0-9][-_.a-zA-Z0-9]*[a-zA-Z0-9])$');
-
-    $inputElement.keyup(function(e){
-            var currentMessage = $inputElement.val();
-            var currentCaretPosition = $inputElement[0].selectionStart;
-
-            $container.data('search', '');
-            var messageBeforeCaret = currentMessage.substr(0, currentCaretPosition);
-            var lastAtPos = messageBeforeCaret.lastIndexOf('@');
-            if(lastAtPos >= 0){
-                // Search from one char before last @ ... if possible
-                var m = mentionRe.exec(messageBeforeCaret.substr(Math.max(0, lastAtPos - 1)));
-                if(m){
-                    $container.data('before', currentMessage.substr(0, lastAtPos + 1));
-                    $container.data('search', currentMessage.substr(lastAtPos + 1, currentCaretPosition - lastAtPos - 1));
-                    $container.data('after', currentMessage.substr(currentCaretPosition));
-                }
-            }
-        });
-}
+var MentionsAutoComplete = function ($inputElement) {
+  $inputElement.atwho({
+    at: "@",
+    callbacks: {
+      remoteFilter: function(query, callback) {
+        $.getJSON(
+          pyroutes.url('users_and_groups_data'),
+          {
+            query: query,
+            types: 'users'
+          },
+          function(data) {
+            callback(data.results)
+          }
+        );
+      },
+      sorter: function(query, items, searchKey) {
+        return items;
+      }
+    },
+    displayTpl: "<li>" + autocompleteGravatar('${fname} ${lname} (${nname})', '${gravatar_lnk}', 16) + "</li>",
+    insertTpl: "${atwho-at}${nname}"
+  });
+};
 
 
 // Set caret at the given position in the input element
--- a/kallithea/public/less/main.less	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/public/less/main.less	Mon Dec 10 22:54:04 2018 +0100
@@ -11,6 +11,7 @@
 /* 3rd party styles */
 @import "node_modules/bootstrap/less/bootstrap.less";
 @import (inline) "node_modules/datatables.net-bs/css/dataTables.bootstrap.css";
+@import (inline) "node_modules/at.js/dist/css/jquery.atwho.css";
 @import (less) "node_modules/select2/select2.css";
 @import (less) "node_modules/select2-bootstrap-css/select2-bootstrap.css";
 @import (less) "tmp/pygments.css";
--- a/kallithea/public/less/style.less	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/public/less/style.less	Mon Dec 10 22:54:04 2018 +0100
@@ -929,3 +929,9 @@
 #context-pages > ul > li > a {
   height: @navbar-height;
 }
+
+/* at.js */
+.atwho-view strong {
+  /* the blue color doesn't look good, use normal color */
+  color: inherit;
+}
--- a/kallithea/templates/base/root.html	Mon Dec 10 23:32:39 2018 +0100
+++ b/kallithea/templates/base/root.html	Mon Dec 10 22:54:04 2018 +0100
@@ -74,6 +74,8 @@
         <script type="text/javascript" src="${h.url('/js/bootstrap.js', ver=c.kallithea_version)}"></script>
         <script type="text/javascript" src="${h.url('/js/select2.js', ver=c.kallithea_version)}"></script>
         <script type="text/javascript" src="${h.url('/js/native.history.js', ver=c.kallithea_version)}"></script>
+        <script type="text/javascript" src="${h.url('/js/jquery.caret.min.js', ver=c.kallithea_version)}"></script>
+        <script type="text/javascript" src="${h.url('/js/jquery.atwho.min.js', ver=c.kallithea_version)}"></script>
         <script type="text/javascript" src="${h.url('/js/base.js', ver=c.kallithea_version)}"></script>
         ## EXTRA FOR JS
         <%block name="js_extra"/>