From patchwork Sun Sep 9 23:43:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael-Doyle Hudson X-Patchwork-Id: 11257 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 7684623E29 for ; Sun, 9 Sep 2012 23:43:16 +0000 (UTC) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by fiordland.canonical.com (Postfix) with ESMTP id C57EAA18167 for ; Sun, 9 Sep 2012 23:43:15 +0000 (UTC) Received: by ieak11 with SMTP id k11so2031428iea.11 for ; Sun, 09 Sep 2012 16:43:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :content-type:mime-version:x-launchpad-project:x-launchpad-branch :x-launchpad-message-rationale:x-launchpad-branch-revision-number :x-launchpad-notification-type:to:from:subject:message-id:date :reply-to:sender:errors-to:precedence:x-generated-by :x-launchpad-hash:x-gm-message-state; bh=RVzJrwzy3TOQRV4eT/4VQkAToLdgeSLtYH8lvuEA0Hc=; b=LcqEkIxMVKA+E2PrbrOUlb+KFB3nCXWN6aoYBsPQru06/4/EFNbQZRi7CaocAoUPsk BwNpIaPTnlLQqq8PPDTVUcn65z+X8kHtWXOI0L9Qi8N4c5tZG/L7aLpa19yksdDT6fSu eqzRC1yt+b9pPZj0yFIh+tAcOJZ5SwhMyYhtUzuPQ0wcOKx0zFVDLyaL5awjWyADnFGx lKl+LC2yC2Y1CD4/RuO4euYEF+uwlbH0LCRakptlX1IIZOBQgyuLwRNgEkhtpMHdK7Em xLSwBdkd4Pvp3rftHv9h0zUz5twMfNMzsE66DyVe0LUuqY3YrsplOMkb3RpS4svLwjSH kv4w== Received: by 10.50.207.106 with SMTP id lv10mr8801802igc.0.1347234195139; Sun, 09 Sep 2012 16:43:15 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.184.232 with SMTP id ex8csp65407igc; Sun, 9 Sep 2012 16:43:13 -0700 (PDT) Received: by 10.180.107.163 with SMTP id hd3mr12877183wib.19.1347234193013; Sun, 09 Sep 2012 16:43:13 -0700 (PDT) Received: from indium.canonical.com (indium.canonical.com. [91.189.90.7]) by mx.google.com with ESMTPS id v56si16502938web.77.2012.09.09.16.43.12 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 09 Sep 2012 16:43:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) client-ip=91.189.90.7; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of bounces@canonical.com designates 91.189.90.7 as permitted sender) smtp.mail=bounces@canonical.com Received: from ackee.canonical.com ([91.189.89.26]) by indium.canonical.com with esmtp (Exim 4.71 #1 (Debian)) id 1TAr9k-0000Yg-1L for ; Sun, 09 Sep 2012 23:43:12 +0000 Received: from ackee.canonical.com (localhost [127.0.0.1]) by ackee.canonical.com (Postfix) with ESMTP id EFAB5E041B for ; Sun, 9 Sep 2012 23:43:11 +0000 (UTC) MIME-Version: 1.0 X-Launchpad-Project: lava-dashboard X-Launchpad-Branch: ~linaro-validation/lava-dashboard/trunk X-Launchpad-Message-Rationale: Subscriber X-Launchpad-Branch-Revision-Number: 342 X-Launchpad-Notification-Type: branch-revision To: Linaro Patch Tracker From: noreply@launchpad.net Subject: [Branch ~linaro-validation/lava-dashboard/trunk] Rev 342: use django formsets and the js from django-dynamic-formset to make attribute editing on filters a... Message-Id: <20120909234311.15985.89021.launchpad@ackee.canonical.com> Date: Sun, 09 Sep 2012 23:43:11 -0000 Reply-To: noreply@launchpad.net Sender: bounces@canonical.com Errors-To: bounces@canonical.com Precedence: bulk X-Generated-By: Launchpad (canonical.com); Revision="15914"; Instance="launchpad-lazr.conf" X-Launchpad-Hash: ad8c6f998fa256cf678d4b86d2bae8736b7f2b56 X-Gm-Message-State: ALoCoQlS8CJpf1beAF7k1WDXF4GwFFIWOesMexlEIa0mb+6cr1gNAhX+AMU4mRn/Z1iHXnWPa3GD Merge authors: Michael Hudson-Doyle (mwhudson) ------------------------------------------------------------ revno: 342 [merge] committer: Michael Hudson-Doyle branch nick: trunk timestamp: Mon 2012-09-10 11:42:02 +1200 message: use django formsets and the js from django-dynamic-formset to make attribute editing on filters a bit more standard and reusable added: dashboard_app/static/js/jquery.formset.js modified: dashboard_app/static/js/filter-edit.js dashboard_app/templates/dashboard_app/filter_form.html dashboard_app/views.py --- lp:lava-dashboard https://code.launchpad.net/~linaro-validation/lava-dashboard/trunk You are subscribed to branch lp:lava-dashboard. To unsubscribe from this branch go to https://code.launchpad.net/~linaro-validation/lava-dashboard/trunk/+edit-subscription === modified file 'dashboard_app/static/js/filter-edit.js' --- dashboard_app/static/js/filter-edit.js 2012-08-20 23:55:03 +0000 +++ dashboard_app/static/js/filter-edit.js 2012-09-09 23:30:23 +0000 @@ -1,4 +1,3 @@ -var row_number; $(function () { function updateTestCasesFromTest() { var test_id=$("#id_test option:selected").html(); @@ -22,34 +21,16 @@ select.attr('disabled', 'disabled'); } }; + $("#id_test").change(updateTestCasesFromTest); -row_number = $("#attribute-table tbody tr").size(); -$("#add-attribute").click( - function (e) { - e.preventDefault(); - var body = $("#attribute-table tbody"); - var row = $("#template-row").clone(true, true); - row.show(); - row.find('.key').attr('id', 'id_attribute_key_' + row_number); - row.find('.value').attr('id', 'id_attribute_value_' + row_number); - row.find('.key').attr('name', 'attribute_key_' + row_number); - row.find('.value').attr('name', 'attribute_value_' + row_number); - row_number += 1; - body.append(row); - row.find(".key").autocomplete(keyAutocompleteConfig); - row.find(".value").autocomplete(valueAutocompleteConfig); - }); -$("a.delete-row").click( - function (e) { - e.preventDefault(); - $(this).closest('tr').remove(); - }); -var keyAutocompleteConfig = { + +var nameAutocompleteConfig = { source: attr_name_completion_url }; + var valueAutocompleteConfig = { source: function (request, response) { - var attrName = this.element.closest('tr').find('input.key').val(); + var attrName = this.element.closest('tr').find('.name input').val(); $.getJSON( attr_value_completion_url, { @@ -62,6 +43,21 @@ ); } }; -$("tbody .key").autocomplete(keyAutocompleteConfig); -$("tbody .value").autocomplete(valueAutocompleteConfig); + +$("tbody .name input").autocomplete(nameAutocompleteConfig); +$("tbody .value input").autocomplete(valueAutocompleteConfig); + +$("#attributes-table tbody tr").formset( + { + formTemplate: '#id_attributes_empty_form', + prefix: "attributes", + addText: "Add a required attribute", + added: function(row) { + row.find(".name input").unbind(); + row.find(".name input").autocomplete(nameAutocompleteConfig); + row.find(".value input").unbind(); + row.find(".value input").autocomplete(valueAutocompleteConfig); + } + }); + }); \ No newline at end of file === added file 'dashboard_app/static/js/jquery.formset.js' --- dashboard_app/static/js/jquery.formset.js 1970-01-01 00:00:00 +0000 +++ dashboard_app/static/js/jquery.formset.js 2012-09-07 00:53:52 +0000 @@ -0,0 +1,206 @@ +/** + * jQuery Formset 1.3-pre + * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com) + * @requires jQuery 1.2.6 or later + * + * Copyright (c) 2009, Stanislaus Madueke + * All rights reserved. + * + * Licensed under the New BSD License + * See: http://www.opensource.org/licenses/bsd-license.php + */ +;(function($) { + $.fn.formset = function(opts) + { + var options = $.extend({}, $.fn.formset.defaults, opts), + flatExtraClasses = options.extraClasses.join(' '), + totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS'), + maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS'), + childElementSelector = 'input,select,textarea,label,div', + $$ = $(this), + + applyExtraClasses = function(row, ndx) { + if (options.extraClasses) { + row.removeClass(flatExtraClasses); + row.addClass(options.extraClasses[ndx % options.extraClasses.length]); + } + }, + + updateElementIndex = function(elem, prefix, ndx) { + var idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'), + replacement = prefix + '-' + ndx + '-'; + if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement)); + if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement)); + if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement)); + }, + + hasChildElements = function(row) { + return row.find(childElementSelector).length > 0; + }, + + showAddButton = function() { + return maxForms.length == 0 || // For Django versions pre 1.2 + (maxForms.val() == '' || (maxForms.val() - totalForms.val() > 0)) + }, + + insertDeleteLink = function(row) { + if (row.is('TR')) { + // If the forms are laid out in table rows, insert + // the remove button into the last table cell: + row.children(':last').append('' + options.deleteText + ''); + } else if (row.is('UL') || row.is('OL')) { + // If they're laid out as an ordered/unordered list, + // insert an
  • after the last list item: + row.append('
  • ' + options.deleteText +'
  • '); + } else { + // Otherwise, just insert the remove button as the + // last child element of the form's container: + row.append('' + options.deleteText +''); + } + row.find('a.' + options.deleteCssClass).click(function() { + var row = $(this).parents('.' + options.formCssClass), + del = row.find('input:hidden[id $= "-DELETE"]'), + buttonRow = row.siblings("a." + options.addCssClass + ', .' + options.formCssClass + '-add'), + forms; + if (del.length) { + // We're dealing with an inline formset. + // Rather than remove this form from the DOM, we'll mark it as deleted + // and hide it, then let Django handle the deleting: + del.val('on'); + row.hide(); + forms = $('.' + options.formCssClass).not(':hidden'); + } else { + row.remove(); + // Update the TOTAL_FORMS count: + forms = $('.' + options.formCssClass).not('.formset-custom-template'); + totalForms.val(forms.length); + } + for (var i=0, formCount=forms.length; i