Merge lp:~rharding/launchpad/replace_foldables into lp:launchpad

Proposed by Richard Harding on 2012-01-09
Status: Merged
Approved by: Ian Booth on 2012-01-10
Approved revision: no longer in the source branch.
Merged at revision: 14661
Proposed branch: lp:~rharding/launchpad/replace_foldables
Merge into: lp:launchpad
Diff against target: 338 lines (+242/-56)
5 files modified
lib/lp/app/javascript/foldables.js (+79/-0)
lib/lp/app/javascript/lp-mochi.js (+0/-53)
lib/lp/app/javascript/tests/test_foldables.html (+28/-0)
lib/lp/app/javascript/tests/test_foldables.js (+131/-0)
lib/lp/app/templates/base-layout-macros.pt (+4/-3)
To merge this branch: bzr merge lp:~rharding/launchpad/replace_foldables
Reviewer Review Type Date Requested Status
Ian Booth (community) code 2012-01-09 Approve on 2012-01-10
Review via email: mp+87924@code.launchpad.net

Commit Message

[r=wallyworld][no-qa] Remove the mochikit foldable ui interaction from being used, replace with YUI lp.app.foldable.

Description of the Change

= Summary =
We're removing mochikit library which this foldable ui interaction relies on. In discussions with Curtis and others, it was determined that this was an effort to help with spam management. Since that issues isn't as prevalent these days, it won't be missed if the feature was just removed.

== Proposed Fix ==
Remove the function.

== Implementation Details ==
Removed

== Tests ==
google-chrome lib/lp/app/javascript/tests/test_foldable.html

== Demo and Q/A ==
Load a bug with a quoted comment and verify that you can close/

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/app/javascript/foldable.js
  lib/lp/app/javascript/tests/test_foldable.html
  lib/lp/app/javascript/tests/test_foldable.js

To post a comment you must log in.
Ian Booth (wallyworld) wrote :

Looks good. I have some questions/suggstions:

1. init method name: Y.lp.app.foldable.init();

Should we make it Y.lp.app.foldable.activate_foldables();
to be consistent with activate_collapsables() naming? The suggested name is also more indicative of what we are doing ie lookign for all foldable elements and activating each one. init() implies more that a module is being initialised rather than many page elements.

2. The old code:
if (quoted_lines && quoted_lines.length <= 11) {
was replaced with
if (quoted_lines && quoted_lines.size() <= 12) {

Which is correct?
I'd like to see a test around the corner case of 12 lines
ie test that exactly 12 lines is not folded but 13 lines is

review: Needs Fixing (code)
Ian Booth (wallyworld) wrote :

Excellent. Thanks for adding the suggested improvements.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'lib/lp/app/javascript/foldables.js'
2--- lib/lp/app/javascript/foldables.js 1970-01-01 00:00:00 +0000
3+++ lib/lp/app/javascript/foldables.js 2012-01-10 17:43:30 +0000
4@@ -0,0 +1,79 @@
5+/**
6+ * Copyright 2011 Canonical Ltd. This software is licensed under the
7+ * GNU Affero General Public License version 3 (see the file LICENSE).
8+ *
9+ * Making foldable sections of html
10+ *
11+ * Usage:
12+ * lp.app.foldables.activate();
13+ *
14+ * @module lp.app.foldables
15+ */
16+
17+YUI.add('lp.app.foldables', function(Y) {
18+
19+ var module = Y.namespace('lp.app.foldables');
20+ var VOID_URL = '_:void(0);'.replace('_', 'javascript');
21+
22+ var toggleFoldable = function(e) {
23+ var ELEMENT_NODE = 1;
24+ var node = e.currentTarget;
25+ while (node.get('nextSibling')) {
26+ node = node.get('nextSibling');
27+ if (node.get('nodeType') !== ELEMENT_NODE) {
28+ continue;
29+ }
30+ if (!node.hasClass('foldable') &&
31+ !node.hasClass('foldable-quoted')) {
32+ continue;
33+ }
34+ if (node.getStyle('display') === 'none') {
35+ node.setStyle('display', 'inline');
36+ } else {
37+ node.setStyle('display', 'none');
38+ }
39+ }
40+ };
41+
42+ module.activate = function () {
43+ // Create links to toggle the display of foldable content.
44+ var included = Y.all('span.foldable');
45+ var quoted = Y.all('span.foldable-quoted');
46+ quoted.each(function (n) {
47+ included.push(n);
48+ });
49+
50+ included.each(function (span, index, list) {
51+ if (span.hasClass('foldable-quoted')) {
52+ var quoted_lines = span.all('br');
53+ debugger;
54+ if (quoted_lines && quoted_lines.size() <= 11) {
55+ // We do not hide short quoted passages (12 lines) by
56+ // default.
57+ return;
58+ }
59+ }
60+
61+ var ellipsis = Y.Node.create('<a/>');
62+ ellipsis.setStyle('textDecoration', 'underline');
63+ ellipsis.set('href', VOID_URL);
64+ ellipsis.on('click', toggleFoldable);
65+ ellipsis.appendChild(Y.Node.create('[...]'));
66+
67+ span.get('parentNode').insertBefore(ellipsis, span);
68+ span.insertBefore(Y.Node.create('<br/>'), span.get('firstChild'));
69+ span.setStyle('display', 'none');
70+ if (span.get('nextSibling')) {
71+ // Text lines follows this span.
72+ var br = Y.Node.create('<br/>');
73+ span.get('parentNode').insertBefore(
74+ br,
75+ span.get('nextSibling')
76+ );
77+ }
78+ });
79+ };
80+
81+}, '0.1.0', {
82+ requires: ['base', 'node']
83+});
84
85=== modified file 'lib/lp/app/javascript/lp-mochi.js'
86--- lib/lp/app/javascript/lp-mochi.js 2011-06-30 17:38:28 +0000
87+++ lib/lp/app/javascript/lp-mochi.js 2012-01-10 17:43:30 +0000
88@@ -13,59 +13,6 @@
89 return node;
90 }
91
92-function toggleFoldable(e) {
93- var ELEMENT_NODE = 1;
94- var node = this;
95- while (node.nextSibling) {
96- node = node.nextSibling;
97- if (node.nodeType != ELEMENT_NODE) {
98- continue;
99- }
100- if (node.className.indexOf('foldable') == -1) {
101- continue;
102- }
103- if (node.style.display == 'none') {
104- node.style.display = 'inline';
105- } else {
106- node.style.display = 'none';
107- }
108- }
109-}
110-
111-function activateFoldables() {
112- // Create links to toggle the display of foldable content.
113- var included = getElementsByTagAndClassName(
114- 'span', 'foldable', document);
115- var quoted = getElementsByTagAndClassName(
116- 'span', 'foldable-quoted', document);
117- var elements = concat(included, quoted);
118- for (var i = 0; i < elements.length; i++) {
119- var span = elements[i];
120- if (span.className == 'foldable-quoted') {
121- var quoted_lines = span.getElementsByTagName('br');
122- if (quoted_lines && quoted_lines.length <= 11) {
123- // We do not hide short quoted passages (12 lines) by default.
124- continue;
125- }
126- }
127-
128- var ellipsis = document.createElement('a');
129- ellipsis.style.textDecoration = 'underline';
130- ellipsis.href = VOID_URL;
131- ellipsis.onclick = toggleFoldable;
132- ellipsis.appendChild(document.createTextNode('[...]'));
133-
134- span.parentNode.insertBefore(ellipsis, span);
135- span.insertBefore(document.createElement('br'), span.firstChild);
136- span.style.display = 'none';
137- if (span.nextSibling) {
138- // Text lines follows this span.
139- var br = document.createElement('br');
140- span.parentNode.insertBefore(br, span.nextSibling);
141- }
142- }
143-}
144-
145 function convertTextInputToTextArea(text_input_id, rows) {
146 var current_text_input = getElement(text_input_id);
147 var new_text_area = document.createElement("textarea");
148
149=== added file 'lib/lp/app/javascript/tests/test_foldables.html'
150--- lib/lp/app/javascript/tests/test_foldables.html 1970-01-01 00:00:00 +0000
151+++ lib/lp/app/javascript/tests/test_foldables.html 2012-01-10 17:43:30 +0000
152@@ -0,0 +1,28 @@
153+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
154+ "http://www.w3.org/TR/html4/strict.dtd">
155+<html>
156+ <head>
157+ <title>Foldable Text Tests</title>
158+
159+ <!-- YUI and test setup -->
160+ <script type="text/javascript"
161+ src="../../../../canonical/launchpad/icing/yui/yui/yui.js">
162+ </script>
163+ <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
164+ <script type="text/javascript"
165+ src="../../../app/javascript/testing/testrunner.js"></script>
166+
167+ <!-- The module under test -->
168+ <script type="text/javascript" src="../foldables.js"></script>
169+
170+ <!-- The test suite -->
171+ <script type="text/javascript" src="test_foldables.js"></script>
172+
173+</head>
174+<body class="yui3-skin-sam">
175+ <div id="target"></div>
176+ <ul id="suites">
177+ <li>lp.app.foldables.test</li>
178+ </ul>
179+</body>
180+</html>
181
182=== added file 'lib/lp/app/javascript/tests/test_foldables.js'
183--- lib/lp/app/javascript/tests/test_foldables.js 1970-01-01 00:00:00 +0000
184+++ lib/lp/app/javascript/tests/test_foldables.js 2012-01-10 17:43:30 +0000
185@@ -0,0 +1,131 @@
186+/* Copyright (c) 2011, Canonical Ltd. All rights reserved. */
187+
188+YUI.add('lp.app.foldables.test', function (Y) {
189+
190+ var test_foldables = Y.namespace('lp.app.foldables.test');
191+ var suite = new Y.Test.Suite('Foldable Tests');
192+
193+ var quote_comment = ['<p>Mister X wrote:<br />',
194+ '<span class="foldable-quoted">',
195+ '&gt; This is a quoted line<br />',
196+ '&gt; This is a quoted line<br />',
197+ '&gt; This is a quoted line<br />',
198+ '&gt; This is a quoted line<br />',
199+ '&gt; This is a quoted line<br />',
200+ '&gt; This is a quoted line<br />',
201+ '&gt; This is a quoted line<br />',
202+ '&gt; This is a quoted line<br />',
203+ '&gt; This is a quoted line<br />',
204+ '&gt; This is a quoted line<br />',
205+ '&gt; This is a quoted line<br />',
206+ '</span>',
207+ 'This is a reply to the line above.<br />',
208+ 'This is a continuation line.</p>'].join('');
209+
210+ var longer_comment = [
211+ '<p>Attribution line<br />',
212+ '<span class="foldable-quoted">',
213+ '&gt; First line in the first paragraph.<br />',
214+ '&gt; Second line in the first paragraph.<br />',
215+ '&gt; First line in the second paragraph.<br />',
216+ '&gt; Second line in the second paragraph.<br />',
217+ '&gt; First line in the third paragraph.<br />',
218+ '&gt; First line in the third paragraph.<br />',
219+ '&gt; First line in the third paragraph.<br />',
220+ '&gt; First line in the third paragraph.<br />',
221+ '&gt; First line in the third paragraph.<br />',
222+ '&gt; First line in the third paragraph.<br />',
223+ '&gt; First line in the third paragraph.<br />',
224+ '&gt; First line in the third paragraph.<br />',
225+ '&gt; First line in the third paragraph.<br />',
226+ '</span></p>'
227+ ];
228+
229+ var foldable_comment = [
230+ '<p><span class="foldable" style="display: none; "><br>',
231+ '-----BEGIN PGP SIGNED MESSAGE-----<br>',
232+ 'Hash: SHA1',
233+ '</span></p>'
234+ ].join('');
235+
236+ suite.add(new Y.Test.Case({
237+
238+ name: 'foldable_tests',
239+
240+ _add_comment: function (comment) {
241+ var cnode = Y.Node.create('<div/>');
242+ cnode.set('innerHTML', comment);
243+ Y.one('#target').appendChild(cnode);
244+ },
245+
246+ tearDown: function () {
247+ Y.one('#target').setContent('');
248+ },
249+
250+ test_namespace_exists: function () {
251+ Y.Assert.isObject(Y.lp.app.foldables,
252+ 'Foldable should be found');
253+ },
254+
255+ test_inserts_ellipsis: function () {
256+ this._add_comment(longer_comment);
257+ Y.lp.app.foldables.activate();
258+ Y.Assert.isObject(Y.one('a'));
259+ Y.Assert.areSame('[...]', Y.one('a').getContent());
260+ },
261+
262+ test_hides_quote: function () {
263+ this._add_comment(longer_comment);
264+ Y.lp.app.foldables.activate();
265+ var quote = Y.one('.foldable-quoted');
266+ Y.Assert.areSame(quote.getStyle('display'), 'none');
267+ },
268+
269+ test_doesnt_hide_short: function () {
270+ debugger;
271+ this._add_comment(quote_comment);
272+ Y.lp.app.foldables.activate();
273+ Y.Assert.isNull(Y.one('a'));
274+ var quote = Y.one('.foldable-quoted');
275+ // this one should be visible since it's only 12 lines
276+ Y.Assert.areSame(quote.getStyle('display'), 'inline');
277+ },
278+
279+ test_clicking_link_shows: function () {
280+ this._add_comment(longer_comment);
281+ Y.lp.app.foldables.activate();
282+
283+ var quote = Y.one('.foldable-quoted');
284+ // it should be hidden to start since it's 13 lines long
285+ Y.Assert.areSame(quote.getStyle('display'), 'none');
286+
287+ var link = Y.one('a');
288+ link.simulate('click');
289+ var quote = Y.one('.foldable-quoted');
290+ Y.Assert.areSame(quote.getStyle('display'), 'inline');
291+
292+ // Make sure that if clicked again it hides.
293+ link.simulate('click');
294+ Y.Assert.areSame(quote.getStyle('display'), 'none');
295+ },
296+
297+ test_foldable: function () {
298+ this._add_comment(foldable_comment);
299+ Y.lp.app.foldables.activate();
300+ var link = Y.one('a');
301+ link.simulate('click');
302+
303+ var quote = Y.one('.foldable');
304+ Y.Assert.areSame(quote.getStyle('display'), 'inline');
305+
306+ // Make sure that if clicked again it hides.
307+ link.simulate('click');
308+ Y.Assert.areSame(quote.getStyle('display'), 'none');
309+ }
310+ }));
311+
312+ test_foldables.suite = suite;
313+
314+}, '0.1', {
315+ requires: ['test', 'node-event-simulate', 'node', 'lp.app.foldables']
316+});
317
318=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
319--- lib/lp/app/templates/base-layout-macros.pt 2012-01-06 12:34:37 +0000
320+++ lib/lp/app/templates/base-layout-macros.pt 2012-01-10 17:43:30 +0000
321@@ -115,13 +115,14 @@
322 </script>
323
324 <script id="base-layout-load-scripts" type="text/javascript">
325- LPS.use('node', 'event-delegate', 'lp', 'lp.app.links', 'lp.app.longpoll',
326- 'lp.app.inlinehelp', function(Y) {
327+ LPS.use('node', 'event-delegate', 'lp', 'lp.app.foldables', 'lp.app.links',
328+ 'lp.app.longpoll', 'lp.app.inlinehelp', function(Y) {
329 Y.on('load', function(e) {
330 sortables_init();
331 Y.lp.app.inlinehelp.init_help();
332 Y.lp.activate_collapsibles();
333- activateFoldables();
334+ Y.lp.app.foldables.activate();
335+
336 activateConstrainBugExpiration();
337 Y.lp.app.links.check_valid_lp_links();
338 // Longpolling will only start if