~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/services/inlinehelp/javascript/inlinehelp.js

  • Committer: Launchpad Patch Queue Manager
  • Date: 2012-01-06 17:11:54 UTC
  • mfrom: (14565.3.17 inline_help_907443)
  • Revision ID: launchpad@pqm.canonical.com-20120106171154-fjgapb91cd49zzih
[r=deryck][bug=907443] Port the inlinehelp javascript from mochikit
        to YUI in lp.app.inlinehelp.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2009 Canonical Ltd.  This software is licensed under the
3
 
 * GNU Affero General Public License version 3 (see the file LICENSE).
4
 
 *
5
 
 * This script defines functions for popping up a 'Help' dialog for an
6
 
 * external site.  All links that have a 'target="help"' attribute will
7
 
 * be turned into pop-up help links.  A single popup is present on the
8
 
 * screen at a time - opening another help link will open a new dialog,
9
 
 * and clicking on the same link again closes the dialog.
10
 
 *
11
 
 * This library depends on the MochiKit JavaScript library v1.4+.
12
 
 *
13
 
 */
14
 
 
15
 
 
16
 
/*
17
 
 * Page Setup
18
 
 */
19
 
 
20
 
 
21
 
function initInlineHelp() {
22
 
    /*
23
 
      Activate the popup help system by connecting all of the actionable
24
 
      page elements.
25
 
    */
26
 
    // The button is inserted in the page dynamically:
27
 
    // Changed from an <input type=button> to a <button> since
28
 
    // IE8 doesn't handle style.css's input{visibility:inherit} correctly.
29
 
    $('help-close').innerHTML =
30
 
        '<button id="help-close-btn">Close</button>';
31
 
    forEach(findHelpLinks(), setupHelpTrigger);
32
 
    initHelpPane();
33
 
}
34
 
 
35
 
function findHelpLinks() {
36
 
    /*
37
 
      Return all of the links in the document that have a target="help"
38
 
      attribute value.
39
 
    */
40
 
    has_help_target = function (elem) {
41
 
        return getNodeAttribute(elem, 'target') == 'help';
42
 
    };
43
 
    return filter(has_help_target,
44
 
                  currentDocument().getElementsByTagName('a'));
45
 
}
46
 
 
47
 
function setupHelpTrigger(elem) {
48
 
    /*
49
 
      Turn the specified element into a proper help link: add the
50
 
      'class="help"' attribute if it is missing, and connect the
51
 
      necessary event handlers.
52
 
    */
53
 
    // We want this to be idempotent, so we treat the 'help' class as a
54
 
    // marker.
55
 
    if (!hasElementClass(elem, 'help')) {
56
 
        addElementClass(elem, 'help');
57
 
        connect(elem, 'onclick', handleClickOnHelp);
58
 
    }
59
 
}
60
 
 
61
 
 
62
 
/*
63
 
 * Functions for using the help window.
64
 
 */
65
 
 
66
 
 
67
 
// We need to keep track of last element that triggered a help window.
68
 
var last_help_trigger = null;
69
 
 
70
 
 
71
 
function initHelpPane() {
72
 
    /*
73
 
      Link the popup help pane to its events, set its visibility, etc.
74
 
    */
75
 
    connect('help-close-btn', 'onclick', handleClickOnClose);
76
 
    dismissHelp();
77
 
}
78
 
 
79
 
function showHelpFor(trigger) {
80
 
    /*
81
 
      Show the help popup for a particular trigger element.
82
 
    */
83
 
 
84
 
    // Assume we are using an <iframe> for the help.
85
 
    // Also assume an <a> tag is the source, and we want to target the
86
 
    // <iframe> at its href.
87
 
 
88
 
    // Let our "Loading..." background gif show through.
89
 
    makeInvisible('help-pane-content');
90
 
 
91
 
    // Set our 'onload' event handler *outside* of the MochiKit.Signal
92
 
    // framework.  Normally we should not do this, but we need
93
 
    // to work around a bug where the 'onload' signal falls silent
94
 
    // for all events after the first.
95
 
    $('help-pane-content').onload = handleHelpLoaded;
96
 
 
97
 
    setNodeAttribute('help-pane-content', 'src', trigger.href);
98
 
 
99
 
    var help_pane = $('help-pane');
100
 
 
101
 
    /* The help pane is positioned in the center of the screen: */
102
 
    var viewport_dim = getViewportDimensions();
103
 
    var help_pane_dim = elementDimensions('help-pane');
104
 
    var pos_x = Math.round(viewport_dim.w / 2) - (help_pane_dim.w / 2);
105
 
    var pos_y = Math.round(viewport_dim.h / 2) - (help_pane_dim.h / 2);
106
 
    var viewport_pos = getViewportPosition();
107
 
    pos_y += viewport_pos.y;
108
 
    setElementPosition(help_pane, new Coordinates(pos_x, pos_y));
109
 
    makeVisible(help_pane);
110
 
 
111
 
    // XXX mars 2008-05-19
112
 
    // Work-around for MochiKit bug #274.  The previous call to
113
 
    // setElementPosition() sets "style=none;" as a side-effect!!!
114
 
    setStyle(help_pane, {'display': ''});
115
 
}
116
 
 
117
 
function dismissHelp() {
118
 
    makeInvisible('help-pane');
119
 
}
120
 
 
121
 
function handleClickOnHelp(event) {
122
 
    // We don't want <a> tags to navigate.
123
 
    event.stop();
124
 
    var trigger = event.src();
125
 
 
126
 
    if (!isVisible('help-pane')) {
127
 
        showHelpFor(trigger);
128
 
    } else if (trigger == last_help_trigger) {
129
 
        // Clicking on the same link that opened a help window closes it
130
 
        // again.
131
 
        dismissHelp();
132
 
    } else {
133
 
        // The user clicked on a different help link, so open it instead.
134
 
        dismissHelp();
135
 
        showHelpFor(trigger);
136
 
    }
137
 
    last_help_trigger = trigger;
138
 
}
139
 
 
140
 
function handleClickOnClose(event) {
141
 
    // Prevent the <a> tag from navigating.
142
 
    event.stop();
143
 
    dismissHelp();
144
 
}
145
 
 
146
 
function handleHelpLoaded(event) {
147
 
    /*
148
 
      Show the help contents after the help <iframe> has finished
149
 
      loading.
150
 
    */
151
 
    makeVisible('help-pane-content');
152
 
}
153
 
 
154
 
function handleClickOnPage(event) {
155
 
    /*
156
 
      Check to see if a click was inside a help window.  If it wasn't,
157
 
      and the window is open, then dismiss it.
158
 
    */
159
 
    var help = $('help-pane');
160
 
    if (isVisible(help) &&
161
 
        !isInside(event.mouse().page, help)) {
162
 
        dismissHelp();
163
 
    }
164
 
}
165
 
 
166
 
 
167
 
/*
168
 
 * Helpers and utility functions.
169
 
 */
170
 
 
171
 
 
172
 
function toggleVisible(elem) {
173
 
    toggleElementClass("invisible", elem);
174
 
}
175
 
 
176
 
function makeVisible(elem) {
177
 
    removeElementClass(elem, "invisible");
178
 
}
179
 
 
180
 
function makeInvisible(elem) {
181
 
    addElementClass(elem, "invisible");
182
 
}
183
 
 
184
 
function isVisible(elem) {
185
 
    // You may also want to check for:
186
 
    // getElement(elem).style.display == "none"
187
 
    return !hasElementClass(elem, "invisible");
188
 
}
189
 
 
190
 
function isInside(point, element) {
191
 
    /*
192
 
      Is 'point' inside the supplied 'element'?
193
 
    */
194
 
    return intersect(point,
195
 
                     getElementPosition(element),
196
 
                     getElementDimensions(element));
197
 
}
198
 
 
199
 
function intersect(point, dim_point, dimensions) {
200
 
    /*
201
 
      Is 'point' inside the box draw by 'dimensions' at point 'dim_point'?
202
 
    */
203
 
    return ((point.x > dim_point.x) &&
204
 
            (point.x < dim_point.x + dimensions.w) &&
205
 
            (point.y > dim_point.y) &&
206
 
            (point.y < dim_point.y + dimensions.h));
207
 
}