Merge lp:~mars/launchpad/unroll-mochikit into lp:launchpad

Proposed by Paul Hummer
Status: Merged
Approved by: Robert Collins
Approved revision: 10204
Merge reported by: Paul Hummer
Merged at revision: not available
Proposed branch: lp:~mars/launchpad/unroll-mochikit
Merge into: lp:launchpad
Diff against target: 865 lines (+396/-396)
4 files modified
Makefile (+0/-1)
lib/canonical/launchpad/javascript/lp/lp-mochi.js (+383/-0)
lib/canonical/launchpad/javascript/lp/lp.js (+0/-392)
lib/lp/app/templates/base-layout-macros.pt (+13/-3)
To merge this branch: bzr merge lp:~mars/launchpad/unroll-mochikit
Reviewer Review Type Date Requested Status
Paul Hummer (community) Approve
Review via email: mp+17870@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) :
review: Approve
lp:~mars/launchpad/unroll-mochikit updated
10204. By Māris Fogels

Added the core Launchpad MochiKit dependant JS modules to the devmode script set.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Makefile'
2--- Makefile 2010-01-11 20:57:16 +0000
3+++ Makefile 2010-01-22 14:00:33 +0000
4@@ -126,7 +126,6 @@
5 -n launchpad \
6 -s lib/canonical/launchpad/javascript \
7 -b $(LP_BUILT_JS_ROOT) \
8- lib/canonical/launchpad/icing/MochiKit.js \
9 $(shell $(HERE)/utilities/yui-deps.py) \
10 lib/canonical/launchpad/icing/lazr/build/lazr.js
11
12
13=== added file 'lib/canonical/launchpad/javascript/lp/lp-mochi.js'
14--- lib/canonical/launchpad/javascript/lp/lp-mochi.js 1970-01-01 00:00:00 +0000
15+++ lib/canonical/launchpad/javascript/lp/lp-mochi.js 2010-01-22 14:00:33 +0000
16@@ -0,0 +1,383 @@
17+// Copyright 2010 Canonical Ltd. All rights reserved.
18+//
19+// Launchpad JavaScript core functions that require the MochiKit library.
20+
21+function getContentArea() {
22+ // to end all doubt on where the content sits. It also felt a bit
23+ // silly doing this over and over in every function, even if it is
24+ // a tiny operation. Just guarding against someone changing the
25+ // names again, in the name of semantics or something.... ;)
26+ var node = document.getElementById('maincontent');
27+ if (!node) {node = $('content');}
28+ if (!node) {node = $('mainarea');}
29+ return node;
30+}
31+
32+function toggleCollapsible(e) {
33+ // this is the function that collapses/expands fieldsets.
34+
35+ // "this" is the node that the event is attached to
36+ var node = this;
37+
38+ // walk up the node hierarchy until we find the <legend> element
39+ while (node.nodeName.toLowerCase() != 'legend') {
40+ node = node.parentNode;
41+ if (!node) {
42+ return false;
43+ }
44+ }
45+
46+ // the expander image is legend -> a -> img
47+ var icon = node.firstChild.firstChild;
48+ var legend = node;
49+
50+ if (icon.getAttribute('src').indexOf('/@@/treeCollapsed') != -1) {
51+ // that was an ugly check, but IE rewrites image sources to
52+ // absolute urls from some sick reason....
53+ icon.setAttribute('src','/@@/treeExpanded');
54+ swapElementClass(
55+ legend.parentNode.lastChild, 'collapsed', 'expanded');
56+ swapElementClass(
57+ legend.parentNode.childNodes[1], 'expanded', 'collapsed');
58+ } else {
59+ icon.setAttribute('src','/@@/treeCollapsed');
60+ swapElementClass(
61+ legend.parentNode.lastChild, 'expanded', 'collapsed');
62+ swapElementClass(
63+ legend.parentNode.childNodes[1], 'collapsed', 'expanded');
64+ }
65+ return false;
66+}
67+
68+function activateCollapsibles() {
69+ // a script that searches for sections that can be (or are
70+ // already) collapsed - and enables the collapse-behavior
71+
72+ // usage : give the class "collapsible" to a fieldset also, give
73+ // it a <legend> with some descriptive text. you can also add the
74+ // class "collapsed" amounting to a total of
75+ // <fieldset class="collapsible collapsed"> to make the section
76+ // pre-collapsed
77+
78+ // terminate if we hit a non-compliant DOM implementation
79+ if (!document.getElementsByTagName) {
80+ return false;
81+ }
82+ if (!document.getElementById) {
83+ return false;
84+ }
85+
86+ // only search in the content-area
87+ var contentarea = getContentArea();
88+ if (!contentarea) {
89+ return false;
90+ }
91+
92+ // gather all objects that are to be collapsed
93+ // we only do fieldsets for now. perhaps DIVs later...
94+ var collapsibles = contentarea.getElementsByTagName('fieldset');
95+
96+ for (var i = 0; i < collapsibles.length; i++) {
97+ if (collapsibles[i].className.indexOf('collapsible') == -1) {
98+ continue;
99+ }
100+
101+ var legends = collapsibles[i].getElementsByTagName('LEGEND');
102+
103+ // get the legend
104+ // if there is no legend, we do not touch the fieldset at all.
105+ // we assume that if there is a legend, there is only
106+ // one. nothing else makes any sense
107+ if (!legends.length) {
108+ continue;
109+ }
110+ var legend = legends[0];
111+
112+ //create an anchor to handle click-events
113+ var anchor = document.createElement('a');
114+ anchor.href = '#';
115+ anchor.onclick = toggleCollapsible;
116+
117+ // add the icon/button with its functionality to the legend
118+ var icon = document.createElement('img');
119+ icon.setAttribute('src','/@@/treeExpanded');
120+ icon.setAttribute('class','collapseIcon');
121+ icon.setAttribute('height','14');
122+ icon.setAttribute('width','14');
123+
124+ // insert the icon icon at the start of the anchor
125+ anchor.appendChild(icon);
126+
127+ // reparent all the legend's children into a span, and the span
128+ // into an anchor. The span is used to underline the legend
129+ // text; because the img is inside the anchor, we can't
130+ // underline the whole anchor.
131+ var span = document.createElement('span');
132+ while (legend.hasChildNodes()) {
133+ var child = legend.firstChild;
134+ legend.removeChild(child);
135+ span.appendChild(child);
136+ }
137+ anchor.appendChild(span);
138+
139+ // add the anchor to the legend
140+ legend.appendChild(anchor);
141+
142+ // wrap the contents inside a div to make turning them on and
143+ // off simpler. unless something very strange happens, this
144+ // new div should always be the last childnode we'll give it a
145+ // class to make sure.
146+
147+ var hiderWrapper = document.createElement('div');
148+ hiderWrapper.setAttribute('class','collapseWrapper');
149+
150+ // also add a new div describing that the element is collapsed.
151+ var collapsedDescription = document.createElement('div');
152+ collapsedDescription.setAttribute('class','collapsedText');
153+ collapsedDescription.style.display = 'none';
154+
155+ // if the fieldset has the class of "collapsed", pre-collapse
156+ // it. This can be used to preserve valuable UI-space
157+ if (collapsibles[i].className.indexOf('collapsed') != -1 ) {
158+ icon.setAttribute('src','/@@/treeCollapsed');
159+ collapsedDescription.style.display = 'block';
160+ setElementClass(hiderWrapper, 'collapsed');
161+ // Unhide the fieldset, now that all of its children are hidden:
162+ removeElementClass(collapsibles[i], 'collapsed');
163+ }
164+
165+ // now we have the wrapper div.. Stuff all the contents inside it
166+ var nl = collapsibles[i].childNodes.length;
167+ for (var j = 0; j < nl; j++){
168+ var node = collapsibles[i].childNodes[0];
169+ if (node.nodeName == 'LEGEND') {
170+ if (collapsibles[i].childNodes.length > 1) {
171+ hiderWrapper.appendChild(collapsibles[i].childNodes[1]);
172+ }
173+ } else {
174+ hiderWrapper.appendChild(collapsibles[i].childNodes[0]);
175+ }
176+ }
177+ // and add it to the document
178+ collapsibles[i].appendChild(hiderWrapper);
179+ collapsibles[i].insertBefore(collapsedDescription, hiderWrapper);
180+ }
181+}
182+
183+function toggleFoldable(e) {
184+ var ELEMENT_NODE = 1;
185+ var node = this;
186+ while (node.nextSibling) {
187+ node = node.nextSibling;
188+ if (node.nodeType != ELEMENT_NODE) {
189+ continue;
190+ }
191+ if (node.className.indexOf('foldable') == -1) {
192+ continue;
193+ }
194+ if (node.style.display == 'none') {
195+ node.style.display = 'inline';
196+ } else {
197+ node.style.display = 'none';
198+ }
199+ }
200+}
201+
202+function activateFoldables() {
203+ // Create links to toggle the display of foldable content.
204+ var included = getElementsByTagAndClassName(
205+ 'span', 'foldable', document);
206+ var quoted = getElementsByTagAndClassName(
207+ 'span', 'foldable-quoted', document);
208+ var elements = concat(included, quoted);
209+ for (var i = 0; i < elements.length; i++) {
210+ var span = elements[i];
211+ if (span.className == 'foldable-quoted') {
212+ var quoted_lines = span.getElementsByTagName('br');
213+ if (quoted_lines && quoted_lines.length <= 11) {
214+ // We do not hide short quoted passages (12 lines) by default.
215+ continue;
216+ }
217+ }
218+
219+ var ellipsis = document.createElement('a');
220+ ellipsis.style.textDecoration = 'underline';
221+ ellipsis.href = VOID_URL;
222+ ellipsis.onclick = toggleFoldable;
223+ ellipsis.appendChild(document.createTextNode('[...]'));
224+
225+ span.parentNode.insertBefore(ellipsis, span);
226+ span.insertBefore(document.createElement('br'), span.firstChild);
227+ span.style.display = 'none';
228+ if (span.nextSibling) {
229+ // Text lines follows this span.
230+ var br = document.createElement('br');
231+ span.parentNode.insertBefore(br, span.nextSibling);
232+ }
233+ }
234+}
235+
236+function convertTextInputToTextArea(text_input_id, rows) {
237+ var current_text_input = getElement(text_input_id);
238+ var new_text_area = document.createElement("textarea");
239+ var attributes = {
240+ 'id': text_input_id,
241+ 'rows': rows,
242+ 'name': getNodeAttribute(current_text_input, 'name'),
243+ 'lang': getNodeAttribute(current_text_input, 'lang'),
244+ 'dir': getNodeAttribute(current_text_input, 'dir')
245+ };
246+
247+ updateNodeAttributes(new_text_area, attributes);
248+
249+ // we set the javascript events because updateNodeAttributes gets confused
250+ // with those events, because it says that 'event' is not defined. 'event'
251+ // is one of the arguments of the javascript call that is being copied.
252+ new_text_area.setAttribute(
253+ 'onKeyPress', getNodeAttribute(current_text_input, 'onkeypress'));
254+ new_text_area.setAttribute(
255+ 'onChange', getNodeAttribute(current_text_input, 'onchange'));
256+ new_text_area.value = current_text_input.value;
257+ swapDOM(current_text_input, new_text_area);
258+ return new_text_area;
259+}
260+
261+function upgradeToTextAreaForTranslation(text_input_id) {
262+ var rows = 6;
263+ var current_text_input = $(text_input_id);
264+ var text_area = convertTextInputToTextArea(text_input_id, rows);
265+ text_area.focus();
266+}
267+
268+function insertExpansionButton(expandable_field) {
269+ var button = createDOM(
270+ 'button', {
271+ 'style': 'padding: 0;',
272+ 'title': 'Makes the field larger, so you can see more text.'
273+ }
274+ );
275+ var icon = createDOM(
276+ 'img', {
277+ 'alt': 'Enlarge Field',
278+ 'src': '/+icing/translations-add-more-lines.gif'
279+ }
280+ );
281+ appendChildNodes(button, icon);
282+ function buttonOnClick(e) {
283+ upgradeToTextAreaForTranslation(expandable_field.id);
284+ e.preventDefault();
285+ removeElement(button);
286+ return false;
287+ }
288+ connect(button, 'onclick', buttonOnClick);
289+ insertSiblingNodesAfter(expandable_field, button);
290+}
291+
292+function insertAllExpansionButtons() {
293+ var expandable_fields = getElementsByTagAndClassName(
294+ 'input', 'expandable');
295+ forEach(expandable_fields, insertExpansionButton);
296+}
297+
298+function copyInnerHTMLById(from_id, to_id) {
299+ var from = getElement(from_id);
300+ var to = getElement(to_id);
301+
302+ // The replacement regex strips all tags from the html.
303+ to.value = unescapeHTML(from.innerHTML.replace(/<\/?[^>]+>/gi, ""));
304+
305+}
306+
307+function writeTextIntoPluralTranslationFields(from_id,
308+ to_id_pattern, nplurals) {
309+ // skip when x is 0, as that is the singular
310+ for (var x = 1; x < nplurals; x++) {
311+ var to_id = to_id_pattern + x + "_new";
312+ var to_select = to_id_pattern + x + "_new_select";
313+ copyInnerHTMLById(from_id, to_id);
314+ document.getElementById(to_select).checked = true;
315+ }
316+}
317+
318+function activateConstrainBugExpiration() {
319+ // Constrain enable_bug_expiration to the Launchpad Bugs radio input.
320+ // The Launchpad bug tracker is either the first item in a product's
321+ // bugtracker field, or it is a distribution's official_malone field.
322+ var bug_tracker_input = getElement('field.bugtracker.0');
323+ if (! bug_tracker_input) {
324+ bug_tracker_input = getElement('field.official_malone');
325+ }
326+ var bug_expiration_input = getElement('field.enable_bug_expiration');
327+ if (! bug_tracker_input || ! bug_expiration_input) {
328+ return;
329+ }
330+ // Disable enable_bug_expiration onload if Launchpad is not the
331+ // bug tracker.
332+ if (! bug_tracker_input.checked) {
333+ bug_expiration_input.disabled = true;
334+ }
335+ constraint = function (e) {
336+ if (bug_tracker_input.checked) {
337+ bug_expiration_input.disabled = false;
338+ bug_expiration_input.checked = true;
339+ } else {
340+ bug_expiration_input.checked = false;
341+ bug_expiration_input.disabled = true;
342+ }
343+ };
344+ var inputs = document.getElementsByTagName('input');
345+ for (var i = 0; i < inputs.length; i++) {
346+ if (inputs[i].name == 'field.bugtracker' ||
347+ inputs[i].name == 'field.official_malone') {
348+ inputs[i].onclick = constraint;
349+ }
350+ }
351+}
352+
353+function collapseRemoteCommentReply(comment_index) {
354+ var prefix = 'remote_comment_reply_';
355+ $(prefix + 'tree_icon_' + comment_index).src = '/@@/treeCollapsed';
356+ $(prefix + 'div_' + comment_index).style.display = 'none';
357+}
358+
359+function expandRemoteCommentReply(comment_index) {
360+ var prefix = 'remote_comment_reply_';
361+ $(prefix + 'tree_icon_' + comment_index).src = '/@@/treeExpanded';
362+ $(prefix + 'div_' + comment_index).style.display = 'block';
363+}
364+
365+function toggleRemoteCommentReply(comment_index) {
366+ var imgname = $('remote_comment_reply_tree_icon_' + comment_index)
367+ .src.split('/')
368+ .pop();
369+ var expanded = (imgname == 'treeExpanded');
370+ if (expanded) {
371+ collapseRemoteCommentReply(comment_index);
372+ } else {
373+ expandRemoteCommentReply(comment_index);
374+ }
375+}
376+
377+function connectRemoteCommentReply(comment_index) {
378+ YUI().use('event', function(Y) {
379+ var toggleFunc = function() {
380+ toggleRemoteCommentReply(comment_index);
381+ return false;
382+ };
383+
384+ var prefix = 'remote_comment_reply_expand_link_';
385+
386+ Y.on('load', function(e) {
387+ $(prefix + comment_index).onclick = toggleFunc;
388+ }, window);
389+ });
390+}
391+
392+function unescapeHTML(unescaped_string) {
393+ // Based on prototype's unescapeHTML method.
394+ // See launchpad bug #78788 for details.
395+ var div = document.createElement('div');
396+ div.innerHTML = unescaped_string;
397+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
398+}
399+
400
401=== modified file 'lib/canonical/launchpad/javascript/lp/lp.js'
402--- lib/canonical/launchpad/javascript/lp/lp.js 2009-12-07 12:26:37 +0000
403+++ lib/canonical/launchpad/javascript/lp/lp.js 2010-01-22 14:00:33 +0000
404@@ -245,221 +245,6 @@
405 });
406 }
407
408-function getContentArea() {
409- // to end all doubt on where the content sits. It also felt a bit
410- // silly doing this over and over in every function, even if it is
411- // a tiny operation. Just guarding against someone changing the
412- // names again, in the name of semantics or something.... ;)
413- var node = document.getElementById('maincontent');
414- if (!node) {node = $('content');}
415- if (!node) {node = $('mainarea');}
416- return node;
417-}
418-
419-function toggleCollapsible(e) {
420- // this is the function that collapses/expands fieldsets.
421-
422- // "this" is the node that the event is attached to
423- var node = this;
424-
425- // walk up the node hierarchy until we find the <legend> element
426- while (node.nodeName.toLowerCase() != 'legend') {
427- node = node.parentNode;
428- if (!node) {
429- return false;
430- }
431- }
432-
433- // the expander image is legend -> a -> img
434- var icon = node.firstChild.firstChild;
435- var legend = node;
436-
437- if (icon.getAttribute('src').indexOf('/@@/treeCollapsed') != -1) {
438- // that was an ugly check, but IE rewrites image sources to
439- // absolute urls from some sick reason....
440- icon.setAttribute('src','/@@/treeExpanded');
441- swapElementClass(
442- legend.parentNode.lastChild, 'collapsed', 'expanded');
443- swapElementClass(
444- legend.parentNode.childNodes[1], 'expanded', 'collapsed');
445- } else {
446- icon.setAttribute('src','/@@/treeCollapsed');
447- swapElementClass(
448- legend.parentNode.lastChild, 'expanded', 'collapsed');
449- swapElementClass(
450- legend.parentNode.childNodes[1], 'collapsed', 'expanded');
451- }
452- return false;
453-}
454-
455-function activateCollapsibles() {
456- // a script that searches for sections that can be (or are
457- // already) collapsed - and enables the collapse-behavior
458-
459- // usage : give the class "collapsible" to a fieldset also, give
460- // it a <legend> with some descriptive text. you can also add the
461- // class "collapsed" amounting to a total of
462- // <fieldset class="collapsible collapsed"> to make the section
463- // pre-collapsed
464-
465- // terminate if we hit a non-compliant DOM implementation
466- if (!document.getElementsByTagName) {
467- return false;
468- }
469- if (!document.getElementById) {
470- return false;
471- }
472-
473- // only search in the content-area
474- var contentarea = getContentArea();
475- if (!contentarea) {
476- return false;
477- }
478-
479- // gather all objects that are to be collapsed
480- // we only do fieldsets for now. perhaps DIVs later...
481- var collapsibles = contentarea.getElementsByTagName('fieldset');
482-
483- for (var i = 0; i < collapsibles.length; i++) {
484- if (collapsibles[i].className.indexOf('collapsible') == -1) {
485- continue;
486- }
487-
488- var legends = collapsibles[i].getElementsByTagName('LEGEND');
489-
490- // get the legend
491- // if there is no legend, we do not touch the fieldset at all.
492- // we assume that if there is a legend, there is only
493- // one. nothing else makes any sense
494- if (!legends.length) {
495- continue;
496- }
497- var legend = legends[0];
498-
499- //create an anchor to handle click-events
500- var anchor = document.createElement('a');
501- anchor.href = '#';
502- anchor.onclick = toggleCollapsible;
503-
504- // add the icon/button with its functionality to the legend
505- var icon = document.createElement('img');
506- icon.setAttribute('src','/@@/treeExpanded');
507- icon.setAttribute('class','collapseIcon');
508- icon.setAttribute('height','14');
509- icon.setAttribute('width','14');
510-
511- // insert the icon icon at the start of the anchor
512- anchor.appendChild(icon);
513-
514- // reparent all the legend's children into a span, and the span
515- // into an anchor. The span is used to underline the legend
516- // text; because the img is inside the anchor, we can't
517- // underline the whole anchor.
518- var span = document.createElement('span');
519- while (legend.hasChildNodes()) {
520- var child = legend.firstChild;
521- legend.removeChild(child);
522- span.appendChild(child);
523- }
524- anchor.appendChild(span);
525-
526- // add the anchor to the legend
527- legend.appendChild(anchor);
528-
529- // wrap the contents inside a div to make turning them on and
530- // off simpler. unless something very strange happens, this
531- // new div should always be the last childnode we'll give it a
532- // class to make sure.
533-
534- var hiderWrapper = document.createElement('div');
535- hiderWrapper.setAttribute('class','collapseWrapper');
536-
537- // also add a new div describing that the element is collapsed.
538- var collapsedDescription = document.createElement('div');
539- collapsedDescription.setAttribute('class','collapsedText');
540- collapsedDescription.style.display = 'none';
541-
542- // if the fieldset has the class of "collapsed", pre-collapse
543- // it. This can be used to preserve valuable UI-space
544- if (collapsibles[i].className.indexOf('collapsed') != -1 ) {
545- icon.setAttribute('src','/@@/treeCollapsed');
546- collapsedDescription.style.display = 'block';
547- setElementClass(hiderWrapper, 'collapsed');
548- // Unhide the fieldset, now that all of its children are hidden:
549- removeElementClass(collapsibles[i], 'collapsed');
550- }
551-
552- // now we have the wrapper div.. Stuff all the contents inside it
553- var nl = collapsibles[i].childNodes.length;
554- for (var j = 0; j < nl; j++){
555- var node = collapsibles[i].childNodes[0];
556- if (node.nodeName == 'LEGEND') {
557- if (collapsibles[i].childNodes.length > 1) {
558- hiderWrapper.appendChild(collapsibles[i].childNodes[1]);
559- }
560- } else {
561- hiderWrapper.appendChild(collapsibles[i].childNodes[0]);
562- }
563- }
564- // and add it to the document
565- collapsibles[i].appendChild(hiderWrapper);
566- collapsibles[i].insertBefore(collapsedDescription, hiderWrapper);
567- }
568-}
569-
570-function toggleFoldable(e) {
571- var ELEMENT_NODE = 1;
572- var node = this;
573- while (node.nextSibling) {
574- node = node.nextSibling;
575- if (node.nodeType != ELEMENT_NODE) {
576- continue;
577- }
578- if (node.className.indexOf('foldable') == -1) {
579- continue;
580- }
581- if (node.style.display == 'none') {
582- node.style.display = 'inline';
583- } else {
584- node.style.display = 'none';
585- }
586- }
587-}
588-
589-function activateFoldables() {
590- // Create links to toggle the display of foldable content.
591- var included = getElementsByTagAndClassName(
592- 'span', 'foldable', document);
593- var quoted = getElementsByTagAndClassName(
594- 'span', 'foldable-quoted', document);
595- var elements = concat(included, quoted);
596- for (var i = 0; i < elements.length; i++) {
597- var span = elements[i];
598- if (span.className == 'foldable-quoted') {
599- var quoted_lines = span.getElementsByTagName('br');
600- if (quoted_lines && quoted_lines.length <= 11) {
601- // We do not hide short quoted passages (12 lines) by default.
602- continue;
603- }
604- }
605-
606- var ellipsis = document.createElement('a');
607- ellipsis.style.textDecoration = 'underline';
608- ellipsis.href = VOID_URL;
609- ellipsis.onclick = toggleFoldable;
610- ellipsis.appendChild(document.createTextNode('[...]'));
611-
612- span.parentNode.insertBefore(ellipsis, span);
613- span.insertBefore(document.createElement('br'), span.firstChild);
614- span.style.display = 'none';
615- if (span.nextSibling) {
616- // Text lines follows this span.
617- var br = document.createElement('br');
618- span.parentNode.insertBefore(br, span.nextSibling);
619- }
620- }
621-}
622-
623 function toggleExpandableTableRow(element_id) {
624 var row = document.getElementById(element_id);
625 var view_icon = document.getElementById(element_id + "-arrow");
626@@ -557,98 +342,6 @@
627 document.getElementById(widget_name).checked = true;
628 }
629
630-
631-function convertTextInputToTextArea(text_input_id, rows) {
632- var current_text_input = getElement(text_input_id);
633- var new_text_area = document.createElement("textarea");
634- var attributes = {
635- 'id': text_input_id,
636- 'rows': rows,
637- 'name': getNodeAttribute(current_text_input, 'name'),
638- 'lang': getNodeAttribute(current_text_input, 'lang'),
639- 'dir': getNodeAttribute(current_text_input, 'dir')
640- };
641-
642- updateNodeAttributes(new_text_area, attributes);
643-
644- // we set the javascript events because updateNodeAttributes gets confused
645- // with those events, because it says that 'event' is not defined. 'event'
646- // is one of the arguments of the javascript call that is being copied.
647- new_text_area.setAttribute(
648- 'onKeyPress', getNodeAttribute(current_text_input, 'onkeypress'));
649- new_text_area.setAttribute(
650- 'onChange', getNodeAttribute(current_text_input, 'onchange'));
651- new_text_area.value = current_text_input.value;
652- swapDOM(current_text_input, new_text_area);
653- return new_text_area;
654-}
655-
656-
657-function upgradeToTextAreaForTranslation(text_input_id) {
658- var rows = 6;
659- var current_text_input = $(text_input_id);
660- var text_area = convertTextInputToTextArea(text_input_id, rows);
661- text_area.focus();
662-}
663-
664-function insertExpansionButton(expandable_field) {
665- var button = createDOM(
666- 'button', {
667- 'style': 'padding: 0;',
668- 'title': 'Makes the field larger, so you can see more text.'
669- }
670- );
671- var icon = createDOM(
672- 'img', {
673- 'alt': 'Enlarge Field',
674- 'src': '/+icing/translations-add-more-lines.gif'
675- }
676- );
677- appendChildNodes(button, icon);
678- function buttonOnClick(e) {
679- upgradeToTextAreaForTranslation(expandable_field.id);
680- e.preventDefault();
681- removeElement(button);
682- return false;
683- }
684- connect(button, 'onclick', buttonOnClick);
685- insertSiblingNodesAfter(expandable_field, button);
686-}
687-
688-function insertAllExpansionButtons() {
689- var expandable_fields = getElementsByTagAndClassName(
690- 'input', 'expandable');
691- forEach(expandable_fields, insertExpansionButton);
692-}
693-
694-function unescapeHTML(unescaped_string) {
695- // Based on prototype's unescapeHTML method.
696- // See launchpad bug #78788 for details.
697- var div = document.createElement('div');
698- div.innerHTML = unescaped_string;
699- return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
700-}
701-
702-function copyInnerHTMLById(from_id, to_id) {
703- var from = getElement(from_id);
704- var to = getElement(to_id);
705-
706- // The replacement regex strips all tags from the html.
707- to.value = unescapeHTML(from.innerHTML.replace(/<\/?[^>]+>/gi, ""));
708-
709-}
710-
711-function writeTextIntoPluralTranslationFields(from_id,
712- to_id_pattern, nplurals) {
713- // skip when x is 0, as that is the singular
714- for (var x = 1; x < nplurals; x++) {
715- var to_id = to_id_pattern + x + "_new";
716- var to_select = to_id_pattern + x + "_new_select";
717- copyInnerHTMLById(from_id, to_id);
718- document.getElementById(to_select).checked = true;
719- }
720-}
721-
722 function switchBugBranchFormAndWhiteboard(id) {
723 var div = document.getElementById('bugbranch' + id);
724 var wb = document.getElementById('bugbranch' + id + '-wb');
725@@ -703,92 +396,7 @@
726 return false;
727 }
728
729-function activateConstrainBugExpiration() {
730- // Constrain enable_bug_expiration to the Launchpad Bugs radio input.
731- // The Launchpad bug tracker is either the first item in a product's
732- // bugtracker field, or it is a distribution's official_malone field.
733- var bug_tracker_input = getElement('field.bugtracker.0');
734- if (! bug_tracker_input) {
735- bug_tracker_input = getElement('field.official_malone');
736- }
737- var bug_expiration_input = getElement('field.enable_bug_expiration');
738- if (! bug_tracker_input || ! bug_expiration_input) {
739- return;
740- }
741- // Disable enable_bug_expiration onload if Launchpad is not the
742- // bug tracker.
743- if (! bug_tracker_input.checked) {
744- bug_expiration_input.disabled = true;
745- }
746- constraint = function (e) {
747- if (bug_tracker_input.checked) {
748- bug_expiration_input.disabled = false;
749- bug_expiration_input.checked = true;
750- } else {
751- bug_expiration_input.checked = false;
752- bug_expiration_input.disabled = true;
753- }
754- };
755- var inputs = document.getElementsByTagName('input');
756- for (var i = 0; i < inputs.length; i++) {
757- if (inputs[i].name == 'field.bugtracker' ||
758- inputs[i].name == 'field.official_malone') {
759- inputs[i].onclick = constraint;
760- }
761- }
762-}
763-
764 function updateField(field, enabled)
765 {
766 field.disabled = !enabled;
767 }
768-
769-
770-function collapseRemoteCommentReply(comment_index) {
771- var prefix = 'remote_comment_reply_';
772- $(prefix + 'tree_icon_' + comment_index).src = '/@@/treeCollapsed';
773- $(prefix + 'div_' + comment_index).style.display = 'none';
774-}
775-
776-function expandRemoteCommentReply(comment_index) {
777- var prefix = 'remote_comment_reply_';
778- $(prefix + 'tree_icon_' + comment_index).src = '/@@/treeExpanded';
779- $(prefix + 'div_' + comment_index).style.display = 'block';
780-}
781-
782-function toggleRemoteCommentReply(comment_index) {
783- var imgname = $('remote_comment_reply_tree_icon_' + comment_index)
784- .src.split('/')
785- .pop();
786- var expanded = (imgname == 'treeExpanded');
787- if (expanded) {
788- collapseRemoteCommentReply(comment_index);
789- } else {
790- expandRemoteCommentReply(comment_index);
791- }
792-}
793-
794-function connectRemoteCommentReply(comment_index) {
795- YUI().use('event', function(Y) {
796- var toggleFunc = function() {
797- toggleRemoteCommentReply(comment_index);
798- return false;
799- };
800-
801- var prefix = 'remote_comment_reply_expand_link_';
802-
803- Y.on('load', function(e) {
804- $(prefix + comment_index).onclick = toggleFunc;
805- }, window);
806- });
807-}
808-
809-function switchDisplay(tag_id1, tag_id2) {
810- var tag1 = getElement(tag_id1);
811- var tag2 = getElement(tag_id2);
812- var display = tag1.style.display;
813- tag1.style.display = tag2.style.display;
814- tag2.style.display = display;
815- return false;
816-}
817-
818
819=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
820--- lib/lp/app/templates/base-layout-macros.pt 2010-01-08 21:39:00 +0000
821+++ lib/lp/app/templates/base-layout-macros.pt 2010-01-22 14:00:33 +0000
822@@ -52,6 +52,16 @@
823 do any initialization.
824 </tal:comment>
825
826+ <tal:comment>
827+ XXX mars 2010-01-21
828+ We have to load MochiKit outside of the main javascript rollup so that the
829+ rollup's size does not exceed 512Kb. That magic number triggers a bug
830+ somewhere in the automated test system that will prevent Windmill from
831+ executing.
832+ </tal:comment>
833+ <script type="text/javascript"
834+ tal:attributes="src string:${icingroot}/MochiKit.js"></script>
835+
836 <tal:devmode condition="devmode">
837
838 <tal:comment replace="nothing">
839@@ -80,7 +90,7 @@
840 <script type="text/javascript"
841 tal:attributes="src string:${yui}/event/event.js"></script>
842 <script type="text/javascript"
843- tal:attributes="src string:${yui}/event/event-key.js"></script>
844+ tal:attributes="src string:${yui}/event/event-key.js"></script>
845 <script type="text/javascript"
846 tal:attributes="src string:${yui}/event-custom/event-custom.js"></script>
847 <script type="text/javascript"
848@@ -133,8 +143,6 @@
849 tal:attributes="src string:${yui}/node-menunav/node-menunav.js"></script>
850
851 <script type="text/javascript"
852- tal:attributes="src string:${icingroot}/MochiKit.js"></script>
853- <script type="text/javascript"
854 tal:attributes="src string:${lazr_js}/lazr/lazr.js"></script>
855 <script type="text/javascript"
856 tal:attributes="src string:${lazr_js}/anim/anim.js"></script>
857@@ -158,6 +166,8 @@
858 <script type="text/javascript"
859 tal:attributes="src string:${lp_js}/lp/lp.js"></script>
860 <script type="text/javascript"
861+ tal:attributes="src string:${lp_js}/lp/lp-mochi.js"></script>
862+ <script type="text/javascript"
863 tal:attributes="src string:${lp_js}/lp/dragscroll.js"></script>
864 <script type="text/javascript"
865 tal:attributes="src string:${lp_js}/lp/picker.js"></script>