← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/bug-tag-enhacement into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/bug-tag-enhacement into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1016636 in Launchpad itself: "Template makes all the markup for the bug tag completer"
  https://bugs.launchpad.net/launchpad/+bug/1016636

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/bug-tag-enhacement/+merge/111639

The bug tag completer is not portable. We cannot put it on +filebug or
advanced search without adding a lot of markup. The script could generate
its markup instead of assuming the page provides it which will make it
easier to reuse the code.

--------------------------------------------------------------------

RULES

    Pre-implementation: jcsackett
    * Pull the bug tag completer markup into the script.
    * There are actually two different blocks that could be merged
      into a single block that the bug tag completer manages.

    Addendum
    * I discovered that the failure case flashed green and the cancel
      case flashed red. Deryck, Jon, and Rick agreed they colours should
      be switched


QA

    * Visit https://bugs.qastaging.launchpad.net/gdp/+bug/459328
    * Verify you can remove all tags.
    * Verify the link reads "(+) Add tags"
    * Verify you can add and save a tag.
    * Verify the page shows the linked tags and there is an edit icon.


LINT

    lib/canonical/launchpad/icing/css/modifiers.css
    lib/lp/bugs/javascript/bug_tags_entry.js
    lib/lp/bugs/javascript/tests/test_bug_tags_entry.html
    lib/lp/bugs/javascript/tests/test_bug_tags_entry.js
    lib/lp/bugs/templates/bugtask-index.pt


TEST

    ./bin/test -vvc -t bug_tags_entry lp.bugs.tests.test_yui


IMPLEMENTATION

Updated the .hidden rule to have more precedence than form.inline. I made
a previous CSS fix this week by changing the order of classes. I think this
change is final. We want .hidden to override any other rule that sets the
display property.
    lib/canonical/launchpad/icing/css/modifiers.css

Simplified the bug-tag markup into one block for textual and graphical
browsers. The markup and the javascript do not need to work with add and
edit elements as separate features. The bug tag completer creates the
form and completer as needed. The bug tag completer hides the form
instead of each element in the form. I reversed the colours for failure
and cancel; the former should be red and the later should be green.
    lib/lp/bugs/javascript/bug_tags_entry.js
    lib/lp/bugs/javascript/tests/test_bug_tags_entry.html
    lib/lp/bugs/javascript/tests/test_bug_tags_entry.js
    lib/lp/bugs/templates/bugtask-index.pt
-- 
https://code.launchpad.net/~sinzui/launchpad/bug-tag-enhacement/+merge/111639
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/bug-tag-enhacement into lp:launchpad.
=== modified file 'lib/canonical/launchpad/icing/css/modifiers.css'
--- lib/canonical/launchpad/icing/css/modifiers.css	2012-06-21 13:01:53 +0000
+++ lib/canonical/launchpad/icing/css/modifiers.css	2012-06-22 16:23:39 +0000
@@ -212,5 +212,5 @@
 /* Hidden must be the last rule because it overides all other rules. */
 .unseen,
 .hidden {
-    display: none;
+    display: none !important;
     }

=== modified file 'lib/lp/bugs/javascript/bug_tags_entry.js'
--- lib/lp/bugs/javascript/bug_tags_entry.js	2012-06-21 13:58:55 +0000
+++ lib/lp/bugs/javascript/bug_tags_entry.js	2012-06-22 16:23:39 +0000
@@ -12,8 +12,8 @@
 var namespace = Y.namespace('lp.bugs.bug_tags_entry');
 
 var bug_tags_div;
-var edit_tags_trigger;
-var add_tags_trigger;
+var tags_heading;
+var tags_trigger;
 var tag_list_span;
 var tag_input;
 var ok_button;
@@ -23,16 +23,11 @@
 var available_tags;
 var autocomplete;
 
-var DISPLAY = 'display',
-    NONE = 'none',
-    INLINE = 'inline',
-    A = 'a',
+var A = 'a',
     VALUE = 'value',
     BUG = 'bug',
     INNER_HTML = 'innerHTML',
     ESCAPE = 27,
-    TAGS_SHOW = 'tags-show',
-    TAGS_HIDE = 'tags-hide';
     HIDDEN = 'hidden';
 
 /**
@@ -111,25 +106,20 @@
                     {tag_url: base_url + tag, tag: tag});
             }).join(' ');
             tag_list_span.set(INNER_HTML, tags_html);
-            tag_input.addClass(HIDDEN);
             tag_list_span.removeClass(HIDDEN);
-            ok_button.addClass(HIDDEN);
-            cancel_button.addClass(HIDDEN);
-            edit_tags_trigger.removeClass(HIDDEN);
+            tags_trigger.removeClass(HIDDEN);
+            ok_button.removeClass(HIDDEN);
+            cancel_button.removeClass(HIDDEN);
             tags_edit_spinner.addClass(HIDDEN);
+            tags_form.addClass(HIDDEN);
             Y.lp.anim.green_flash({ node: tag_list_span }).run();
-            if (Y.Lang.trim(tags_html) === '') {
-                Y.one('#bug-tags').removeClass(TAGS_SHOW);
-                Y.one('#bug-tags').addClass(TAGS_HIDE);
-                Y.one('#add-bug-tags').removeClass(TAGS_HIDE);
-                Y.one('#add-bug-tags').addClass(TAGS_SHOW);
-            }
+            namespace.update_ui();
         },
         failure: function(id, request) {
             tags_edit_spinner.addClass(HIDDEN);
             ok_button.removeClass(HIDDEN);
             cancel_button.removeClass(HIDDEN);
-            Y.lp.anim.green_flash({ node: tag_list_span }).run();
+            Y.lp.anim.red_flash({ node: tag_list_span }).run();
         }
     }});
 };
@@ -140,20 +130,13 @@
  * @method cancel
  */
 var cancel = function() {
-    tag_input.addClass(HIDDEN);
     tag_list_span.removeClass(HIDDEN);
-    ok_button.addClass(HIDDEN);
-    cancel_button.addClass(HIDDEN);
-    edit_tags_trigger.removeClass(HIDDEN);
+    tags_trigger.removeClass(HIDDEN);
     tags_edit_spinner.addClass(HIDDEN);
+    tags_form.addClass(HIDDEN);
     autocomplete.hide();
-    Y.lp.anim.red_flash({ node: tag_list_span }).run();
-    if (Y.Lang.trim(tag_list_span.get('innerHTML')) === '') {
-        Y.one('#bug-tags').removeClass(TAGS_SHOW);
-        Y.one('#bug-tags').addClass(TAGS_HIDE);
-        Y.one('#add-bug-tags').removeClass(TAGS_HIDE);
-        Y.one('#add-bug-tags').addClass(TAGS_SHOW);
-    }
+    Y.lp.anim.green_flash({ node: tag_list_span }).run();
+    namespace.update_ui();
 };
 
 /**
@@ -164,14 +147,39 @@
 var edit = function() {
     populate_tags_input();
     tag_list_span.addClass(HIDDEN);
-    tag_input.removeClass(HIDDEN);
+    tags_trigger.addClass(HIDDEN);
     tag_input.focus();
-    edit_tags_trigger.addClass(HIDDEN);
-    ok_button.removeClass(HIDDEN);
-    cancel_button.removeClass(HIDDEN);
+    tags_form.removeClass(HIDDEN);
     autocomplete.render();
 };
 
+
+/**
+ * Update the heading and action to match the tag state.
+ *
+ * @method update_ui
+ */
+namespace.update_ui = function() {
+    if (Y.Lang.trim(tag_list_span.get('innerHTML')) === '') {
+        // Show the add tags presentation.
+        tags_heading.set('text', '');
+        tags_trigger.set('text', 'Add tags');
+        tags_trigger.set('title', 'Add tags');
+        tags_trigger.removeClass('edit');
+        tags_trigger.removeClass('action-icon');
+        tags_trigger.addClass('add');
+    } else {
+        // Show the edit tags presentation.
+        tags_heading.set('text', 'Tags:');
+        tags_trigger.set('text', 'Edit');
+        tags_trigger.set('title', 'Edit tags');
+        tags_trigger.removeClass('add');
+        tags_trigger.addClass('edit');
+        tags_trigger.addClass('action-icon');
+    }
+};
+
+
 /**
  * Set up inline tag editing on a bug page.
  *
@@ -182,26 +190,31 @@
 
     available_tags = available_official_tags;
     bug_tags_div = Y.one('#bug-tags');
-    edit_tags_trigger = bug_tags_div.one('#edit-tags-trigger');
-    add_tags_trigger = Y.one('#add-tags-trigger');
+    tags_heading = bug_tags_div.one('#tags-heading');
+    tags_trigger = bug_tags_div.one('#tags-trigger');
     tag_list_span = bug_tags_div.one('#tag-list');
-    tag_input = bug_tags_div.one('#tag-input');
-    ok_button = bug_tags_div.one('#edit-tags-ok');
-    cancel_button = bug_tags_div.one('#edit-tags-cancel');
-    tags_edit_spinner = bug_tags_div.one('#tags-edit-spinner');
-    tags_form = bug_tags_div.one('#tags-form');
-
-    edit_tags_trigger.on('click', function(e) {
-        e.halt();
-        edit();
-    });
-
-    add_tags_trigger.on('click', function(e) {
-        e.halt();
-        Y.one('#bug-tags').removeClass(TAGS_HIDE);
-        Y.one('#bug-tags').addClass(TAGS_SHOW);
-        Y.one('#add-bug-tags').removeClass(TAGS_SHOW);
-        Y.one('#add-bug-tags').addClass(TAGS_HIDE);
+
+    tags_form = Y.Node.create(
+        '<form id="tags-form" class="inline hidden"></form>');
+    tag_input = Y.Node.create(
+        '<input type="text" id="tag-input" />');
+    tags_edit_spinner = Y.Node.create(
+        '<img src="/@@/spinner" id="tags-edit-spinner" class="hidden" />');
+    ok_button = Y.Node.create(
+        '<button class="lazr-pos lazr-btn yui-ieditor-submit_button" ' +
+        'id="edit-tags-ok" type="button">Ok</button>');
+    cancel_button = Y.Node.create(
+        '<button class="lazr-neg lazr-btn yui-ieditor-cancel_button" ' +
+        'id="edit-tags-cancel" type="button">Cancel</button>');
+    tags_form.append(tag_input);
+    tags_form.append("&nbsp;");
+    tags_form.append(tags_edit_spinner);
+    tags_form.append(ok_button);
+    tags_form.append(cancel_button);
+    tag_list_span.insert(tags_form, 'after');
+
+    tags_trigger.on('click', function(e) {
+        e.halt();
         edit();
     });
 
@@ -235,9 +248,11 @@
     // We indicate that the links are AJAXified before the AutoComplete
     // widget is set up, since the AutoComplete isn't needed to edit the
     // tags inline.
-    add_tags_trigger.addClass('js-action');
-    edit_tags_trigger.addClass('js-action');
+    tags_trigger.addClass('js-action');
 
+    bug_tags_div.append(
+        '<div id="tags-autocomplete"><div id="tags-autocomplete-content">' +
+        '</div></div>');
     autocomplete = new Y.lazr.AutoComplete({
         input: '#tag-input',
         data: available_official_tags,

=== modified file 'lib/lp/bugs/javascript/tests/test_bug_tags_entry.html'
--- lib/lp/bugs/javascript/tests/test_bug_tags_entry.html	2012-06-21 02:50:33 +0000
+++ lib/lp/bugs/javascript/tests/test_bug_tags_entry.html	2012-06-22 16:23:39 +0000
@@ -52,39 +52,34 @@
 
         <div id="fixture"></div>
 
-        <script type="text/x-template" id="bug-tag-form">
-        <!-- Has tags -->
-         <div id="bug-tags" class="tags-show">
-            Tags:
+        <script type="text/x-template" id="edit-bug-tag-form">
+          <div id="bug-tags">
+            <span id="tags-heading">
+              Tags:
+            </span>
             <span id="tag-list">
               <a class="official-tag"
                   href="/fnord/+bugs?field.tag=project-tag">project-tag</a>
               <a class="unofficial-tag"
                   href="/fnord/+bugs?field.tag=user-tag">user-tag</a>
             </span>
-
-            <form id="tags-form" style="display: inline">
-                <input type="text" id="tag-input" class="hidden" />
-                <img src="/@@/spinner" id="tags-edit-spinner" class="hidden"/>
-                <a href="+edit" title="Edit tags" id="edit-tags-trigger"
-                    class="sprite edit action-icon">Edit</a>
-
-              <button class="lazr-pos lazr-btn yui-ieditor-submit_button hidden"
-                  id="edit-tags-ok" type="button">Ok</button>
-              <button class="lazr-neg lazr-btn yui-ieditor-cancel_button hidden"
-                  id="edit-tags-cancel" type="button">Cancel</button>
-           </form>
-
-           <a href="/+help-bugs/tag-help.html" target="help"
-               class="sprite maybe action-icon">Tag help</a>
+            <a href="+edit" title="Edit tags" id="tags-trigger"
+              class="sprite edit action-icon">Edit</a>
+            <a href="/+help-bugs/tag-help.html" target="help"
+              class="sprite maybe action-icon">Tag help</a>
           </div>
+        </script>
 
-          <!-- No tags -->
-          <div id="add-bug-tags" class="tags-hide">
-            <a href="+edit" title="Add tags" id="add-tags-trigger"
-                class="sprite add">Add tags</a>
+        <script type="text/x-template" id="add-bug-tag-form">
+          <div id="bug-tags">
+            <span id="tags-heading">
+            </span>
+            <span id="tag-list">
+            </span>
+            <a href="+edit" title="Add tags" id="tags-trigger"
+              class="sprite add action-icon">Add tags</a>
             <a href="/+help-bugs/tag-help.html" target="help"
-                class="sprite maybe action-icon">Tag help</a>
+              class="sprite maybe action-icon">Tag help</a>
           </div>
         </script>
     </body>

=== modified file 'lib/lp/bugs/javascript/tests/test_bug_tags_entry.js'
--- lib/lp/bugs/javascript/tests/test_bug_tags_entry.js	2012-06-21 13:58:55 +0000
+++ lib/lp/bugs/javascript/tests/test_bug_tags_entry.js	2012-06-22 16:23:39 +0000
@@ -45,15 +45,9 @@
 
         setUp: function() {
             this.fixture = Y.one("#fixture");
-            var template = Y.one('#bug-tag-form').getContent();
+            var template = Y.one('#edit-bug-tag-form').getContent();
             this.fixture.append(template);
-            this.edit_tags_trigger = Y.one('#edit-tags-trigger');
-            this.add_tags_trigger = Y.one('#add-tags-trigger');
-            this.tag_list_span = Y.one('#tag-list');
-            this.tag_input = Y.one('#tag-input');
-            this.ok_button = Y.one('#edit-tags-ok');
-            this.cancel_button = Y.one('#edit-tags-cancel');
-            this.tags_edit_spinner = Y.one('#tags-edit-spinner');
+            this.bug_tags_div = Y.one('#bug-tags');
             window.LP = {
                 links: {me : "/~user"},
                 cache: {
@@ -65,7 +59,7 @@
                 };
         },
 
-        tearDown: function () {
+        tearDown: function() {
             if (this.fixture !== null) {
                 this.fixture.empty();
             }
@@ -73,31 +67,91 @@
             delete window.LP;
         },
 
-        test_edit: function () {
-            module.setup_tag_entry(['project-tag']);
-            this.edit_tags_trigger.simulate('click');
+        _set_common_elements: function() {
+            this.tags_heading = Y.one('#tags-heading');
+            this.tags_trigger = Y.one('#tags-trigger');
+            this.tag_list_span = Y.one('#tag-list');
+            this.tags_form = Y.one('#tags-form');
+            this.tag_input = Y.one('#tag-input');
+            this.ok_button = Y.one('#edit-tags-ok');
+            this.cancel_button = Y.one('#edit-tags-cancel');
+            this.tags_edit_spinner = Y.one('#tags-edit-spinner');
+        },
+
+        test_setup_tag_entry: function() {
+            module.setup_tag_entry(['project-tag']);
+            // The form is created.
+            var form_node = this.bug_tags_div.one('#tags-form');
+            Y.Assert.isInstanceOf(Y.Node, form_node);
+            Y.Assert.isInstanceOf(Y.Node, form_node.one('#tag-input'));
+            Y.Assert.isInstanceOf(Y.Node, form_node.one('#tags-edit-spinner'));
+            Y.Assert.isInstanceOf(Y.Node, form_node.one('#edit-tags-cancel'));
+            Y.Assert.isInstanceOf(Y.Node, form_node.one('#tag-input'));
+            // The Autocompleter nodes are provided.
+            var completer_node = this.bug_tags_div.one('#tags-autocomplete');
+            Y.Assert.isInstanceOf(Y.Node, completer_node);
+            var completer_content = completer_node.one(
+                '#tags-autocomplete-content');
+            Y.Assert.isInstanceOf(Y.Node, completer_content);
+        },
+
+        test_update_ui_remove_all_tags: function() {
+            // The add tags presentation is shown when the tags are removed.
+            module.setup_tag_entry(['project-tag']);
+            this._set_common_elements();
+            this.tag_list_span.set('text', '');
+            module.update_ui();
+            Y.Assert.areEqual('', this.tags_heading.get('text'));
+            Y.Assert.areEqual('Add tags', this.tags_trigger.get('text'));
+            Y.Assert.areEqual('Add tags', this.tags_trigger.get('title'));
+            Y.Assert.isTrue(this.tags_trigger.hasClass('add'));
+            Y.Assert.isFalse(this.tags_trigger.hasClass('action-icon'));
+            Y.Assert.isFalse(this.tags_trigger.hasClass('edit'));
+        },
+
+        test_update_ui_add_tags: function() {
+            // The edit tags presentation is shown when tags are added.
+            module.setup_tag_entry(['project-tag']);
+            var template = Y.one('#add-bug-tag-form').getContent();
+            this.fixture.append(template);
+            this._set_common_elements();
+            this.tag_list_span.set(
+                'innerHtml', '<a href="#">project-tag</a>');
+            module.update_ui();
+            Y.Assert.areEqual('Tags:', this.tags_heading.get('text'));
+            Y.Assert.areEqual('Edit', this.tags_trigger.get('text'));
+            Y.Assert.areEqual('Edit tags', this.tags_trigger.get('title'));
+            Y.Assert.isTrue(this.tags_trigger.hasClass('edit'));
+            Y.Assert.isTrue(this.tags_trigger.hasClass('action-icon'));
+            Y.Assert.isFalse(this.tags_trigger.hasClass('add'));
+        },
+
+        test_edit: function() {
+            module.setup_tag_entry(['project-tag']);
+            this._set_common_elements();
+            this.tags_trigger.simulate('click');
             Y.Assert.isTrue(this.tag_list_span.hasClass('hidden'));
-            Y.Assert.isTrue(this.edit_tags_trigger.hasClass('hidden'));
-            Y.Assert.isFalse(this.tag_input.hasClass('hidden'));
+            Y.Assert.isTrue(this.tags_trigger.hasClass('hidden'));
+            Y.Assert.isFalse(this.tags_form.hasClass('hidden'));
             Y.Assert.isFalse(this.ok_button.hasClass('hidden'));
             Y.Assert.isFalse(this.cancel_button.hasClass('hidden'));
         },
 
-        test_cancel: function () {
+        test_cancel: function() {
             module.setup_tag_entry(['project-tag']);
-            this.edit_tags_trigger.simulate('click');
+            this._set_common_elements();
+            this.tags_trigger.simulate('click');
             this.cancel_button.simulate('click');
             Y.Assert.isFalse(this.tag_list_span.hasClass('hidden'));
-            Y.Assert.isFalse(this.edit_tags_trigger.hasClass('hidden'));
-            Y.Assert.isTrue(this.tag_input.hasClass('hidden'));
-            Y.Assert.isTrue(this.ok_button.hasClass('hidden'));
-            Y.Assert.isTrue(this.cancel_button.hasClass('hidden'));
+            Y.Assert.isFalse(this.tags_trigger.hasClass('hidden'));
+            Y.Assert.isTrue(this.tags_form.hasClass('hidden'));
             Y.Assert.isTrue(this.tags_edit_spinner.hasClass('hidden'));
         },
 
-        test_save_tags_success: function () {
+        test_save_tags_success: function() {
             module.setup_tag_entry(['project-tag']);
-            this.edit_tags_trigger.simulate('click');
+            this._set_common_elements();
+            this.tags_trigger.simulate('click');
             var mockio = new Y.lp.testing.mockio.MockIo();
             module.lp_config = {io_provider: mockio};
             this.ok_button.simulate('click');
@@ -111,16 +165,17 @@
                     tags: ['project-tag']}),
                 responseHeaders: {'Content-Type': 'application/json'}});
             Y.Assert.isFalse(this.tag_list_span.hasClass('hidden'));
-            Y.Assert.isFalse(this.edit_tags_trigger.hasClass('hidden'));
-            Y.Assert.isTrue(this.tag_input.hasClass('hidden'));
-            Y.Assert.isTrue(this.ok_button.hasClass('hidden'));
-            Y.Assert.isTrue(this.cancel_button.hasClass('hidden'));
+            Y.Assert.isFalse(this.tags_trigger.hasClass('hidden'));
+            Y.Assert.isTrue(this.tags_form.hasClass('hidden'));
             Y.Assert.isTrue(this.tags_edit_spinner.hasClass('hidden'));
+            Y.Assert.isFalse(this.ok_button.hasClass('hidden'));
+            Y.Assert.isFalse(this.cancel_button.hasClass('hidden'));
         },
 
-        test_save_tags_failure: function () {
+        test_save_tags_failure: function() {
             module.setup_tag_entry(['project-tag']);
-            this.edit_tags_trigger.simulate('click');
+            this._set_common_elements();
+            this.tags_trigger.simulate('click');
             var mockio = new Y.lp.testing.mockio.MockIo();
             module.lp_config = {io_provider: mockio};
             this.ok_button.simulate('click');

=== modified file 'lib/lp/bugs/templates/bugtask-index.pt'
--- lib/lp/bugs/templates/bugtask-index.pt	2012-06-15 16:23:50 +0000
+++ lib/lp/bugs/templates/bugtask-index.pt	2012-06-22 16:23:39 +0000
@@ -84,10 +84,6 @@
     </metal:heading>
 
     <div metal:fill-slot="main" tal:define="context_menu context/menu:context">
-      <div id="tags-autocomplete">
-        <div id="tags-autocomplete-content"></div>
-      </div>
-
       <p class="informational message"
          tal:condition="view/notices"
          tal:repeat="notice view/notices"
@@ -132,54 +128,40 @@
           >See <a href="comments/0">original description</a></span>
         </div>
 
-          <div id="bug-tags"
-               tal:attributes="class python: (context.bug.tags and
-                                             'tags-show' or 'tags-hide')">
-            Tags:
-            <span id="tag-list">
-              <a tal:repeat="tag view/official_tags"
-                 tal:content="python: tag[0]"
-                 class="official-tag"
-                 tal:attributes="href python: tag[1]">tag</a>
-              <a tal:repeat="tag view/unofficial_tags"
-                 tal:content="python: tag[0]"
-                 class="unofficial-tag"
-                 tal:attributes="href python: tag[1]">tag</a>
-            </span>
-            <form id="tags-form" style="display: inline">
-                <input type="text" id="tag-input" class="hidden" style="width: 35em;" />
-                <img src="/@@/spinner" id="tags-edit-spinner" class="hidden"/>
-                <a href="+edit" title="Edit tags" id="edit-tags-trigger" class="sprite edit action-icon">Edit</a>
+        <div id="bug-tags">
+          <span id="tags-heading">
+            <tal:heading condition="context/bug/tags">Tags:</tal:heading>
+          </span>
+          <span id="tag-list">
+            <a tal:repeat="tag view/official_tags"
+               tal:content="python: tag[0]"
+               class="official-tag"
+               tal:attributes="href python: tag[1]">tag</a>
+            <a tal:repeat="tag view/unofficial_tags"
+               tal:content="python: tag[0]"
+               class="unofficial-tag"
+               tal:attributes="href python: tag[1]">tag</a>
+          </span>
+          <a href="+edit" title="Add tags" id="tags-trigger"
+            class="sprite add action-icon"
+            tal:condition="not: context/bug/tags">Add tags</a>
+          <a href="+edit" title="Edit tags" id="tags-trigger"
+            class="sprite edit action-icon"
+            tal:condition="context/bug/tags">Edit</a>
+          <a href="/+help-bugs/tag-help.html" target="help"
+            class="sprite maybe action-icon">Tag help</a>
+        </div>
 
-              <button class="lazr-pos lazr-btn yui-ieditor-submit_button hidden"
-                      id="edit-tags-ok"
-                      type="button">Ok</button>
-              <button class="lazr-neg lazr-btn yui-ieditor-cancel_button hidden"
-                      id="edit-tags-cancel"
-                      type="button">Cancel</button>
-           </form>
-           <a href="/+help-bugs/tag-help.html" target="help"
-              class="sprite maybe action-icon">Tag help</a>
-          </div>
-          <div id="add-bug-tags"
-               tal:attributes="class python: (not(context.bug.tags) and
-                                             'tags-show' or 'tags-hide')">
-            <a href="+edit" title="Add tags" id="add-tags-trigger" class="sprite add">
-              Add tags
-            </a>
-            <a href="/+help-bugs/tag-help.html" target="help"
-               class="sprite maybe action-icon">Tag help</a>
-            <script type="text/javascript">
-                LPJS.use('event', 'node', 'lp.bugs.bug_tags_entry', function(Y) {
-                    Y.on('domready',
-                         function(e) {
-                             Y.lp.bugs.bug_tags_entry.setup_tag_entry(
-                                 available_official_tags);
-                         },
-                         window);
-                });
-            </script>
-          </div>
+        <script type="text/javascript">
+          LPJS.use('event', 'node', 'lp.bugs.bug_tags_entry', function(Y) {
+              Y.on('domready',
+                   function(e) {
+                       Y.lp.bugs.bug_tags_entry.setup_tag_entry(
+                           available_official_tags);
+                   },
+                   window);
+          });
+        </script>
 
         <div class="clearfix"></div>
       </div>


Follow ups