# HG changeset patch # User domruf # Date 2018-12-10 21:54:04 # Node ID 2e7ffb755d4f3429656c048e6f5b46908c2ee734 # Parent bf514091b27fd24a25bbacd6f093ce0b2b25ce5d 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. diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -32,6 +32,8 @@ syntax: regexp ^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$ diff --git a/LICENSE.md b/LICENSE.md --- a/LICENSE.md +++ b/LICENSE.md @@ -84,6 +84,38 @@ using the ''kallithea-cli front-end-buil +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 ---------- diff --git a/kallithea/bin/kallithea_cli_front_end.py b/kallithea/bin/kallithea_cli_front_end.py --- a/kallithea/bin/kallithea_cli_front_end.py +++ b/kallithea/bin/kallithea_cli_front_end.py @@ -66,11 +66,13 @@ def front_end_build(install_deps, genera 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')) diff --git a/kallithea/front-end/package.json b/kallithea/front-end/package.json --- a/kallithea/front-end/package.json +++ b/kallithea/front-end/package.json @@ -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" diff --git a/kallithea/public/js/base.js b/kallithea/public/js/base.js --- a/kallithea/public/js/base.js +++ b/kallithea/public/js/base.js @@ -751,7 +751,7 @@ function _comment_div_append_form($comme tooltip_activate(); if ($textarea.length > 0) { - MentionsAutoComplete($textarea, _USERS_AC_DATA); + MentionsAutoComplete($textarea); } if (f_path) { $textarea.focus(); @@ -1155,65 +1155,30 @@ var MembersAutoComplete = function ($inp }); } -var MentionsAutoComplete = function ($inputElement, users_list) { - var $container = $('
').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: "
  • " + autocompleteGravatar('${fname} ${lname} (${nname})', '${gravatar_lnk}', 16) + "
  • ", + insertTpl: "${atwho-at}${nname}" + }); +}; // Set caret at the given position in the input element diff --git a/kallithea/public/less/main.less b/kallithea/public/less/main.less --- a/kallithea/public/less/main.less +++ b/kallithea/public/less/main.less @@ -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"; diff --git a/kallithea/public/less/style.less b/kallithea/public/less/style.less --- a/kallithea/public/less/style.less +++ b/kallithea/public/less/style.less @@ -929,3 +929,9 @@ nav.navbar #quick > li > a, #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; +} diff --git a/kallithea/templates/base/root.html b/kallithea/templates/base/root.html --- a/kallithea/templates/base/root.html +++ b/kallithea/templates/base/root.html @@ -74,6 +74,8 @@ + + ## EXTRA FOR JS <%block name="js_extra"/>