Merge branch 'MDL-39056-download-api-version' of git://github.com/mudrd8mz/moodle
[moodle.git] / lib / form / yui / dateselector / dateselector.js
1 YUI.add('moodle-form-dateselector', function(Y) {
3     /**
4      * Add some custom methods to the node class to make our lives a little
5      * easier within this module.
6      */
7     Y.mix(Y.Node.prototype, {
8         /**
9          * Gets the value of the first option in the select box
10          */
11         firstOptionValue : function() {
12             if (this.get('nodeName').toLowerCase() != 'select') {
13                 return false;
14             }
15             return this.one('option').get('value');
16         },
17         /**
18          * Gets the value of the last option in the select box
19          */
20         lastOptionValue : function() {
21             if (this.get('nodeName').toLowerCase() != 'select') {
22                 return false;
23             }
24             return this.all('option').item(this.optionSize()-1).get('value');
25         },
26         /**
27          * Gets the number of options in the select box
28          */
29         optionSize : function() {
30             if (this.get('nodeName').toLowerCase() != 'select') {
31                 return false;
32             }
33             return parseInt(this.all('option').size());
34         },
35         /**
36          * Gets the value of the selected option in the select box
37          */
38         selectedOptionValue : function() {
39             if (this.get('nodeName').toLowerCase() != 'select') {
40                 return false;
41             }
42             return this.all('option').item(this.get('selectedIndex')).get('value');
43         }
44     });
46     /**
47      * Calendar class
48      *
49      * This is our main class
50      */
51     var CALENDAR = function(config) {
52         CALENDAR.superclass.constructor.apply(this, arguments);
53     };
54     CALENDAR.prototype = {
55         panel : null,
56         yearselect : null,
57         monthselect : null,
58         dayselect : null,
59         calendarimage : null,
60         enablecheckbox : null,
61         closepopup : true,
62         initializer : function(config) {
63             var controls = this.get('node').all('select');
64             controls.each(function(node){
65                 if (node.get('name').match(/\[year]/)) {
66                     this.yearselect = node;
67                 } else if (node.get('name').match(/\[month\]/)) {
68                     this.monthselect = node;
69                 } else if (node.get('name').match(/\[day]/)) {
70                     this.dayselect = node;
71                 }
72                 node.after('change', this.handle_select_change, this);
73             }, this);
75             // Loop through the input fields.
76             var inputs = this.get('node').all('input');
77             inputs.each(function(node) {
78                 // Check if the current node is a calendar image field.
79                 if (node.get('name').match(/\[calendar]/)) {
80                     // Set it so that when the image is clicked the pop-up displays.
81                     node.on('click', this.focus_event, this);
82                     // Set the node to the calendarimage variable.
83                     this.calendarimage = node;
84                 } else { // Must be the enabled checkbox field.
85                     // If the enable checkbox is clicked we want to either disable/enable the calendar image.
86                     node.on('click', this.toggle_calendar_image, this);
87                     // Set the node to the enablecheckbox variable.
88                     this.enablecheckbox = node;
89                     // Set the calendar icon status depending on the value of the checkbox.
90                     this.toggle_calendar_image();
91                 }
92             }, this);
93         },
94         focus_event : function(e) {
95             M.form.dateselector.cancel_any_timeout();
96             // If the current owner is set, then the pop-up is currently being displayed, so hide it.
97             if (M.form.dateselector.currentowner) {
98                 this.release_calendar();
99             } else if ((this.enablecheckbox == null)
100                 || (this.enablecheckbox.get('checked'))) { // Must be hidden. If the field is enabled display the pop-up.
101                 this.claim_calendar();
102             }
103             // Stop the input image field from submitting the form.
104             e.preventDefault();
105         },
106         handle_select_change : function(e) {
107             // It may seem as if the following variable is not used, however any call to set_date_from_selects will trigger a
108             // call to set_selects_from_date if the calendar is open as the date has changed. Whenever the calendar is displayed
109             // the set_selects_from_date function is set to trigger on any date change (see function connect_handlers).
110             this.closepopup = false;
111             this.set_date_from_selects();
112             this.closepopup = true;
113         },
114         claim_calendar : function() {
115             M.form.dateselector.cancel_any_timeout();
116             this.connect_handlers();
117             this.set_date_from_selects();
118             M.form.dateselector.currentowner = this;
119             M.form.dateselector.calendar.cfg.setProperty('mindate', new Date(this.yearselect.firstOptionValue(), 0, 1));
120             M.form.dateselector.calendar.cfg.setProperty('maxdate', new Date(this.yearselect.lastOptionValue(), 11, 31));
121             M.form.dateselector.panel.show();
122             M.form.dateselector.fix_position();
123             setTimeout(function(){M.form.dateselector.cancel_any_timeout()}, 100);
124         },
125         set_date_from_selects : function() {
126             var year = parseInt(this.yearselect.get('value'));
127             var month = parseInt(this.monthselect.get('value')) - 1;
128             var day = parseInt(this.dayselect.get('value'));
129             M.form.dateselector.calendar.select(new Date(year, month, day));
130             M.form.dateselector.calendar.setMonth(month);
131             M.form.dateselector.calendar.setYear(year);
132             M.form.dateselector.calendar.render();
133         },
134         set_selects_from_date : function(eventtype, args) {
135             var date = args[0][0];
136             var newyear = date[0];
137             var newindex = newyear - this.yearselect.firstOptionValue();
138             this.yearselect.set('selectedIndex', newindex);
139             this.monthselect.set('selectedIndex', date[1] - this.monthselect.firstOptionValue());
140             this.dayselect.set('selectedIndex', date[2] - this.dayselect.firstOptionValue());
141             if (M.form.dateselector.currentowner && this.closepopup) {
142                 this.release_calendar();
143             }
144         },
145         connect_handlers : function() {
146             M.form.dateselector.calendar.selectEvent.subscribe(this.set_selects_from_date, this, true);
147         },
148         release_calendar : function() {
149             M.form.dateselector.panel.hide();
150             M.form.dateselector.currentowner = null;
151             M.form.dateselector.calendar.selectEvent.unsubscribe(this.set_selects_from_date, this);
152         },
153         toggle_calendar_image : function() {
154             // If the enable checkbox is not checked, disable the image.
155             if (!this.enablecheckbox.get('checked')) {
156                 this.calendarimage.set('disabled', 'disabled');
157                 this.calendarimage.setStyle('cursor', 'default');
158             } else {
159                 this.calendarimage.set('disabled', false);
160                 this.calendarimage.setStyle('cursor', 'auto');
161             }
162         }
163     };
164     Y.extend(CALENDAR, Y.Base, CALENDAR.prototype, {
165         NAME : 'Date Selector',
166         ATTRS : {
167             firstdayofweek  : {
168                 validator : Y.Lang.isString
169             },
170             node : {
171                 setter : function(node) {
172                     return Y.one(node);
173                 }
174             }
175         }
176     });
178     M.form = M.form || {};
179     M.form.dateselector = {
180         panel : null,
181         calendar : null,
182         currentowner : null,
183         hidetimeout : null,
184         repositiontimeout : null,
185         init_date_selectors : function(config) {
186             if (this.panel === null) {
187                 this.initPanel(config);
188             }
189             Y.all('fieldset.fdate_time_selector').each(function(){
190                 config.node = this;
191                 new CALENDAR(config);
192             });
193             Y.all('fieldset.fdate_selector').each(function(){
194                 config.node = this;
195                 new CALENDAR(config);
196             });
197         },
198         initPanel : function(config) {
199             this.panel = new Y.Overlay({
200                 visible : false,
201                 bodyContent : Y.Node.create('<div id="dateselector-calendar-content"></div>'),
202                 id : 'dateselector-calendar-panel'
203             });
204             this.panel.render(document.body);
205             this.panel.on('heightChange', this.fix_position, this);
207             Y.one('#dateselector-calendar-panel').on('click', function(e){e.halt();});
208             Y.one(document.body).on('click', this.document_click, this);
210             this.calendar = new Y.YUI2.widget.Calendar(document.getElementById('dateselector-calendar-content'), {
211                 iframe: false,
212                 hide_blank_weeks: true,
213                 start_weekday: config.firstdayofweek,
214                 locale_weekdays: 'medium',
215                 locale_months: 'long',
216                 WEEKDAYS_MEDIUM: [
217                     config.sun,
218                     config.mon,
219                     config.tue,
220                     config.wed,
221                     config.thu,
222                     config.fri,
223                     config.sat ],
224                 MONTHS_LONG: [
225                     config.january,
226                     config.february,
227                     config.march,
228                     config.april,
229                     config.may,
230                     config.june,
231                     config.july,
232                     config.august,
233                     config.september,
234                     config.october,
235                     config.november,
236                     config.december ]
237             });
238             this.calendar.changePageEvent.subscribe(function(){
239                 this.fix_position();
240             }, this);
241         },
242         cancel_any_timeout : function() {
243             if (this.hidetimeout) {
244                 clearTimeout(this.hidetimeout);
245                 this.hidetimeout = null;
246             }
247             if (this.repositiontimeout) {
248                 clearTimeout(this.repositiontimeout);
249                 this.repositiontimeout = null;
250             }
251         },
252         delayed_reposition : function() {
253             if (this.repositiontimeout) {
254                 clearTimeout(this.repositiontimeout);
255                 this.repositiontimeout = null;
256             }
257             this.repositiontimeout = setTimeout(this.fix_position, 500);
258         },
259         fix_position : function() {
260             if (this.currentowner) {
261                 this.panel.set('align', {
262                     node:this.currentowner.get('node').one('select'),
263                     points:[Y.WidgetPositionAlign.BL, Y.WidgetPositionAlign.TL]
264                 });
265             }
266         },
267         document_click : function(e) {
268             if (this.currentowner) {
269                 if (this.currentowner.get('node').ancestor('div').contains(e.target)) {
270                     setTimeout(function() {M.form.dateselector.cancel_any_timeout()}, 100);
271                 } else {
272                     this.currentowner.release_calendar();
273                 }
274             }
275         }
276     }
278 }, '@VERSION@', {requires:['base','node','overlay', 'yui2-calendar', 'moodle-form-dateselector-skin']});