franck@1
|
1 // $Id: popups.js,v 1.9.8.19 2010/12/10 02:51:17 drewish Exp $ |
franck@0
|
2 |
franck@0
|
3 /** |
franck@0
|
4 * Popup Modal Dialog API |
franck@0
|
5 * |
franck@0
|
6 * Provide an API for building and displaying JavaScript, in-page, popups modal dialogs. |
franck@0
|
7 * Modality is provided by a fixed, semi-opaque div, positioned in front of the page contents. |
franck@0
|
8 * |
franck@0
|
9 */ |
franck@0
|
10 |
franck@0
|
11 /* |
franck@0
|
12 * TODO |
franck@0
|
13 * * Return key in add node form not working. |
franck@0
|
14 * * Tabledrag breaking after ahah reload. |
franck@0
|
15 */ |
franck@0
|
16 |
franck@0
|
17 // *************************************************************************** |
franck@0
|
18 // DRUPAL Namespace |
franck@0
|
19 // *************************************************************************** |
franck@0
|
20 |
franck@0
|
21 /** |
franck@0
|
22 * Attach the popups bevior to the all the requested links on the page. |
franck@0
|
23 * |
franck@0
|
24 * @param context |
franck@0
|
25 * The jQuery object to apply the behaviors to. |
franck@0
|
26 */ |
franck@0
|
27 |
franck@0
|
28 Drupal.behaviors.popups = function(context) { |
franck@0
|
29 Popups.saveSettings(); |
franck@1
|
30 |
franck@0
|
31 var $body = $('body'); |
franck@0
|
32 if(!$body.hasClass('popups-processed')) { |
franck@0
|
33 $body.addClass('popups-processed'); |
franck@0
|
34 $(document).bind('keydown', Popups.keyHandle); |
franck@0
|
35 var $popit = $('#popit'); |
franck@0
|
36 if ($popit.length) { |
franck@0
|
37 $popit.remove(); |
franck@0
|
38 Popups.message($popit.html()); |
franck@0
|
39 } |
franck@1
|
40 |
franck@1
|
41 // Make note of all the CSS and JS on the page so when we load a popup we |
franck@1
|
42 // don't try to add them a second time. |
franck@1
|
43 $('link[rel="stylesheet"][href]').each(function(i, v) { |
franck@1
|
44 Popups.originalCSS[$(this).attr('href').replace(/^(\/.+)\?\w$/, '$1')] = 1; |
franck@1
|
45 }); |
franck@1
|
46 if (Drupal.settings.popups && Drupal.settings.popups.originalCSS) { |
franck@1
|
47 $.extend(Popups.originalCSS, Drupal.settings.popups.originalCSS); |
franck@1
|
48 } |
franck@1
|
49 $('script[src]').each(function(i, v) { |
franck@1
|
50 Popups.originalJS[$(this).attr('src').replace(/^(\/.+)\?\w$/, '$1')] = 1; |
franck@1
|
51 }); |
franck@1
|
52 if (Drupal.settings.popups && Drupal.settings.popups.originalJS) { |
franck@1
|
53 $.extend(Popups.originalJS, Drupal.settings.popups.originalJS); |
franck@1
|
54 } |
franck@0
|
55 } |
franck@1
|
56 |
franck@0
|
57 // Add the popups-link-in-dialog behavior to links defined in Drupal.settings.popups.links array. |
franck@0
|
58 // Get these from current Drupal.settings, not Popups.originalSettings, as each page has it's own hooks. |
franck@0
|
59 if (Drupal.settings.popups && Drupal.settings.popups.links) { |
franck@1
|
60 jQuery.each(Drupal.settings.popups.links, function (link, options) { |
franck@0
|
61 Popups.attach(context, link, Popups.options(options)); |
franck@0
|
62 }); |
franck@0
|
63 } |
franck@1
|
64 |
franck@1
|
65 Popups.attach(context, '.popups', Popups.options({updateMethod: 'none'})); |
franck@0
|
66 Popups.attach(context, '.popups-form', Popups.options({updateMethod: 'ajax'})); // ajax reload. |
franck@1
|
67 Popups.attach(context, '.popups-form-reload', Popups.options({updateMethod: 'reload'})); // whole page reload. |
franck@0
|
68 Popups.attach(context, '.popups-form-noupdate', Popups.options({updateMethod: 'none'})); // no reload at all. |
franck@0
|
69 }; |
franck@0
|
70 |
franck@0
|
71 // *************************************************************************** |
franck@0
|
72 // Popups Namespace ********************************************************** |
franck@0
|
73 // *************************************************************************** |
franck@0
|
74 /** |
franck@0
|
75 * The Popups namespace contains: |
franck@0
|
76 * * An ordered stack of Popup objects, |
franck@0
|
77 * * The state of the original page, |
franck@0
|
78 * * Functions for managing both of the above. |
franck@0
|
79 */ |
franck@0
|
80 Popups = function(){}; |
franck@0
|
81 |
franck@0
|
82 /** |
franck@0
|
83 * Static variables in the Popups namespace. |
franck@0
|
84 */ |
franck@1
|
85 Popups.popupStack = []; |
franck@1
|
86 Popups.addedCSS = {}; |
franck@1
|
87 Popups.addedJS = {}; |
franck@1
|
88 Popups.originalCSS = {}; |
franck@1
|
89 Popups.originalJS = {}; |
franck@0
|
90 Popups.originalSettings = null; // The initial popup options of the page. |
franck@0
|
91 /** |
franck@0
|
92 * Each popup object gets it's own set of options. |
franck@0
|
93 * These are the defaults. |
franck@0
|
94 */ |
franck@0
|
95 Popups.defaultOptions = { |
franck@0
|
96 doneTest: null, // null, *path*, *regexp*. how do we know when a multiform flow is done? |
franck@0
|
97 updateMethod: 'ajax', // none, ajax, reload, *callback* |
franck@0
|
98 updateSource: 'initial', // initial, final. Only used if updateMethod != none. |
franck@1
|
99 onUpdate: '', // Only used if updateMethod == callback. |
franck@1
|
100 href: null, |
franck@0
|
101 width: null, // Override the width specified in the css. |
franck@0
|
102 targetSelectors: null, // Hash of jQuery selectors that define the content to be swapped out. |
franck@0
|
103 titleSelectors: null, // Array of jQuery selectors to place the new page title. |
franck@0
|
104 reloadOnError: false, // Force the entire page to reload if the popup href is unaccessable. |
franck@1
|
105 noMessage: false, // Don't show drupal_set_message messages. |
franck@1
|
106 skipDirtyCheck: false, // If true, this popup will not check for edits on the originating page. |
franck@1
|
107 hijackDestination: true // Use the destiination param to force a form submit to return to the originating page. |
franck@0
|
108 }; |
franck@0
|
109 |
franck@0
|
110 // *************************************************************************** |
franck@0
|
111 // Popups.Popup Object ******************************************************* |
franck@0
|
112 // *************************************************************************** |
franck@0
|
113 /** |
franck@0
|
114 * A Popup is a single modal dialog. |
franck@0
|
115 * The popup object encapslated all the info about a single popup. |
franck@0
|
116 */ |
franck@0
|
117 Popups.Popup = function() { |
franck@0
|
118 this.id = 'popups-' + Popups.nextCounter(); |
franck@1
|
119 |
franck@0
|
120 // These properties are needed if the popup contains a form that will be ajax submitted. |
franck@0
|
121 this.parent = null; // The popup that spawned this one. If parent is null, this popup was spawned by the original page. |
franck@0
|
122 this.path = null; // If popup is showing content from a url, this is that path. |
franck@0
|
123 this.element = null; // The DOM element that was clicked to launch this popup. |
franck@0
|
124 this.options = null; // An option array that control how the popup behaves. See Popups.defaultOptions for explainations. |
franck@0
|
125 }; |
franck@0
|
126 Popups.Popup.prototype.$popup = function() { |
franck@0
|
127 return $('#' + this.id); |
franck@0
|
128 }; |
franck@0
|
129 Popups.Popup.prototype.$popupBody = function() { |
franck@0
|
130 return $('#' + this.id + ' .popups-body'); |
franck@0
|
131 }; |
franck@0
|
132 Popups.Popup.prototype.$popupClose = function() { |
franck@0
|
133 return $('#' + this.id + ' .popups-close'); |
franck@0
|
134 }; |
franck@0
|
135 Popups.Popup.prototype.$popupTitle = function() { |
franck@0
|
136 return $('#' + this.id + ' .popups-title'); |
franck@0
|
137 }; |
franck@0
|
138 Popups.Popup.prototype.$popupButtons = function() { |
franck@0
|
139 return $('#' + this.id + ' .popups-buttons'); |
franck@0
|
140 }; |
franck@0
|
141 Popups.Popup.prototype.$popupFooter = function() { |
franck@0
|
142 return $('#' + this.id + ' .popups-footer'); |
franck@0
|
143 }; |
franck@0
|
144 |
franck@0
|
145 /** |
franck@0
|
146 * Create the jQuery wrapped html at the heart of the popup object. |
franck@1
|
147 * |
franck@0
|
148 * @param title |
franck@0
|
149 * String |
franck@0
|
150 * @param body |
franck@0
|
151 * String/HTML |
franck@0
|
152 * @param buttons |
franck@0
|
153 * Hash/Object |
franck@0
|
154 * @return |
franck@0
|
155 * The $popup. |
franck@0
|
156 */ |
franck@0
|
157 Popups.Popup.prototype.fill = function(title, body, buttons) { |
franck@0
|
158 return $(Drupal.theme('popupDialog', this.id, title, body, buttons)); |
franck@0
|
159 } |
franck@0
|
160 |
franck@0
|
161 /** |
franck@1
|
162 * Hide the popup by pushing it off to the side. |
franck@0
|
163 * Just making it display:none causes flash in FF2. |
franck@0
|
164 */ |
franck@0
|
165 Popups.Popup.prototype.hide = function() { |
franck@0
|
166 this.$popup().css('left', '-9999px'); |
franck@0
|
167 }; |
franck@0
|
168 |
franck@0
|
169 Popups.Popup.prototype.show = function() { |
franck@0
|
170 Popups.resizeAndCenter(this); |
franck@0
|
171 }; |
franck@0
|
172 |
franck@0
|
173 Popups.Popup.prototype.open = function(title, body, buttons, width){ |
franck@0
|
174 return Popups.open(this, title, body, buttons, width); |
franck@0
|
175 }; |
franck@0
|
176 |
franck@1
|
177 Popups.Popup.prototype.removePopup = function() { |
franck@0
|
178 Popups.removePopup(this); |
franck@1
|
179 }; |
franck@0
|
180 |
franck@0
|
181 /** |
franck@0
|
182 * Remove everything. |
franck@0
|
183 */ |
franck@0
|
184 Popups.Popup.prototype.close = function() { |
franck@0
|
185 return Popups.close(this); |
franck@0
|
186 }; |
franck@0
|
187 |
franck@0
|
188 /** |
franck@0
|
189 * Set the focus on the popups to the first visible, enabled form element, or the close link. |
franck@0
|
190 */ |
franck@0
|
191 Popups.Popup.prototype.refocus = function() { |
franck@0
|
192 // Select the first visible enabled input element. |
franck@0
|
193 var $popup = this.$popup(); |
franck@0
|
194 var $focus = $popup.find(':input:visible:enabled:first'); |
franck@0
|
195 if (!$focus.length) { |
franck@0
|
196 // There is no visible enabled input element, so select the close link. |
franck@0
|
197 $focus = $popup.find('.popups-close a'); |
franck@0
|
198 } |
franck@0
|
199 $focus.focus(); |
franck@0
|
200 }; |
franck@0
|
201 |
franck@0
|
202 /** |
franck@0
|
203 * Return a selector that will find target content on the layer that spawned this popup. |
franck@1
|
204 * This is needed for the popup to do ajax updates. |
franck@0
|
205 */ |
franck@0
|
206 Popups.Popup.prototype.targetLayerSelector = function() { |
franck@0
|
207 if (this.parent === null) { |
franck@0
|
208 return 'body'; // Select content in the original page. |
franck@0
|
209 } |
franck@0
|
210 else { |
franck@0
|
211 return '#' + this.parent.id; // Select content in the parent popup. |
franck@1
|
212 } |
franck@0
|
213 }; |
franck@0
|
214 |
franck@0
|
215 /** |
franck@0
|
216 * Determine if we are at an end point of a form flow, or just moving from one popups to another. |
franck@1
|
217 * |
franck@0
|
218 * @param path |
franck@0
|
219 * The path of the page that the form flow has moved to. |
franck@1
|
220 * This path is relative to the base_path. |
franck@0
|
221 * Ex: node/add/story, not http://localhost/drupal6/node/add/story or drupa6/node/add/story. |
franck@0
|
222 * @return bool |
franck@1
|
223 */ |
franck@0
|
224 Popups.Popup.prototype.isDone = function(path) { |
franck@0
|
225 var done; |
franck@0
|
226 if (this.options.doneTest) { |
franck@0
|
227 // Test if we are at the path specified by doneTest. |
franck@1
|
228 done = (path === this.options.doneTest || path.match(this.options.doneTest)); |
franck@0
|
229 } |
franck@1
|
230 else { |
franck@0
|
231 if (this.parent) { |
franck@0
|
232 // Test if we are back to the parent popup's path. |
franck@1
|
233 done = (path === this.parent.path); |
franck@0
|
234 } |
franck@0
|
235 else { |
franck@0
|
236 // Test if we are back to the original page's path. |
franck@0
|
237 done = (path === Popups.originalSettings.popups.originalPath); |
franck@0
|
238 } |
franck@1
|
239 }; |
franck@1
|
240 return done; |
franck@0
|
241 }; |
franck@0
|
242 |
franck@0
|
243 |
franck@0
|
244 // *************************************************************************** |
franck@0
|
245 // Popups Functions ********************************************************** |
franck@0
|
246 // *************************************************************************** |
franck@0
|
247 |
franck@0
|
248 /** |
franck@1
|
249 * Test if the param has been set. |
franck@0
|
250 * Used to distinguish between a value set to null or false and on not yet unset. |
franck@0
|
251 */ |
franck@0
|
252 Popups.isset = function(v) { |
franck@0
|
253 return (typeof(v) !== 'undefined'); |
franck@0
|
254 }; |
franck@0
|
255 |
franck@0
|
256 /** |
franck@0
|
257 * Get the currently active popup in the page. |
franck@0
|
258 * Currently it is the only one visible, but that could change. |
franck@0
|
259 */ |
franck@0
|
260 Popups.activePopup = function() { |
franck@0
|
261 if (Popups.popupStack.length) { |
franck@0
|
262 return Popups.popupStack[Popups.popupStack.length - 1]; // top of stack. |
franck@0
|
263 } |
franck@0
|
264 else { |
franck@0
|
265 return null; |
franck@0
|
266 } |
franck@0
|
267 }; |
franck@0
|
268 |
franck@0
|
269 /** |
franck@0
|
270 * Manage the page wide popupStack. |
franck@0
|
271 */ |
franck@0
|
272 Popups.push = function(popup) { |
franck@0
|
273 Popups.popupStack.push(popup); |
franck@0
|
274 }; |
franck@0
|
275 // Should I integrate this with popupRemove?? |
franck@0
|
276 Popups.pop = function(popup) { |
franck@0
|
277 return Popups.popupStack.pop(); |
franck@0
|
278 }; |
franck@0
|
279 |
franck@0
|
280 /** |
franck@0
|
281 * Build an options hash from defaults. |
franck@1
|
282 * |
franck@0
|
283 * @param overrides |
franck@0
|
284 * Hash of values to override the defaults. |
franck@0
|
285 */ |
franck@0
|
286 Popups.options = function(overrides) { |
franck@0
|
287 var defaults = Popups.defaultOptions; |
franck@1
|
288 return Popups.overrideOptions(defaults, overrides); |
franck@0
|
289 } |
franck@0
|
290 |
franck@0
|
291 /** |
franck@1
|
292 * Build an options hash. |
franck@0
|
293 * Also maps deprecated options to current options. |
franck@1
|
294 * |
franck@0
|
295 * @param defaults |
franck@0
|
296 * Hash of default values |
franck@0
|
297 * @param overrides |
franck@0
|
298 * Hash of values to override the defaults with. |
franck@0
|
299 */ |
franck@0
|
300 Popups.overrideOptions = function(defaults, overrides) { |
franck@0
|
301 var options = {}; |
franck@0
|
302 for(var option in defaults) { |
franck@0
|
303 var value; |
franck@0
|
304 if (Popups.isset(overrides[option])) { |
franck@0
|
305 options[option] = overrides[option]; |
franck@0
|
306 } |
franck@1
|
307 else { |
franck@0
|
308 options[option] = defaults[option]; |
franck@0
|
309 } |
franck@0
|
310 } |
franck@0
|
311 // Map deprecated options. |
franck@0
|
312 if (overrides['noReload'] || overrides['noUpdate']) { |
franck@0
|
313 options['updateMethod'] = 'none'; |
franck@1
|
314 } |
franck@0
|
315 if (overrides['reloadWhenDone']) { |
franck@0
|
316 options['updateMethod'] = 'reload'; |
franck@1
|
317 } |
franck@0
|
318 if (overrides['afterSubmit']) { |
franck@0
|
319 options['updateMethod'] = 'callback'; |
franck@0
|
320 options['onUpdate'] = overrides['afterSubmit']; |
franck@1
|
321 } |
franck@0
|
322 if (overrides['forceReturn']) { |
franck@0
|
323 options['doneTest'] = overrides['forceReturn']; |
franck@1
|
324 } |
franck@0
|
325 return options; |
franck@0
|
326 } |
franck@0
|
327 |
franck@0
|
328 /** |
franck@0
|
329 * Attach the popups behavior to all elements inside the context that match the selector. |
franck@0
|
330 * |
franck@0
|
331 * @param context |
franck@0
|
332 * Chunk of html to search. |
franck@0
|
333 * @param selector |
franck@0
|
334 * jQuery selector for elements to attach popups behavior to. |
franck@0
|
335 * @param options |
franck@0
|
336 * Hash of options associated with these links. |
franck@0
|
337 */ |
franck@0
|
338 Popups.attach = function(context, selector, options) { |
franck@0
|
339 $(selector, context).not('.popups-processed').each(function() { |
franck@1
|
340 var $element = $(this); |
franck@1
|
341 |
franck@1
|
342 // Mark the element as processed. |
franck@0
|
343 $element.addClass('popups-processed'); |
franck@1
|
344 |
franck@0
|
345 // Append note to link title. |
franck@0
|
346 var title = ''; |
franck@0
|
347 if ($element.attr('title')) { |
franck@0
|
348 title = $element.attr('title') + ' '; |
franck@0
|
349 } |
franck@0
|
350 title += Drupal.t('[Popup]'); |
franck@1
|
351 $element.attr('title', title); |
franck@1
|
352 |
franck@0
|
353 // Attach the on-click popup behavior to the element. |
franck@0
|
354 $element.click(function(event){ |
franck@0
|
355 return Popups.clickPopupElement(this, options); |
franck@0
|
356 }); |
franck@0
|
357 }); |
franck@1
|
358 }; |
franck@0
|
359 |
franck@0
|
360 /** |
franck@0
|
361 * Respond to click by opening a popup. |
franck@1
|
362 * |
franck@0
|
363 * @param element |
franck@0
|
364 * The element that was clicked. |
franck@0
|
365 * @param options |
franck@0
|
366 * Hash of options associated with the element. |
franck@0
|
367 */ |
franck@0
|
368 Popups.clickPopupElement = function(element, options) { |
franck@0
|
369 Popups.saveSettings(); |
franck@1
|
370 |
franck@0
|
371 // If the element contains a on-popups-options attribute, override default options param. |
franck@0
|
372 if ($(element).attr('on-popups-options')) { |
franck@1
|
373 var overrides = Drupal.parseJson($(element).attr('on-popups-options')); |
franck@0
|
374 options = Popups.overrideOptions(options, overrides); |
franck@0
|
375 } |
franck@1
|
376 |
franck@0
|
377 // The parent of the new popup is the currently active popup. |
franck@0
|
378 var parent = Popups.activePopup(); |
franck@1
|
379 |
franck@0
|
380 // If the option is distructive, check if the page is already modified, and offer to save. |
franck@0
|
381 var willModifyOriginal = !(options.updateMethod === 'none' || options.skipDirtyCheck); |
franck@0
|
382 if (willModifyOriginal && Popups.activeLayerIsEdited()) { |
franck@0
|
383 // The user will lose modifications, so show dialog offering to save current state. |
franck@0
|
384 Popups.offerToSave(element, options, parent); |
franck@0
|
385 } |
franck@0
|
386 else { |
franck@0
|
387 // Page is clean, or popup is safe, so just open it. |
franck@0
|
388 Popups.openPath(element, options, parent); |
franck@0
|
389 } |
franck@1
|
390 return false; |
franck@0
|
391 }; |
franck@0
|
392 |
franck@0
|
393 /** |
franck@0
|
394 * Test if the active layer been edited. |
franck@0
|
395 * Active layer is either the original page, or the active Popup. |
franck@0
|
396 */ |
franck@0
|
397 Popups.activeLayerIsEdited = function() { |
franck@0
|
398 var layer = Popups.activePopup(); |
franck@0
|
399 var $context = Popups.getLayerContext(layer); |
franck@1
|
400 // TODO: better test for edited page, maybe capture change event on :inputs. |
franck@1
|
401 var edited = $context.find('span.tabledrag-changed').length; |
franck@0
|
402 return edited; |
franck@0
|
403 } |
franck@0
|
404 |
franck@0
|
405 /** |
franck@0
|
406 * Show dialog offering to save form on parent layer. |
franck@1
|
407 * |
franck@0
|
408 * @param element |
franck@0
|
409 * The DOM element that was clicked. |
franck@0
|
410 * @param options |
franck@0
|
411 * The options associated with that element. |
franck@0
|
412 * @param parent |
franck@0
|
413 * The layer that has the unsaved edits. Null means the underlying page. |
franck@0
|
414 */ |
franck@0
|
415 Popups.offerToSave = function(element, options, parent) { |
franck@0
|
416 var popup = new Popups.Popup(); |
franck@0
|
417 var body = Drupal.t("There are unsaved changes in the form, which you will lose if you continue."); |
franck@0
|
418 var buttons = { |
franck@0
|
419 'popup_save': {title: Drupal.t('Save Changes'), func: function(){Popups.saveFormOnLayer(element, options, parent);}}, |
franck@0
|
420 'popup_submit': {title: Drupal.t('Continue'), func: function(){popup.removePopup(); Popups.openPath(element, options, parent);}}, |
franck@0
|
421 'popup_cancel': {title: Drupal.t('Cancel'), func: function(){popup.close();}} |
franck@0
|
422 }; |
franck@1
|
423 popup.open(Drupal.t('Warning: Please Confirm'), body, buttons); |
franck@0
|
424 }; |
franck@0
|
425 |
franck@0
|
426 /** |
franck@0
|
427 * Generic dialog builder. |
franck@0
|
428 * Adds the newly built popup into the DOM. |
franck@1
|
429 * |
franck@0
|
430 * TODO: capture the focus if it tabs out of the dialog. |
franck@0
|
431 * |
franck@0
|
432 * @param popup |
franck@0
|
433 * Popups.Popup object to fill with content, place in the DOM, and show on the screen. |
franck@0
|
434 * @param String title |
franck@0
|
435 * String: title of new dialog. |
franck@0
|
436 * @param body (optional) |
franck@0
|
437 * String: body of new dialog. |
franck@0
|
438 * @param buttons (optional) |
franck@0
|
439 * Hash of button parameters. |
franck@0
|
440 * @param width (optional) |
franck@0
|
441 * Width of new dialog. |
franck@1
|
442 * |
franck@0
|
443 * @return popup object |
franck@0
|
444 */ |
franck@0
|
445 Popups.open = function(popup, title, body, buttons, width){ |
franck@0
|
446 Popups.addOverlay(); |
franck@1
|
447 |
franck@0
|
448 if (Popups.activePopup()) { |
franck@0
|
449 // Hiding previously active popup. |
franck@0
|
450 Popups.activePopup().hide(); |
franck@0
|
451 } |
franck@1
|
452 |
franck@0
|
453 if (!popup) { |
franck@0
|
454 // Popup object was not handed in, so create a new one. |
franck@0
|
455 popup = new Popups.Popup(); |
franck@0
|
456 } |
franck@0
|
457 Popups.push(popup); // Put this popup at the top of the stack. |
franck@0
|
458 |
franck@0
|
459 // Create the jQuery wrapped html for the new popup. |
franck@0
|
460 var $popup = popup.fill(title, body, buttons); |
franck@0
|
461 popup.hide(); // Hide the new popup until it is finished and sized. |
franck@0
|
462 |
franck@0
|
463 if (width) { |
franck@0
|
464 $popup.css('width', width); |
franck@0
|
465 } |
franck@1
|
466 |
franck@0
|
467 // Add the new popup to the DOM. |
franck@1
|
468 $('body').append($popup); |
franck@0
|
469 |
franck@0
|
470 // Add button function callbacks. |
franck@0
|
471 if (buttons) { |
franck@0
|
472 jQuery.each(buttons, function(id, button){ |
franck@0
|
473 $('#' + id).click(button.func); |
franck@0
|
474 }); |
franck@0
|
475 } |
franck@1
|
476 |
franck@0
|
477 // Add the default click-to-close behavior. |
franck@0
|
478 popup.$popupClose().click(function(){ |
franck@0
|
479 return Popups.close(popup); |
franck@0
|
480 }); |
franck@0
|
481 |
franck@0
|
482 Popups.resizeAndCenter(popup); |
franck@0
|
483 |
franck@0
|
484 // Focus on the first input element in the popup window. |
franck@1
|
485 popup.refocus(); |
franck@1
|
486 |
franck@0
|
487 // TODO - this isn't the place for this - should mirror addLoading calls. |
franck@0
|
488 // Remove the loading image. |
franck@0
|
489 Popups.removeLoading(); |
franck@1
|
490 |
franck@0
|
491 return popup; |
franck@1
|
492 }; |
franck@0
|
493 |
franck@0
|
494 /** |
franck@0
|
495 * Adjust the popup's height to fit it's content. |
franck@0
|
496 * Move it to be centered on the screen. |
franck@0
|
497 * This undoes the effects of popup.hide(). |
franck@1
|
498 * |
franck@0
|
499 * @param popup |
franck@0
|
500 */ |
franck@0
|
501 Popups.resizeAndCenter = function(popup) { |
franck@0
|
502 var $popup = popup.$popup(); |
franck@1
|
503 |
franck@0
|
504 // center on the screen, adding in offsets if the window has been scrolled |
franck@1
|
505 var popupWidth = $popup.width(); |
franck@0
|
506 var windowWidth = Popups.windowWidth(); |
franck@0
|
507 var left = (windowWidth / 2) - (popupWidth / 2) + Popups.scrollLeft(); |
franck@1
|
508 |
franck@0
|
509 // Get popups's height on the page. |
franck@0
|
510 $popup.css('height', 'auto'); // Reset height. |
franck@1
|
511 var popupHeight = $popup.height(); |
franck@0
|
512 $popup.height(popupHeight); |
franck@0
|
513 var windowHeight = Popups.windowHeight(); |
franck@1
|
514 |
franck@0
|
515 if (popupHeight > (0.9 * windowHeight) ) { // Must fit in 90% of window. |
franck@0
|
516 popupHeight = 0.9 * windowHeight; |
franck@0
|
517 $popup.height(popupHeight); |
franck@1
|
518 } |
franck@0
|
519 var top = (windowHeight / 2) - (popupHeight / 2) + Popups.scrollTop(); |
franck@0
|
520 |
franck@1
|
521 $popup.css('top', top).css('left', left); // Position the popups to be visible. |
franck@0
|
522 }; |
franck@1
|
523 |
franck@0
|
524 |
franck@0
|
525 /** |
franck@0
|
526 * Create and show a simple popup dialog that functions like the browser's alert box. |
franck@0
|
527 */ |
franck@0
|
528 Popups.message = function(title, message) { |
franck@0
|
529 message = message || ''; |
franck@0
|
530 var popup = new Popups.Popup(); |
franck@0
|
531 var buttons = { |
franck@0
|
532 'popup_ok': {title: Drupal.t('OK'), func: function(){popup.close();}} |
franck@0
|
533 }; |
franck@0
|
534 popup.open(title, message, buttons); |
franck@0
|
535 return popup; |
franck@0
|
536 }; |
franck@0
|
537 |
franck@0
|
538 /** |
franck@0
|
539 * Handle any special keys when popups is active. |
franck@0
|
540 */ |
franck@0
|
541 Popups.keyHandle = function(e) { |
franck@0
|
542 if (!e) { |
franck@0
|
543 e = window.event; |
franck@0
|
544 } |
franck@0
|
545 switch (e.keyCode) { |
franck@0
|
546 case 27: // esc |
franck@0
|
547 Popups.close(); |
franck@0
|
548 break; |
franck@0
|
549 case 191: // '?' key, show help. |
franck@0
|
550 if (e.shiftKey && e.ctrlKey) { |
franck@0
|
551 var $help = $('a.popups.more-help'); |
franck@0
|
552 if ($help.size()) { |
franck@0
|
553 $help.click(); |
franck@0
|
554 } |
franck@0
|
555 else { |
franck@0
|
556 Popups.message(Drupal.t("Sorry, there is no additional help for this page")); |
franck@0
|
557 } |
franck@0
|
558 } |
franck@0
|
559 break; |
franck@0
|
560 } |
franck@0
|
561 }; |
franck@0
|
562 |
franck@0
|
563 /***************************************************************************** |
franck@0
|
564 * Appearence Functions (overlay, loading graphic, remove popups) ********* |
franck@0
|
565 *****************************************************************************/ |
franck@1
|
566 |
franck@0
|
567 /** |
franck@0
|
568 * Add full page div between the page and the dialog, to make the popup modal. |
franck@0
|
569 */ |
franck@0
|
570 Popups.addOverlay = function() { |
franck@0
|
571 var $overlay = $('#popups-overlay'); |
franck@0
|
572 if (!$overlay.length) { // Overlay does not already exist, so create it. |
franck@0
|
573 $overlay = $(Drupal.theme('popupOverlay')); |
franck@0
|
574 $overlay.css('opacity', '0.4'); // for ie6(?) |
franck@0
|
575 // Doing absolute positioning, so make overlay's size equal the entire body. |
franck@0
|
576 var $doc = $(document); |
franck@1
|
577 $overlay.width($doc.width()).height($doc.height()); |
franck@0
|
578 $overlay.click(function(){Popups.close();}); |
franck@0
|
579 $('body').prepend($overlay); |
franck@0
|
580 } |
franck@0
|
581 }; |
franck@0
|
582 |
franck@0
|
583 /** |
franck@0
|
584 * Remove overlay if popupStack is empty. |
franck@0
|
585 */ |
franck@0
|
586 Popups.removeOverlay = function() { |
franck@0
|
587 if (!Popups.popupStack.length) { |
franck@0
|
588 $('#popups-overlay').remove(); |
franck@0
|
589 } |
franck@0
|
590 }; |
franck@0
|
591 |
franck@0
|
592 /** |
franck@0
|
593 * Add a "Loading" message while we are waiting for the ajax response. |
franck@0
|
594 */ |
franck@0
|
595 Popups.addLoading = function() { |
franck@0
|
596 var $loading = $('#popups-loading'); |
franck@0
|
597 if (!$loading.length) { // Loading image does not already exist, so create it. |
franck@0
|
598 $loading = $(Drupal.theme('popupLoading')); |
franck@0
|
599 $('body').prepend($loading); // Loading div is initially display:none. |
franck@0
|
600 var width = $loading.width(); |
franck@0
|
601 var height = $loading.height(); |
franck@0
|
602 var left = (Popups.windowWidth() / 2) - (width / 2) + Popups.scrollLeft(); |
franck@0
|
603 var top = (Popups.windowHeight() / 2) - (height / 2) + Popups.scrollTop(); |
franck@0
|
604 $loading.css({'top': top, 'left': left, 'display': 'block'}); // Center it and make it visible. |
franck@0
|
605 } |
franck@0
|
606 }; |
franck@0
|
607 |
franck@0
|
608 Popups.removeLoading = function() { |
franck@0
|
609 $('#popups-loading').remove(); |
franck@0
|
610 }; |
franck@0
|
611 |
franck@0
|
612 // Should I fold this function into Popups.pop? |
franck@1
|
613 Popups.removePopup = function(popup) { |
franck@0
|
614 if (!Popups.isset(popup)) { |
franck@0
|
615 popup = Popups.activePopup(); |
franck@0
|
616 } |
franck@0
|
617 if (popup) { |
franck@0
|
618 popup.$popup().remove(); |
franck@1
|
619 Popups.popupStack.splice(jQuery.inArray(popup,Popups.popupStack), 1); // Remove popup from stack. Probably should rework into .pop() |
franck@1
|
620 } |
franck@1
|
621 }; |
franck@0
|
622 |
franck@0
|
623 /** |
franck@0
|
624 * Remove everything. |
franck@0
|
625 */ |
franck@0
|
626 Popups.close = function(popup) { |
franck@0
|
627 if (!Popups.isset(popup)) { |
franck@0
|
628 popup = Popups.activePopup(); |
franck@0
|
629 } |
franck@0
|
630 Popups.removePopup(popup); // Should this be a pop?? |
franck@0
|
631 Popups.removeLoading(); |
franck@0
|
632 if (Popups.activePopup()) { |
franck@0
|
633 Popups.activePopup().show(); |
franck@0
|
634 Popups.activePopup().refocus(); |
franck@0
|
635 } |
franck@0
|
636 else { |
franck@0
|
637 Popups.removeOverlay(); |
franck@0
|
638 Popups.restorePage(); |
franck@0
|
639 } |
franck@0
|
640 return false; |
franck@0
|
641 }; |
franck@0
|
642 |
franck@0
|
643 /** |
franck@0
|
644 * Save the page's original Drupal.settings. |
franck@0
|
645 */ |
franck@0
|
646 Popups.saveSettings = function() { |
franck@0
|
647 if (!Popups.originalSettings) { |
franck@0
|
648 Popups.originalSettings = Drupal.settings; |
franck@0
|
649 } |
franck@0
|
650 }; |
franck@0
|
651 |
franck@0
|
652 /** |
franck@0
|
653 * Restore the page's original Drupal.settings. |
franck@0
|
654 */ |
franck@0
|
655 Popups.restoreSettings = function() { |
franck@1
|
656 Drupal.settings = Popups.originalSettings; |
franck@0
|
657 }; |
franck@0
|
658 |
franck@0
|
659 /** |
franck@0
|
660 * Remove as much of the effects of jit loading as possible. |
franck@0
|
661 */ |
franck@0
|
662 Popups.restorePage = function() { |
franck@0
|
663 Popups.restoreSettings(); |
franck@0
|
664 // Remove the CSS files that were jit loaded for popup. |
franck@1
|
665 for (var i in Popups.addedCSS) if (Popups.addedCSS.hasOwnProperty(i)) { |
franck@1
|
666 $('link[href='+ Popups.addedCSS[i] + ']').remove(); |
franck@0
|
667 } |
franck@0
|
668 Popups.addedCSS = []; |
franck@0
|
669 }; |
franck@0
|
670 |
franck@0
|
671 |
franck@0
|
672 /**************************************************************************** |
franck@0
|
673 * Utility Functions ****************************************************** |
franck@0
|
674 ****************************************************************************/ |
franck@0
|
675 |
franck@0
|
676 /** |
franck@0
|
677 * Get the position of the left side of the browser window. |
franck@0
|
678 */ |
franck@0
|
679 Popups.scrollLeft = function() { |
franck@0
|
680 return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft); |
franck@0
|
681 }; |
franck@0
|
682 |
franck@0
|
683 /** |
franck@0
|
684 * Get the position of the top of the browser window. |
franck@0
|
685 */ |
franck@0
|
686 Popups.scrollTop = function() { |
franck@0
|
687 return Math.max(document.documentElement.scrollTop, document.body.scrollTop); |
franck@0
|
688 }; |
franck@0
|
689 |
franck@0
|
690 /** |
franck@0
|
691 * Get the height of the browser window. |
franck@0
|
692 * Fixes jQuery & Opera bug - http://drupal.org/node/366093 |
franck@0
|
693 */ |
franck@0
|
694 Popups.windowHeight = function() { |
franck@1
|
695 if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { |
franck@0
|
696 return document.documentElement.clientHeight; |
franck@0
|
697 } |
franck@0
|
698 return $(window).height(); |
franck@0
|
699 }; |
franck@0
|
700 |
franck@0
|
701 /** |
franck@0
|
702 * Get the height of the browser window. |
franck@0
|
703 * Fixes jQuery & Opera bug - http://drupal.org/node/366093 |
franck@0
|
704 */ |
franck@0
|
705 Popups.windowWidth = function() { |
franck@1
|
706 if ($.browser.opera && $.browser.version > "9.5" && $.fn.jquery <= "1.2.6") { |
franck@0
|
707 return document.documentElement.clientWidth; |
franck@0
|
708 } |
franck@0
|
709 return $(window).width(); |
franck@0
|
710 }; |
franck@0
|
711 |
franck@0
|
712 Popups.nextCounter = function() { |
franck@0
|
713 if (this.counter === undefined) { |
franck@0
|
714 this.counter = 0; |
franck@0
|
715 } |
franck@0
|
716 else { |
franck@0
|
717 this.counter++; |
franck@0
|
718 } |
franck@0
|
719 return this.counter; |
franck@0
|
720 }; |
franck@0
|
721 |
franck@0
|
722 /**************************************************************************** |
franck@0
|
723 * Ajax Functions ****************************************************** |
franck@0
|
724 ****************************************************************************/ |
franck@0
|
725 |
franck@0
|
726 /** |
franck@0
|
727 * Add additional CSS to the page. |
franck@0
|
728 */ |
franck@0
|
729 Popups.addCSS = function(css) { |
franck@0
|
730 Popups.addedCSS = []; |
franck@1
|
731 for (var type in css) if (css.hasOwnProperty(type)) { |
franck@1
|
732 for (var file in css[type]) if (css[type].hasOwnProperty(file)) { |
franck@0
|
733 var link = css[type][file]; |
franck@1
|
734 var href = $(link).attr('href'); |
franck@0
|
735 // Does the page already contain this stylesheet? |
franck@1
|
736 if (!Popups.originalCSS[href.replace(/^(\/.+)\?\w$/, '$1')] && !Popups.addedCSS[href]) { |
franck@0
|
737 $('head').append(link); |
franck@1
|
738 Popups.addedCSS[href] = 1; // Keep a list, so we can remove them later. |
franck@0
|
739 } |
franck@0
|
740 } |
franck@0
|
741 } |
franck@0
|
742 }; |
franck@0
|
743 |
franck@0
|
744 /** |
franck@0
|
745 * Add additional Javascript to the page. |
franck@0
|
746 */ |
franck@0
|
747 Popups.addJS = function(js) { |
franck@0
|
748 // Parse the json info about the new context. |
franck@0
|
749 var scripts = []; |
franck@0
|
750 var inlines = []; |
franck@1
|
751 var src; |
franck@1
|
752 for (var type in js) if (js.hasOwnProperty(type)) { |
franck@0
|
753 if (type != 'setting') { |
franck@1
|
754 for (var file in js[type]) if (js[type].hasOwnProperty(file)) { |
franck@0
|
755 if (type == 'inline') { |
franck@0
|
756 inlines.push($(js[type][file]).text()); |
franck@0
|
757 } |
franck@0
|
758 else { |
franck@1
|
759 src = $(js[type][file]).attr('src'); |
franck@1
|
760 if (!Popups.originalJS[src.replace(/^(\/.+)\?\w$/, '$1')] && !Popups.addedJS[src]) { |
franck@1
|
761 // Get the script from the server and execute it. |
franck@1
|
762 $.ajax({ |
franck@1
|
763 type: 'GET', |
franck@1
|
764 url: src, |
franck@1
|
765 dataType: 'script', |
franck@1
|
766 async : false, |
franck@1
|
767 success: function(script) { |
franck@1
|
768 eval(script); |
franck@1
|
769 } |
franck@1
|
770 }); |
franck@1
|
771 // Mark the js as added to the underlying page. |
franck@1
|
772 Popups.addedJS[src] = 1; |
franck@1
|
773 } |
franck@0
|
774 } |
franck@0
|
775 } |
franck@0
|
776 } |
franck@0
|
777 } |
franck@0
|
778 |
franck@0
|
779 // Add new JS settings to the page, needed for #ahah properties to work. |
franck@0
|
780 Drupal.settings = js.setting; |
franck@0
|
781 |
franck@0
|
782 return inlines; |
franck@0
|
783 }; |
franck@0
|
784 |
franck@0
|
785 /** |
franck@0
|
786 * Execute the jit loaded inline scripts. |
franck@0
|
787 * Q: Do we want to re-excute the ones already in the page? |
franck@1
|
788 * |
franck@0
|
789 * @param inlines |
franck@0
|
790 * Array of inline scripts. |
franck@0
|
791 */ |
franck@0
|
792 Popups.addInlineJS = function(inlines) { |
franck@0
|
793 // Load the inlines into the page. |
franck@0
|
794 for (var n in inlines) { |
franck@0
|
795 // If the script is not already in the page, execute it. |
franck@1
|
796 //if (!$('script:not([src]):contains(' + inlines[n] + ')').length) { |
franck@0
|
797 eval(inlines[n]); |
franck@1
|
798 //} |
franck@0
|
799 } |
franck@0
|
800 }; |
franck@0
|
801 |
franck@0
|
802 Popups.beforeSend = function(xhr) { |
franck@0
|
803 xhr.setRequestHeader("X-Drupal-Render-Mode", 'json/popups'); |
franck@0
|
804 }; |
franck@0
|
805 |
franck@0
|
806 /** |
franck@0
|
807 * Do before the form in the popups is submitted. |
franck@0
|
808 */ |
franck@0
|
809 Popups.beforeSubmit = function(formData, $form, options) { |
franck@0
|
810 Popups.removePopup(); // Remove just the dialog, but not the overlay. |
franck@0
|
811 Popups.addLoading(); |
franck@0
|
812 }; |
franck@0
|
813 |
franck@0
|
814 |
franck@0
|
815 /**************************************************************************** |
franck@0
|
816 * Page & Form in popups functions *** |
franck@0
|
817 ****************************************************************************/ |
franck@0
|
818 |
franck@0
|
819 /** |
franck@0
|
820 * Use Ajax to open a link in a popups window. |
franck@0
|
821 * |
franck@0
|
822 * @param element |
franck@0
|
823 * Element that was clicked to open the popups. |
franck@0
|
824 * @param options |
franck@0
|
825 * Hash of options controlling how the popups interacts with the underlying page. |
franck@0
|
826 * @param parent |
franck@0
|
827 * If path is being opened from inside another popup, that popup is the parent. |
franck@0
|
828 */ |
franck@0
|
829 Popups.openPath = function(element, options, parent) { |
franck@0
|
830 Popups.saveSettings(); |
franck@0
|
831 |
franck@0
|
832 // Let the user know something is happening. |
franck@0
|
833 $('body').css("cursor", "wait"); |
franck@1
|
834 |
franck@0
|
835 // TODO - get nonmodal working. |
franck@0
|
836 if (!options.nonModal) { |
franck@1
|
837 Popups.addOverlay(); |
franck@0
|
838 } |
franck@0
|
839 Popups.addLoading(); |
franck@1
|
840 |
franck@0
|
841 var href = options.href ? options.href : element.href; |
franck@0
|
842 $(document).trigger('popups_open_path', [element, href]); // Broadcast Popup Open Path event. |
franck@1
|
843 |
franck@1
|
844 var params = {}; |
franck@0
|
845 // Force the popups to return back to the orignal page when forms are done, unless hijackDestination option is set to FALSE. |
franck@1
|
846 if (options.hijackDestination) { |
franck@0
|
847 var returnPath; |
franck@0
|
848 if (parent) { |
franck@0
|
849 returnPath = parent.path; |
franck@0
|
850 } |
franck@0
|
851 else { // No parent, so bring flow back to original page. |
franck@0
|
852 returnPath = Popups.originalSettings.popups.originalPath; |
franck@1
|
853 } |
franck@0
|
854 href = href.replace(/destination=[^;&]*[;&]?/, ''); // Strip out any existing destination param. |
franck@1
|
855 params.destination = returnPath; // Set the destination to return to the parent's path. |
franck@0
|
856 } |
franck@0
|
857 |
franck@0
|
858 var ajaxOptions = { |
franck@0
|
859 url: href, |
franck@0
|
860 dataType: 'json', |
franck@0
|
861 data: params, |
franck@0
|
862 beforeSend: Popups.beforeSend, |
franck@1
|
863 success: function(json) { |
franck@0
|
864 // Add additional CSS to the page. |
franck@0
|
865 Popups.addCSS(json.css); |
franck@0
|
866 var inlines = Popups.addJS(json.js); |
franck@0
|
867 var popup = Popups.openPathContent(json.path, json.title, json.messages + json.content, element, options, parent); |
franck@1
|
868 Popups.addInlineJS(inlines); |
franck@0
|
869 // Broadcast an event that the path was opened. |
franck@1
|
870 $(document).trigger('popups_open_path_done', [element, href, popup]); |
franck@0
|
871 }, |
franck@0
|
872 complete: function() { |
franck@1
|
873 $('body').css("cursor", "auto"); // Return the cursor to normal state. |
franck@0
|
874 } |
franck@0
|
875 }; |
franck@0
|
876 |
franck@0
|
877 var ajaxOptions; |
franck@0
|
878 if (options.reloadOnError) { |
franck@0
|
879 ajaxOptions.error = function() { |
franck@0
|
880 location.reload(); // Reload on error. Is this working? |
franck@1
|
881 }; |
franck@0
|
882 } |
franck@0
|
883 else { |
franck@0
|
884 ajaxOptions.error = function() { |
franck@0
|
885 Popups.message("Unable to open: " + href); |
franck@0
|
886 }; |
franck@0
|
887 } |
franck@0
|
888 $.ajax(ajaxOptions); |
franck@1
|
889 |
franck@1
|
890 return false; |
franck@0
|
891 }; |
franck@0
|
892 |
franck@0
|
893 /** |
franck@0
|
894 * Open path's content in an ajax popups. |
franck@0
|
895 * |
franck@0
|
896 * @param title |
franck@0
|
897 * String title of the popups. |
franck@0
|
898 * @param content |
franck@0
|
899 * HTML to show in the popups. |
franck@0
|
900 * @param element |
franck@1
|
901 * A DOM object containing the element that was clicked to initiate the popup. |
franck@0
|
902 * @param options |
franck@0
|
903 * Hash of options controlling how the popups interacts with the underlying page. |
franck@0
|
904 * @param parent |
franck@1
|
905 * Spawning popup, or null if spawned from original page. |
franck@0
|
906 */ |
franck@1
|
907 Popups.openPathContent = function(path, title, content, element, options, parent) { |
franck@0
|
908 var popup = new Popups.Popup(); |
franck@1
|
909 Popups.open(popup, title, content, null, options.width); |
franck@0
|
910 |
franck@1
|
911 // Set properties on new popup. |
franck@0
|
912 popup.parent = parent; |
franck@0
|
913 popup.path = path; |
franck@0
|
914 popup.options = options; |
franck@0
|
915 popup.element = element; |
franck@0
|
916 |
franck@1
|
917 // Add behaviors to content in popups. |
franck@0
|
918 delete Drupal.behaviors.tableHeader; // Work-around for bug in tableheader.js (http://drupal.org/node/234377) |
franck@0
|
919 delete Drupal.behaviors.teaser; // Work-around for bug in teaser.js (sigh). |
franck@0
|
920 Drupal.attachBehaviors(popup.$popupBody()); |
franck@0
|
921 // Adding collapse moves focus. |
franck@0
|
922 popup.refocus(); |
franck@0
|
923 |
franck@0
|
924 // If the popups contains a form, capture submits. |
franck@4
|
925 var $form = $('form:not(.no-popup)', popup.$popupBody()); |
franck@0
|
926 if ($form.length) { |
franck@1
|
927 $form.ajaxForm({ |
franck@1
|
928 dataType: 'json', |
franck@0
|
929 beforeSubmit: Popups.beforeSubmit, |
franck@0
|
930 beforeSend: Popups.beforeSend, |
franck@0
|
931 success: function(json, status) { |
franck@0
|
932 Popups.formSuccess(popup, json); |
franck@0
|
933 }, |
franck@0
|
934 error: function() { |
franck@5
|
935 Popups.message(Drupal.t("Bad Response form submission")); |
franck@0
|
936 } |
franck@0
|
937 }); |
franck@0
|
938 } |
franck@0
|
939 return popup; |
franck@0
|
940 }; |
franck@0
|
941 |
franck@0
|
942 /** |
franck@0
|
943 * The form in the popups was successfully submitted |
franck@0
|
944 * Update the originating page. |
franck@0
|
945 * Show any messages in a popups. |
franck@1
|
946 * |
franck@0
|
947 * @param popup |
franck@0
|
948 * The popup object that contained the form that was just submitted. |
franck@0
|
949 * @param data |
franck@0
|
950 * JSON object from server with status of form submission. |
franck@0
|
951 */ |
franck@1
|
952 Popups.formSuccess = function(popup, data) { |
franck@0
|
953 // Determine if we are at an end point, or just moving from one popups to another. |
franck@0
|
954 var done = popup.isDone(data.path); |
franck@0
|
955 if (!done) { // Not done yet, so show new page in new popups. |
franck@0
|
956 Popups.removeLoading(); |
franck@0
|
957 Popups.openPathContent(data.path, data.title, data.messages + data.content, popup.element, popup.options, popup.parent); |
franck@0
|
958 } |
franck@0
|
959 else { // We are done with popup flow. |
franck@0
|
960 // Execute the onUpdate callback if available. |
franck@1
|
961 if (popup.options.updateMethod === 'callback' && popup.options.onUpdate) { |
franck@0
|
962 var result = eval(popup.options.onUpdate +'(data, popup.options, popup.element)'); |
franck@0
|
963 if (result === false) { // Give onUpdate callback a chance to skip normal processing. |
franck@0
|
964 return; |
franck@0
|
965 } |
franck@0
|
966 } |
franck@0
|
967 |
franck@0
|
968 if (popup.options.updateMethod === 'reload') { // Force a complete, non-ajax reload of the page. |
franck@0
|
969 if (popup.options.updateSource === 'final') { |
franck@0
|
970 location.href = Drupal.settings.basePath + data.path; // TODO: Need to test this. |
franck@0
|
971 } |
franck@0
|
972 else { // Reload originating page. |
franck@1
|
973 location.reload(); |
franck@0
|
974 } |
franck@0
|
975 } |
franck@0
|
976 else { // Normal, targeted ajax, reload behavior. |
franck@1
|
977 var showingMessagePopup = false; |
franck@0
|
978 // Show messages in dialog and embed the results in the original page. |
franck@1
|
979 // TODO - should seperate these two functions. |
franck@1
|
980 // var showMessage = data.messages.length && !popup.options.noMessage; |
franck@6
|
981 if (data.messages && data.messages.length) { |
franck@1
|
982 // If we just dismissed the last popup dialog. |
franck@1
|
983 if (!Popups.activePopup() && !popup.options.noMessage) { |
franck@1
|
984 // Show drupal_set_message in message popup. |
franck@1
|
985 var messagePopup = Popups.message(data.messages); |
franck@1
|
986 if (Popups.originalSettings.popups.autoCloseFinalMessage) { |
franck@1
|
987 setTimeout(function(){Popups.close(messagePopup);}, 2500); // Autoclose the message box in 2.5 seconds. |
franck@1
|
988 } |
franck@1
|
989 showingMessagePopup = true; |
franck@0
|
990 } |
franck@1
|
991 |
franck@1
|
992 |
franck@1
|
993 // Insert the message into the parent layer, above the content. |
franck@0
|
994 // Might not be the standard spot, but it is the easiest to find. |
franck@0
|
995 var $next; |
franck@0
|
996 if (popup.targetLayerSelector() === 'body') { |
franck@0
|
997 $next = $('body').find(Popups.originalSettings.popups.defaultTargetSelector); |
franck@0
|
998 } |
franck@0
|
999 else { |
franck@0
|
1000 $next = $(popup.targetLayerSelector()).find('.popups-body'); |
franck@0
|
1001 } |
franck@0
|
1002 $next.parent().find('div.messages').remove(); // Remove the existing messages. |
franck@0
|
1003 $next.before(data.messages); // Insert new messages. |
franck@0
|
1004 } |
franck@1
|
1005 |
franck@0
|
1006 // Update the content area (defined by 'targetSelectors'). |
franck@1
|
1007 if (popup.options.updateMethod !== 'none') { |
franck@0
|
1008 Popups.testContentSelector(); // Kick up warning message if selector is bad. |
franck@0
|
1009 |
franck@1
|
1010 Popups.restoreSettings(); // Need to restore original Drupal.settings.popups.links before running attachBehaviors. This probably has CSS side effects! |
franck@0
|
1011 if (popup.options.targetSelectors) { // Pick and choose what returned content goes where. |
franck@0
|
1012 jQuery.each(popup.options.targetSelectors, function(t_new, t_old) { |
franck@0
|
1013 if(!isNaN(t_new)) { |
franck@0
|
1014 t_new = t_old; // handle case where targetSelectors is an array, not a hash. |
franck@0
|
1015 } |
franck@0
|
1016 var new_content = $(t_new, data.content); |
franck@0
|
1017 var $c = $(popup.targetLayerSelector()).find(t_old).html(new_content); // Inject the new content into the original page. |
franck@0
|
1018 |
franck@0
|
1019 Drupal.attachBehaviors($c); |
franck@0
|
1020 }); |
franck@0
|
1021 } |
franck@0
|
1022 else { // Put the entire new content into default content area. |
franck@0
|
1023 var $c = $(popup.targetLayerSelector()).find(Popups.originalSettings.popups.defaultTargetSelector).html(data.content); |
franck@1
|
1024 Drupal.attachBehaviors($c); |
franck@0
|
1025 } |
franck@0
|
1026 } |
franck@1
|
1027 |
franck@0
|
1028 // Update the title of the page. |
franck@0
|
1029 if (popup.options.titleSelectors) { |
franck@0
|
1030 jQuery.each(popup.options.titleSelectors, function() { |
franck@0
|
1031 $(''+this).html(data.title); |
franck@0
|
1032 }); |
franck@0
|
1033 } |
franck@1
|
1034 |
franck@0
|
1035 // Done with changes to the original page, remove effects. |
franck@0
|
1036 Popups.removeLoading(); |
franck@1
|
1037 if (!showingMessagePopup) { |
franck@1
|
1038 // If there is not a messages popups, pop the stack. |
franck@1
|
1039 // Sending in null to Popups.close reveales the next popup in the stack. |
franck@1
|
1040 // If the stack is empty, it will remove the overlay. |
franck@1
|
1041 Popups.close(null); |
franck@0
|
1042 } |
franck@0
|
1043 } |
franck@1
|
1044 |
franck@0
|
1045 // Broadcast an event that popup form was done and successful. |
franck@0
|
1046 $(document).trigger('popups_form_success', [popup]); |
franck@1
|
1047 |
franck@0
|
1048 } // End of updating spawning layer. |
franck@1
|
1049 }; |
franck@0
|
1050 |
franck@0
|
1051 |
franck@0
|
1052 /** |
franck@0
|
1053 * Get a jQuery object for the content of a layer. |
franck@0
|
1054 * @param layer |
franck@0
|
1055 * Either a popup, or null to signify the original page. |
franck@0
|
1056 */ |
franck@1
|
1057 Popups.getLayerContext = function(layer) { |
franck@0
|
1058 var $context; |
franck@0
|
1059 if (!layer) { |
franck@0
|
1060 $context = $('body').find(Popups.originalSettings.popups.defaultTargetSelector); |
franck@0
|
1061 } |
franck@0
|
1062 else { |
franck@0
|
1063 $context = layer.$popupBody(); |
franck@0
|
1064 } |
franck@0
|
1065 return $context; |
franck@0
|
1066 } |
franck@0
|
1067 |
franck@0
|
1068 /** |
franck@0
|
1069 * Submit the page and reload the results, before popping up the real dialog. |
franck@0
|
1070 * |
franck@0
|
1071 * @param element |
franck@0
|
1072 * Element that was clicked to open a new popup. |
franck@0
|
1073 * @param options |
franck@0
|
1074 * Hash of options controlling how the popups interacts with the underlying page. |
franck@0
|
1075 * @param layer |
franck@1
|
1076 * Popup with form to save, or null if form is on original page. |
franck@0
|
1077 */ |
franck@0
|
1078 Popups.saveFormOnLayer = function(element, options, layer) { |
franck@0
|
1079 var $context = Popups.getLayerContext(layer); |
franck@0
|
1080 var $form = $context.find('form'); |
franck@0
|
1081 var ajaxOptions = { |
franck@0
|
1082 dataType: 'json', |
franck@1
|
1083 beforeSubmit: Popups.beforeSubmit, |
franck@0
|
1084 beforeSend: Popups.beforeSend, |
franck@1
|
1085 success: function(response, status) { |
franck@0
|
1086 // Sync up the current page contents with the submit. |
franck@0
|
1087 var $c = $context.html(response.content); // Inject the new content into the page. |
franck@0
|
1088 Drupal.attachBehaviors($c); |
franck@0
|
1089 // The form has been saved, the page reloaded, now safe to show the triggering link in a popup. |
franck@1
|
1090 Popups.openPath(element, options, layer); |
franck@1
|
1091 } |
franck@0
|
1092 }; |
franck@1
|
1093 $form.ajaxSubmit(ajaxOptions); // Submit the form. |
franck@0
|
1094 }; |
franck@0
|
1095 |
franck@0
|
1096 /** |
franck@0
|
1097 * Warn the user if ajax updates will not work |
franck@0
|
1098 * due to mismatch between the theme and the theme's popup setting. |
franck@0
|
1099 */ |
franck@0
|
1100 Popups.testContentSelector = function() { |
franck@0
|
1101 var target = Popups.originalSettings.popups.defaultTargetSelector; |
franck@0
|
1102 var hits = $(target).length; |
franck@0
|
1103 if (hits !== 1) { // 1 is the corrent answer. |
franck@0
|
1104 var msg = Drupal.t('The popup content area for this theme is misconfigured.') + '\n'; |
franck@0
|
1105 if (hits === 0) { |
franck@0
|
1106 msg += Drupal.t('There is no element that matches ') + '"' + target + '"\n'; |
franck@0
|
1107 } |
franck@0
|
1108 else if (hits > 1) { |
franck@0
|
1109 msg += Drupal.t('There are multiple elements that match: ') + '"' + target + '"\n'; |
franck@0
|
1110 } |
franck@1
|
1111 msg += Drupal.t('Go to admin/build/themes/settings, select your theme, and edit the "Content Selector" field'); |
franck@0
|
1112 alert(msg); |
franck@0
|
1113 } |
franck@0
|
1114 }; |
franck@0
|
1115 |
franck@0
|
1116 |
franck@0
|
1117 // **************************************************************************** |
franck@0
|
1118 // * Theme Functions ******************************************************** |
franck@0
|
1119 // **************************************************************************** |
franck@0
|
1120 |
franck@0
|
1121 Drupal.theme.prototype.popupLoading = function() { |
franck@0
|
1122 var loading = '<div id="popups-loading">'; |
franck@0
|
1123 loading += '<img src="'+ Drupal.settings.basePath + Popups.originalSettings.popups.modulePath + '/ajax-loader.gif" />'; |
franck@0
|
1124 loading += '</div>'; |
franck@0
|
1125 return loading; |
franck@0
|
1126 }; |
franck@0
|
1127 |
franck@0
|
1128 Drupal.theme.prototype.popupOverlay = function() { |
franck@0
|
1129 return '<div id="popups-overlay"></div>'; |
franck@0
|
1130 }; |
franck@0
|
1131 |
franck@0
|
1132 Drupal.theme.prototype.popupButton = function(title, id) { |
franck@0
|
1133 return '<input type="button" value="'+ title +'" id="'+ id +'" />'; |
franck@0
|
1134 }; |
franck@0
|
1135 |
franck@0
|
1136 Drupal.theme.prototype.popupDialog = function(popupId, title, body, buttons) { |
franck@0
|
1137 var template = Drupal.theme('popupTemplate', popupId); |
franck@0
|
1138 var popups = template.replace('%title', title).replace('%body', body); |
franck@1
|
1139 |
franck@0
|
1140 var themedButtons = ''; |
franck@0
|
1141 if (buttons) { |
franck@1
|
1142 jQuery.each(buttons, function (id, button) { |
franck@0
|
1143 themedButtons += Drupal.theme('popupButton', button.title, id); |
franck@1
|
1144 }); |
franck@1
|
1145 } |
franck@1
|
1146 popups = popups.replace('%buttons', themedButtons); |
franck@0
|
1147 return popups; |
franck@0
|
1148 }; |
franck@0
|
1149 |
franck@0
|
1150 Drupal.theme.prototype.popupTemplate = function(popupId) { |
franck@0
|
1151 var template; |
franck@0
|
1152 template += '<div id="'+ popupId + '" class="popups-box">'; |
franck@0
|
1153 template += ' <div class="popups-title">'; |
franck@0
|
1154 template += ' <div class="popups-close"><a href="#">' + Drupal.t('Close') + '</a></div>'; |
franck@0
|
1155 template += ' <div class="title">%title</div>'; |
franck@0
|
1156 template += ' <div class="clear-block"></div>'; |
franck@0
|
1157 template += ' </div>'; |
franck@0
|
1158 template += ' <div class="popups-body">%body</div>'; |
franck@0
|
1159 template += ' <div class="popups-buttons">%buttons</div>'; |
franck@0
|
1160 template += ' <div class="popups-footer"></div>'; |
franck@0
|
1161 template += '</div>'; |
franck@0
|
1162 return template; |
franck@0
|
1163 }; |