From patchwork Thu Oct 1 14:12:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Lespiau X-Patchwork-Id: 525014 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 6CF99140D16 for ; Fri, 2 Oct 2015 00:17:06 +1000 (AEST) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 43FB71A04EB for ; Fri, 2 Oct 2015 00:17:06 +1000 (AEST) X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by lists.ozlabs.org (Postfix) with ESMTP id 48A411A03ED for ; Fri, 2 Oct 2015 00:13:42 +1000 (AEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga103.fm.intel.com with ESMTP; 01 Oct 2015 07:13:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,617,1437462000"; d="scan'208";a="817195437" Received: from unknown (HELO strange.ger.corp.intel.com) ([10.252.16.209]) by orsmga002.jf.intel.com with ESMTP; 01 Oct 2015 07:13:39 -0700 From: Damien Lespiau To: patchwork@lists.ozlabs.org Subject: [PATCH 23/49] filters: Rewrite the submitter autocompletion code Date: Thu, 1 Oct 2015 15:12:28 +0100 Message-Id: <1443708774-26996-24-git-send-email-damien.lespiau@intel.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1443708774-26996-1-git-send-email-damien.lespiau@intel.com> References: <1443708774-26996-1-git-send-email-damien.lespiau@intel.com> X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" We now have a nice(r) autocompletion widget that will popup the list of options directly underneath the input fild. A few changes are done in this commit that couldn't be split any further: - Use jQuery's $.ajax() for the completion query - Use the application/json content type on the completion answer to allow jQuery to directly create an object from it instead of giving back a string (because of the text/plain content type) - Crafted more logical objects in the json answer ie all properties are at the same level instead of the default queryset serializer that put the object fields in a 'field' sub-object. - Use selectize.js for the autocompletion widget logic A slight change in behaviour is that we now don't allow "free form" submitter search, ie we need a valid completion to search with that specific person (through its primary key). I didn't remove the backend logic that allows the "free form" mechanism, but maybe we should. v2: Squash the unit tests fixes into this patch (Jeremy Kerr) Signed-off-by: Damien Lespiau --- patchwork/filters.py | 16 ++- patchwork/templates/patchwork/filters.html | 152 ++++++----------------------- patchwork/tests/test_person.py | 4 +- patchwork/views/base.py | 18 ++-- 4 files changed, 53 insertions(+), 137 deletions(-) diff --git a/patchwork/filters.py b/patchwork/filters.py index 3f8bd3e..db671ff 100644 --- a/patchwork/filters.py +++ b/patchwork/filters.py @@ -87,6 +87,11 @@ class SubmitterFilter(Filter): self.person = None self.person_match = None submitter_id = None + + str = str.strip() + if str == '': + return + try: submitter_id = int(str) except ValueError: @@ -128,15 +133,8 @@ class SubmitterFilter(Filter): return '' def _form(self): - name = '' - if self.person: - name = self.person.name - return mark_safe(('' % escape(name)) + - '') + return mark_safe(('')) def key(self): if self.person: diff --git a/patchwork/templates/patchwork/filters.html b/patchwork/templates/patchwork/filters.html index 842e643..6ab8108 100644 --- a/patchwork/templates/patchwork/filters.html +++ b/patchwork/templates/patchwork/filters.html @@ -19,127 +19,40 @@ function filter_click() } -function enable_selected_submitter(select, input) -{ - select.name = 'submitter'; - input.name = ''; -} -function filter_form_submit(form) -{ - var i; - - var submitter_select = document.getElementById("submitter_select"); - var submitter_input = document.getElementById("submitter_input"); - if (!submitter_select || !submitter_input) { - req = null; - return; - } - - /* submitter handling. if possible, use the select box, otherwise leave - * as-is (and so the text box is used). */ - - if (submitter_select.options.length == 0) { - /* if there's no match, just use the input */ - - } else if (submitter_select.options.length == 1) { - /* if there's only one match, request by id */ - submitter_select.selectedIndex = 0; - enable_selected_submitter(submitter_select, submitter_input); - - } else if (submitter_select.selectedIndex != -1) { - /* if the user has explicitly selected, request by id */ - enable_selected_submitter(submitter_select, submitter_input); - - } - for (i = 0; i < form.elements.length; i++) { - var e = form.elements[i]; - if (e.type == 'submit') { - continue; - } - - /* handle submitter data */ - if (e.type == 'select-one') { - if (e.name == '') { - e.disabled = true; - } - if (e.selectedIndex != -1 - && e.options[e.selectedIndex].value == '') { - e.disabled = true; +$(document).ready(function() { + $('#submitter_input').selectize({ + valueField: 'pk', + labelField: 'name', + searchField: ['name', 'email'], + maxItems: 1, + persist: false, + render: { + option: function(item, escape) { + return '
' + escape(item.name) + ' <' + + escape(item.email) + '>' + '
'; + }, + item: function(item, escape) { + return '
' + escape(item.name) + '
'; } - - continue; - } - - if (e.value == '') { - e.disabled = true; - } - } -} - -var req = null; - -function submitter_complete_response() -{ - if (req.readyState != 4) { - return - } - - var completions; - eval("completions = " + req.responseText); - - if (completions.length == 0) { - req = null; - return; - } - - var submitter_select = document.getElementById("submitter_select"); - var submitter_input = document.getElementById("submitter_input"); - if (!submitter_select || !submitter_input) { - req = null; - return; - } - - for (i = 0; i < completions.length; i++) { - name = completions[i]['fields']['name']; - if (name) { - name = completions[i]['fields']['name'] + - ' <' + completions[i]['fields']['email'] + '>'; - } else { - name = completions[i]['fields']['email']; + }, + load: function(query, callback) { + if (query.length < 4) + return callback(); + + req = $.ajax({ + url: '{% url 'patchwork.views.submitter_complete' %}?q=' + + encodeURIComponent(query) + '&l=10', + error: function() { + callback(); + }, + success: function(res) { + callback(res); + } + }); } - o = new Option(name, completions[i]['pk']); - submitter_select.options[i] = o; - } - - /* remove remaining options */ - for (; i < submitter_select.length; i++) { - submitter_select.options[i] = null; - } - - submitter_select.disabled = false; - req = null; -} - -function submitter_field_change(field) -{ - var limit = 20; - var value = field.value; - if (value.length < 4) { - return; - } - - if (req) { - return; - } - - var url = '{% url 'patchwork.views.submitter_complete' %}?q=' + value + - '&l=' + limit; - req = new XMLHttpRequest(); - req.onreadystatechange = submitter_complete_response; - req.open("GET", url, true); - req.send(''); -} + }); +});
@@ -162,8 +75,7 @@ function submitter_field_change(field) {% endif %}