Changeset - 2e7ffb755d4f
[Not reviewed]
default
0 8 0
domruf - 7 years ago 2018-12-10 22:54:04
dominikruf@gmail.com
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.
8 files changed with 73 insertions and 61 deletions:
0 comments (0 inline, 0 general)
.hgignore
Show inline comments
 
@@ -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$
LICENSE.md
Show inline comments
 
@@ -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
 
----------
 

	
kallithea/bin/kallithea_cli_front_end.py
Show inline comments
 
@@ -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'))
kallithea/front-end/package.json
Show inline comments
 
@@ -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"
kallithea/public/js/base.js
Show inline comments
 
@@ -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 = $('<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
kallithea/public/less/main.less
Show inline comments
 
@@ -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";
kallithea/public/less/style.less
Show inline comments
 
@@ -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;
 
}
kallithea/templates/base/root.html
Show inline comments
 
@@ -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"/>
0 comments (0 inline, 0 general)