~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/registry/javascript/distroseries/differences.js

[r=allenap][bug=815788] On DistroSeries:+localpackagediffs ensure
        that links dynamically added from JavaScript have a similar
        visual appearance and behaviour to others on Launchpad.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Copyright 2011 Canonical Ltd. This software is licensed under the
3
3
 * GNU Affero General Public License version 3 (see the file LICENSE).
4
4
 *
5
 
 * DistroSeries Initialization.
 
5
 * DistroSeries Differences.
6
6
 *
7
7
 * @module lp.registry.distroseries
8
8
 * @submodule differences
13
13
Y.log('loading lp.registry.distroseries.differences');
14
14
 
15
15
var namespace = Y.namespace('lp.registry.distroseries.differences'),
 
16
    testspace = Y.namespace('lp.registry.distroseries.differences.test'),
16
17
    formwidgets = Y.lp.app.formwidgets,
17
18
    widgets = Y.lp.registry.distroseries.widgets;
18
19
 
19
20
var PACKAGESET_FIELD = "field.packageset",
20
 
    PACKAGESET_FIELD_SELECTOR = "input[name=" + PACKAGESET_FIELD + "]";
 
21
    PACKAGESET_FIELD_SELECTOR = "input[name=" + PACKAGESET_FIELD + "]",
 
22
    CHANGED_BY_FIELD = "field.changed_by",
 
23
    CHANGED_BY_FIELD_SELECTOR = "input[name=" + CHANGED_BY_FIELD + "]";
21
24
 
22
25
 
23
26
/**
51
54
 
52
55
 
53
56
/**
 
57
 * Return the first field.changed_by value from the current window's
 
58
 * query string.
 
59
 *
 
60
 * @param {String} qs The query string, typically obtained from
 
61
 *     window.location.search.
 
62
 */
 
63
var get_changed_by_in_query = function(qs) {
 
64
    var query = Y.QueryString.parse(qs.replace(/^[?]/, ""));
 
65
    var changed_by = query[CHANGED_BY_FIELD];
 
66
    if (Y.Lang.isArray(changed_by)) {
 
67
        return changed_by[0];
 
68
    }
 
69
    else if (Y.Lang.isValue(changed_by)) {
 
70
        return changed_by;
 
71
    }
 
72
    else {
 
73
        return null;
 
74
    }
 
75
};
 
76
 
 
77
 
 
78
/**
 
79
 * Convert the content of the given node into a js-action link.
 
80
 *
 
81
 * I would rather not do this with innerHTML, but I can't figure out
 
82
 * how to get YUI3 to wrap the contents of a node with another node,
 
83
 * including text nodes*.
 
84
 *
 
85
 * Also, node.get("text") is broken; given <a>foo<b/>bar</a>,
 
86
 * a.get("text") will return "foobar".
 
87
 *
 
88
 * @param {Y.Node} node The node to linkify.
 
89
 *
 
90
 */
 
91
var linkify = function(node) {
 
92
    /* Set the href so that the visual display is consistent with
 
93
       other links (cursor most notably). */
 
94
    var link = Y.Node.create(
 
95
        '<a href="#" class="js-action sprite edit" />');
 
96
    link.set("innerHTML", node.get("innerHTML"));
 
97
    node.empty().append(link);
 
98
    return link;
 
99
};
 
100
 
 
101
 
 
102
/**
54
103
 * Wire up a packageset picker that updates the given form.
55
104
 *
56
105
 * @param {Y.Node} origin The node that, when clicked, should activate
120
169
    var reposition_overlay = function() {
121
170
        /* Trigger alignment and constrain to the viewport. Should
122
171
           these not be automatic? Perhaps a bad interaction between
123
 
           widget-position-align and widget-position-constrain? Only
 
172
           widget-position-align and widget-positionposition-constrain? Only
124
173
           reposition when overlay is visible. */
125
174
        if (overlay.get("visible")) {
126
175
            overlay.set("align", overlay.get("align"));
147
196
       populated with choices. */
148
197
    overlay.after("visibleChange", initialize_picker);
149
198
 
150
 
    /* Convert the content of the origin into a js-action link, and
151
 
       show the overlay when it's clicked. I would rather not do this
152
 
       with innerHTML, but I can't figure out how to get YUI3 to wrap
153
 
       the contents of a node with another node, *including text
154
 
       nodes*. Also, node.get("text") is broken; given
155
 
       <a>foo<b/>bar</a>, a.get("text") will return "foobar". */
156
 
    var link = Y.Node.create('<a class="js-action sprite edit" />');
157
 
    link.set("innerHTML", origin.get("innerHTML"));
158
 
    link.on("click", function() { overlay.show(); });
159
 
    origin.empty().append(link);
 
199
    /* Linkify the origin and show the overlay when it's clicked. */
 
200
    linkify(origin).on("click", function(e) {
 
201
        e.halt();
 
202
        overlay.show();
 
203
    });
 
204
};
 
205
 
 
206
 
 
207
/**
 
208
 * Wire up a person picker that updates the given form.
 
209
 *
 
210
 * @param {Y.Node} origin The node that, when clicked, should activate
 
211
 *     the picker.
 
212
 * @param {Y.Node} form The form that the picker should update.
 
213
 */
 
214
var connect_last_changed_picker = function(origin, form) {
 
215
    var config = {
 
216
        picker_type: "person",
 
217
        header: "Choose a person or a team",
 
218
        visible: false
 
219
    };
 
220
    var picker = new Y.lp.app.picker.create("ValidPersonOrTeam", config);
 
221
 
 
222
    /* Align the centre of the overlay with the centre of the origin
 
223
       node. */
 
224
    var align = {
 
225
        node: origin,
 
226
        points: [
 
227
            Y.WidgetPositionAlign.CC,
 
228
            Y.WidgetPositionAlign.CC
 
229
        ]
 
230
    };
 
231
 
 
232
    /* lazr.picker.Picker sets centered to true each time the picker
 
233
       is shown. Not happy. Killing it with fire^W preventDefault. */
 
234
    picker.on("centeredChange", function(e) { e.preventDefault(); });
 
235
 
 
236
    /* XXX: GavinPanella 2011-07-27 bug=817091: Alignment must be done
 
237
       after creating the picker because lp.app.picker.create()
 
238
       clobbers the passed configuration. */
 
239
 
 
240
    /* Pre-fill the search box with an existing selection. */
 
241
    picker.after("visibleChange", function(e) {
 
242
        if (e.newVal) {
 
243
            picker.set("align", align);  // Arg.
 
244
            var changed_by = get_changed_by_in_query(window.location.search);
 
245
            if (Y.Lang.isValue(changed_by)) {
 
246
                picker._search_input.set("value", changed_by);
 
247
            }
 
248
        }
 
249
    });
 
250
 
 
251
    /* When the picker is saved the search filter form is modified and
 
252
       submitted. */
 
253
    picker.on("save", function(e) {
 
254
        form.all(CHANGED_BY_FIELD_SELECTOR).remove();
 
255
        if (e.value) {
 
256
            form.append(
 
257
                Y.Node.create('<input type="hidden" />')
 
258
                    .set("name", CHANGED_BY_FIELD)
 
259
                    .set("value", e.value));
 
260
        }
 
261
        form.submit();
 
262
    });
 
263
 
 
264
    /* Linkify the origin and show the picker when it's clicked. */
 
265
    linkify(origin).on("click", function(e) {
 
266
        e.halt();
 
267
        picker.show();
 
268
    });
 
269
 
 
270
    return picker;
160
271
};
161
272
 
162
273
 
163
274
// Exports.
164
275
namespace.connect_packageset_picker = connect_packageset_picker;
165
 
 
166
 
 
167
 
}, "0.1", {
168
 
    "requires": [
169
 
        "node",
170
 
        "querystring-parse",
171
 
        "lazr.formoverlay",
172
 
        "lp.app.formwidgets",
173
 
        "lp.registry.distroseries.widgets"
174
 
    ]});
 
276
namespace.connect_last_changed_picker = connect_last_changed_picker;
 
277
 
 
278
 
 
279
// Exports for testing.
 
280
testspace.get_packagesets_in_query = get_packagesets_in_query;
 
281
testspace.get_changed_by_in_query = get_changed_by_in_query;
 
282
testspace.linkify = linkify;
 
283
 
 
284
 
 
285
}, "0.1", {"requires": [
 
286
               "lazr.formoverlay", "lp.app.formwidgets",
 
287
               "lp.app.picker", "lp.registry.distroseries.widgets",
 
288
               "node", "querystring-parse"]});