1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
/**
* Copyright 2011 Canonical Ltd. This software is licensed under the
* GNU Affero General Public License version 3 (see the file LICENSE).
*
* DistroSeries Initialization.
*
* @module lp.registry.distroseries
* @submodule differences
*/
YUI.add('lp.registry.distroseries.differences', function(Y) {
Y.log('loading lp.registry.distroseries.differences');
var namespace = Y.namespace('lp.registry.distroseries.differences'),
formwidgets = Y.lp.app.formwidgets,
widgets = Y.lp.registry.distroseries.widgets;
var PACKAGESET_FIELD = "field.packageset",
PACKAGESET_FIELD_SELECTOR = "input[name=" + PACKAGESET_FIELD + "]";
/**
* Return an array of the packageset IDs that are configured in the
* current window's query string.
*
* @param {String} qs The query string, typically obtained from
* window.location.search.
*/
var get_packagesets_in_query = function(qs) {
var query = Y.QueryString.parse(qs.replace(/^[?]/, ""));
/* Y.QueryString.parse() tries to be helpful and convert
numeral strings into numbers... but we don't want that,
so we have to convert back again. */
var packagesets = query[PACKAGESET_FIELD];
var n2s = function(n) { return n.toString(10); };
/* Y.QueryString.parse() tries to be even more helpful by
returning multiple values in an array but single values *not*
in an array... I wonder why I'm using Y.QueryString.parse() at
all. */
if (Y.Lang.isArray(packagesets)) {
return packagesets.map(n2s);
}
else if (Y.Lang.isValue(packagesets)) {
return [n2s(packagesets)];
}
else {
return [];
}
};
/**
* Wire up a packageset picker that updates the given form.
*
* @param {Y.Node} origin The node that, when clicked, should activate
* the picker.
* @param {Y.Node} form The form that the picker should update.
*/
var connect_packageset_picker = function(origin, form) {
var picker_table =
Y.Node.create("<table><tbody /></table>");
var picker =
new widgets.PackagesetPickerWidget()
.set("name", "packagesets")
.set("size", 5)
.set("multiple", true)
.render(picker_table.one("tbody"));
picker.add_distroseries({
api_uri: LP.cache.context.self_link,
title: LP.cache.context.title,
value: LP.cache.context.self_link
});
/* Buttons */
var submit_button = Y.Node.create(
'<button type="submit" class="lazr-pos lazr-btn" />')
.set("text", "OK");
var cancel_button = Y.Node.create(
'<button type="button" class="lazr-neg lazr-btn" />')
.set("text", "Cancel");
/* When the form overlay is submitted the search filter form is
modified and submitted. */
var submit_callback = function(data) {
// Remove all packagesets information previously recorded.
form.all(PACKAGESET_FIELD_SELECTOR).remove();
if (data.packagesets !== undefined) {
Y.each(data.packagesets, function(packageset) {
form.append(
Y.Node.create('<input type="hidden" />')
.set("name", PACKAGESET_FIELD)
.set("value", packageset));
});
}
form.submit();
};
/* Form overlay. */
var overlay = new Y.lazr.FormOverlay({
align: {
/* Align the centre of the overlay with the centre of the
origin node. */
node: origin,
points: [
Y.WidgetPositionAlign.CC,
Y.WidgetPositionAlign.CC
]
},
headerContent: "<h2>Select package sets</h2>",
form_content: picker_table,
form_submit_button: submit_button,
form_cancel_button: cancel_button,
form_submit_callback: submit_callback,
visible: false
});
overlay.render();
var reposition_overlay = function() {
/* Trigger alignment and constrain to the viewport. Should
these not be automatic? Perhaps a bad interaction between
widget-position-align and widget-position-constrain? Only
reposition when overlay is visible. */
if (overlay.get("visible")) {
overlay.set("align", overlay.get("align"));
overlay.constrain(null, true);
}
};
overlay.after("visibleChange", reposition_overlay);
Y.on("windowresize", reposition_overlay);
var packagesets_in_query =
get_packagesets_in_query(window.location.search);
var initialize_picker = function() {
/* Set the current selection from the query string. Only
initialize when overlay is visible. */
if (overlay.get("visible")) {
picker.set("choice", packagesets_in_query);
}
};
/* XXX: GavinPanella 2011-07-20 bug=814531: We should be able to
listen to choicesChange events from the picker widget but
they're not fired consistently. Instead we initialize when
showing the overlay, which is prone to a race condition (it may
update the selection before the packageset picker has been
populated with choices. */
overlay.after("visibleChange", initialize_picker);
/* Convert the content of the origin into a js-action link, and
show the overlay when it's clicked. I would rather not do this
with innerHTML, but I can't figure out how to get YUI3 to wrap
the contents of a node with another node, *including text
nodes*. Also, node.get("text") is broken; given
<a>foo<b/>bar</a>, a.get("text") will return "foobar". */
var link = Y.Node.create('<a class="js-action sprite edit" />');
link.set("innerHTML", origin.get("innerHTML"));
link.on("click", function() { overlay.show(); });
origin.empty().append(link);
};
// Exports.
namespace.connect_packageset_picker = connect_packageset_picker;
}, "0.1", {
"requires": [
"node",
"querystring-parse",
"lazr.formoverlay",
"lp.app.formwidgets",
"lp.registry.distroseries.widgets"
]});
|