1 var CHOOSERDIALOGUE = function() {
2 CHOOSERDIALOGUE.superclass.constructor.apply(this, arguments);
5 Y.extend(CHOOSERDIALOGUE, Y.Base, {
9 // The submit button - we disable this until an element is set
12 // The chooserdialogue container
15 // Any event listeners we may need to cancel later
18 // The initial overflow setting
23 instanceconfig : null,
25 setup_chooser_dialogue : function(bodycontent, headercontent, config) {
26 this.bodycontent = bodycontent;
27 this.headercontent = headercontent;
28 this.instanceconfig = config;
31 prepare_chooser : function () {
36 // Set Default options
39 bodyContent : this.bodycontent.get('innerHTML'),
40 headerContent : this.headercontent.get('innerHTML'),
43 visible : false, // Hide by default
44 zindex : 100, // Display in front of other items
45 lightbox : true, // This dialogue should be modal
47 closeButtonTitle : this.get('closeButtonTitle')
50 // Override with additional options
51 for (paramkey in this.instanceconfig) {
52 params[paramkey] = this.instanceconfig[paramkey];
56 this.panel = new M.core.dialogue(params);
58 // Remove the template for the chooser
59 this.bodycontent.remove();
60 this.headercontent.remove();
62 // Hide and then render the panel
67 this.container = this.panel.get('boundingBox').one('.choosercontainer');
68 this.options = this.container.all('.option input[type=radio]');
70 // Add the chooserdialogue class to the container for styling
71 this.panel.get('boundingBox').addClass('chooserdialogue');
75 * Display the module chooser
77 * @param e Event Triggering Event
80 display_chooser : function (e) {
81 var bb, dialogue, thisevent;
82 this.prepare_chooser();
84 // Stop the default event actions before we proceed
87 bb = this.panel.get('boundingBox');
88 dialogue = this.container.one('.alloptions');
90 // Get the overflow setting when the chooser was opened - we
91 // may need this later
93 this.initialoverflow = Y.one('html').getStyle('overflow');
95 this.initialoverflow = Y.one('body').getStyle('overflow');
98 // This will detect a change in orientation and retrigger centering
99 thisevent = Y.one('document').on('orientationchange', function() {
100 this.center_dialogue(dialogue);
102 this.listenevents.push(thisevent);
104 // Detect window resizes (most browsers)
105 thisevent = Y.one('window').on('resize', function() {
106 this.center_dialogue(dialogue);
108 this.listenevents.push(thisevent);
110 // These will trigger a check_options call to display the correct help
111 thisevent = this.container.on('click', this.check_options, this);
112 this.listenevents.push(thisevent);
113 thisevent = this.container.on('key_up', this.check_options, this);
114 this.listenevents.push(thisevent);
115 thisevent = this.container.on('dblclick', function(e) {
116 if (e.target.ancestor('div.option')) {
117 this.check_options();
119 // Prevent duplicate submissions
120 this.submitbutton.setAttribute('disabled', 'disabled');
121 this.options.setAttribute('disabled', 'disabled');
122 this.cancel_listenevents();
124 this.container.one('form').submit();
127 this.listenevents.push(thisevent);
129 this.container.one('form').on('submit', function() {
130 // Prevent duplicate submissions on submit
131 this.submitbutton.setAttribute('disabled', 'disabled');
132 this.options.setAttribute('disabled', 'disabled');
133 this.cancel_listenevents();
136 // Hook onto the cancel button to hide the form
137 thisevent = this.container.one('.addcancel').on('click', this.cancel_popup, this);
138 this.listenevents.push(thisevent);
140 // Hide will be managed by cancel_popup after restoring the body overflow
141 thisevent = bb.one('button.closebutton').on('click', this.cancel_popup, this);
142 this.listenevents.push(thisevent);
144 // Grab global keyup events and handle them
145 thisevent = Y.one('document').on('keydown', this.handle_key_press, this);
146 this.listenevents.push(thisevent);
148 // Add references to various elements we adjust
149 this.jumplink = this.container.one('.jump');
150 this.submitbutton = this.container.one('.submitbutton');
152 // Disable the submit element until the user makes a selection
153 this.submitbutton.set('disabled', 'true');
155 // Ensure that the options are shown
156 this.options.removeAttribute('disabled');
161 // Re-centre the dialogue after we've shown it.
162 this.center_dialogue(dialogue);
164 // Finally, focus the first radio element - this enables form selection via the keyboard
165 this.container.one('.option input[type=radio]').focus();
167 // Trigger check_options to set the initial jumpurl
168 this.check_options();
172 * Cancel any listen events in the listenevents queue
174 * Several locations add event handlers which should only be called before the form is submitted. This provides
175 * a way of cancelling those events.
179 cancel_listenevents : function () {
180 // Detach all listen events to prevent duplicate triggers
182 while (this.listenevents.length) {
183 thisevent = this.listenevents.shift();
189 * Calculate the optimum height of the chooser dialogue
191 * This tries to set a sensible maximum and minimum to ensure that some options are always shown, and preferably
192 * all, whilst fitting the box within the current viewport.
194 * @param dialogue Y.Node The dialogue
197 center_dialogue : function(dialogue) {
198 var bb = this.panel.get('boundingBox'),
199 winheight = bb.get('winHeight'),
200 winwidth = bb.get('winWidth'),
202 newheight, totalheight, dialoguetop, dialoguewidth, dialogueleft;
204 // Try and set a sensible max-height -- this must be done before setting the top
205 // Set a default height of 640px
206 newheight = this.get('maxheight');
207 if (winheight <= newheight) {
208 // Deal with smaller window sizes
209 if (winheight <= this.get('minheight')) {
210 newheight = this.get('minheight');
212 newheight = winheight;
216 // Set a fixed position if the window is large enough
217 if (newheight > this.get('minheight')) {
218 bb.setStyle('position', 'fixed');
219 // Disable the page scrollbars
221 Y.one('html').setStyle('overflow', 'hidden');
223 Y.one('body').setStyle('overflow', 'hidden');
226 bb.setStyle('position', 'absolute');
227 offsettop = Y.one('window').get('scrollTop');
228 // Ensure that the page scrollbars are enabled
230 Y.one('html').setStyle('overflow', this.initialoverflow);
232 Y.one('body').setStyle('overflow', this.initialoverflow);
236 // Take off 15px top and bottom for borders, plus 40px each for the title and button area before setting the
238 totalheight = newheight;
239 newheight = newheight - (15 + 15 + 40 + 40);
240 dialogue.setStyle('maxHeight', newheight + 'px');
242 dialogueheight = bb.getStyle('height');
243 if (dialogueheight.match(/.*px$/)) {
244 dialogueheight = dialogueheight.replace(/px$/, '');
246 dialogueheight = totalheight;
249 if (dialogueheight < this.get('baseheight')) {
250 dialogueheight = this.get('baseheight');
251 dialogue.setStyle('height', dialogueheight + 'px');
255 // Re-calculate the location now that we've changed the size
256 dialoguetop = Math.max(12, ((winheight - dialogueheight) / 2)) + offsettop;
258 // We need to set the height for the yui3-widget - can't work
259 // out what we're setting at present -- shoud be the boudingBox
260 bb.setStyle('top', dialoguetop + 'px');
262 // Calculate the left location of the chooser
263 // We don't set a minimum width in the same way as we do height as the width would be far lower than the
264 // optimal width for moodle anyway.
265 dialoguewidth = bb.get('offsetWidth');
266 dialogueleft = (winwidth - dialoguewidth) / 2;
267 bb.setStyle('left', dialogueleft + 'px');
270 handle_key_press : function(e) {
271 if (e.keyCode === 27) {
272 this.cancel_popup(e);
276 cancel_popup : function (e) {
277 // Prevent normal form submission before hiding
283 // Cancel all listen events
284 this.cancel_listenevents();
286 // Re-enable the page scrollbars
288 Y.one('html').setStyle('overflow', this.initialoverflow);
290 Y.one('body').setStyle('overflow', this.initialoverflow);
293 this.container.detachAll();
297 check_options : function() {
298 // Check which options are set, and change the parent class
299 // to show/hide help as required
300 this.options.each(function(thisoption) {
301 var optiondiv = thisoption.get('parentNode').get('parentNode');
302 if (thisoption.get('checked')) {
303 optiondiv.addClass('selected');
305 // Trigger any events for this option
306 this.option_selected(thisoption);
308 // Ensure that the form may be submitted
309 this.submitbutton.removeAttribute('disabled');
311 // Ensure that the radio remains focus so that keyboard navigation is still possible
314 optiondiv.removeClass('selected');
319 option_selected : function() {
323 NAME : 'moodle-core-chooserdialogue',
335 validator : Y.Lang.isString,
340 M.core = M.core || {};
341 M.core.chooserdialogue = CHOOSERDIALOGUE;