71c77a30a240b82bbfc2f4ff605efee5d4f0cc48
[moodle.git] / lib / yui / chooserdialogue / chooserdialogue.js
1 YUI.add('moodle-core-chooserdialogue', function(Y) {
3     var CHOOSERDIALOGUE = function() {
4         CHOOSERDIALOGUE.superclass.constructor.apply(this, arguments);
5     }
7     Y.extend(CHOOSERDIALOGUE, Y.Base, {
8         // The overlay widget
9         overlay: null,
11         // The submit button - we disable this until an element is set
12         submitbutton : null,
14         // The chooserdialogue container
15         container : null,
17         // Any event listeners we may need to cancel later
18         listenevents : [],
20         setup_chooser_dialogue : function(bodycontent, headercontent, config) {
21             // Set Default options
22             var params = {
23                 bodyContent : bodycontent.get('innerHTML'),
24                 headerContent : headercontent.get('innerHTML'),
25                 visible : false, // Hide by default
26                 zindex : 100, // Display in front of other items
27                 lightbox : true, // This dialogue should be modal
28                 shim : true
29             }
31             // Override with additional options
32             for (paramkey in config) {
33               params[paramkey] = config[paramkey];
34             }
36             // Create the overlay
37             this.overlay = new M.core.dialogue(params);
39             // Remove the template for the chooser
40             bodycontent.remove();
41             headercontent.remove();
43             // Hide and then render the overlay
44             this.overlay.hide();
45             this.overlay.render();
47             // Set useful links
48             this.container = this.overlay.get('boundingBox').one('#choosercontainer');
49             this.options = this.container.all('.option input[type=radio]');
50         },
52         /**
53          * Display the module chooser
54          *
55          * @param e Event Triggering Event
56          * @return void
57          */
58         display_chooser : function (e) {
59             // Stop the default event actions before we proceed
60             e.preventDefault();
62             var bb = this.overlay.get('boundingBox');
63             var dialogue = this.container.one('.alloptions');
65             var thisevent;
67             // These will trigger a check_options call to display the correct help
68             thisevent = this.container.on('click', this.check_options, this);
69             this.listenevents.push(thisevent);
70             thisevent = this.container.on('key_up', this.check_options, this);
71             this.listenevents.push(thisevent);
72             thisevent = this.container.on('dblclick', function(e) {
73                 if (e.target.ancestor('div.option')) {
74                     this.check_options();
76                     // Prevent duplicate submissions
77                     this.submitbutton.setAttribute('disabled', 'disabled');
78                     this.options.setAttribute('disabled', 'disabled');
79                     this.cancel_listenevents();
81                     this.container.one('form').submit();
82                 }
83             }, this);
84             this.listenevents.push(thisevent);
86             this.container.one('form').on('submit', function(e) {
87                 // Prevent duplicate submissions on submit
88                 this.submitbutton.setAttribute('disabled', 'disabled');
89                 this.options.setAttribute('disabled', 'disabled');
90                 this.cancel_listenevents();
91             }, this);
93             // Hook onto the cancel button to hide the form
94             this.container.one('#addcancel').on('click', this.cancel_popup, this);
96             // Grab global keyup events and handle them
97             Y.one('document').on('keyup', this.handle_key_press, this);
99             // Add references to various elements we adjust
100             this.jumplink     = this.container.one('#jump');
101             this.submitbutton = this.container.one('#submitbutton');
103             // Disable the submit element until the user makes a selection
104             this.submitbutton.set('disabled', 'true');
106             // Ensure that the options are shown
107             this.options.removeAttribute('disabled');
109             // Display the overlay
110             this.overlay.show();
112             // Re-centre the dialogue after we've shown it.
113             this.center_dialogue(dialogue);
115             // Finally, focus the first radio element - this enables form selection via the keyboard
116             this.container.one('.option input[type=radio]').focus();
118             // Trigger check_options to set the initial jumpurl
119             this.check_options();
120         },
122         /**
123          * Cancel any listen events in the listenevents queue
124          *
125          * Several locations add event handlers which should only be called before the form is submitted. This provides
126          * a way of cancelling those events.
127          *
128          * @return void
129          */
130         cancel_listenevents : function () {
131             // Detach all listen events to prevent duplicate triggers
132             var thisevent;
133             while (thisevent = this.listenevents.shift()) {
134                 thisevent.detach();
135             }
136         },
138         /**
139          * Calculate the optimum height of the chooser dialogue
140          *
141          * This tries to set a sensible maximum and minimum to ensure that some options are always shown, and preferably
142          * all, whilst fitting the box within the current viewport.
143          *
144          * @param dialogue Y.Node The dialogue
145          * @return void
146          */
147         center_dialogue : function(dialogue) {
148             var bb = this.overlay.get('boundingBox');
150             var winheight = bb.get('winHeight');
151             var offsettop = 0;
153             // Try and set a sensible max-height -- this must be done before setting the top
154             // Set a default height of 640px
155             var newheight = this.get('maxheight');
156             if (winheight <= newheight) {
157                 // Deal with smaller window sizes
158                 if (winheight <= this.get('minheight')) {
159                     newheight = this.get('minheight');
160                 } else {
161                     newheight = winheight;
162                 }
163             }
165             // Set a fixed position if the window is large enough
166             if (newheight > this.get('minheight')) {
167                 bb.setStyle('position', 'fixed');
168             } else {
169                 bb.setStyle('position', 'absolute');
170                 offsettop = Y.one('window').get('scrollTop');
171             }
173             // Take off 15px top and bottom for borders, plus 40px each for the title and button area before setting the
174             // new max-height
175             var totalheight = newheight;
176             newheight = newheight - (15 + 15 + 40 + 40);
177             dialogue.setStyle('max-height', newheight + 'px');
178             dialogue.setStyle('height', newheight + 'px');
180             // Re-calculate the location now that we've changed the size
181             var dialoguetop = Math.max(12, ((winheight - totalheight) / 2)) + offsettop;
183             // We need to set the height for the yui3-widget - can't work
184             // out what we're setting at present -- shoud be the boudingBox
185             bb.setStyle('top', dialoguetop + 'px');
186         },
188         handle_key_press : function(e) {
189             if (e.keyCode == 27) {
190                 this.cancel_popup(e);
191             }
192         },
194         cancel_popup : function (e) {
195             // Prevent normal form submission before hiding
196             e.preventDefault();
197             this.hide();
198         },
200         hide : function() {
201             // Detach the global keypress handler before hiding
202             Y.one('document').detach('keyup', this.handle_key_press, this);
203             this.container.detachAll();
204             this.overlay.hide();
205         },
207         check_options : function(e) {
208             // Check which options are set, and change the parent class
209             // to show/hide help as required
210             this.options.each(function(thisoption) {
211                 var optiondiv = thisoption.get('parentNode').get('parentNode');
212                 if (thisoption.get('checked')) {
213                     optiondiv.addClass('selected');
215                     // Trigger any events for this option
216                     this.option_selected(thisoption);
218                     // Ensure that the form may be submitted
219                     this.submitbutton.removeAttribute('disabled');
221                     // Ensure that the radio remains focus so that keyboard navigation is still possible
222                     thisoption.focus();
223                 } else {
224                     optiondiv.removeClass('selected');
225                 }
226             }, this);
227         },
229         option_selected : function(e) {
230         }
231     },
232     {
233         NAME : 'moodle-core-chooserdialogue',
234         ATTRS : {
235             minheight : {
236                 value : 300
237             },
238             maxheight : {
239                 value : 660
240             }
241         }
242     });
243     M.core = M.core || {};
244     M.core.chooserdialogue = CHOOSERDIALOGUE;
245 },
246 '@VERSION@', {
247     requires:['base', 'overlay', 'moodle-enrol-notification']
249 );