]> git.mjollnir.org Git - moodle.git/commitdiff
formslib dates: MDL-16592 show a pop-up calendar for picking dates.
authortjhunt <tjhunt>
Fri, 13 Mar 2009 09:56:53 +0000 (09:56 +0000)
committertjhunt <tjhunt>
Fri, 13 Mar 2009 09:56:53 +0000 (09:56 +0000)
Not quite finished. There is a small issue with keyboard focus. See bug.

lib/form/dateselector.php
lib/form/datetimeselector.php
lib/formslib.php
lib/javascript-static.js
theme/standard/styles_layout.css

index 799f9915364ccc1f142c77559193775e9cd4b509..9aa9e455b7f51fe771e35466af317b0ab0c29ef9 100644 (file)
@@ -179,6 +179,7 @@ class MoodleQuickForm_date_selector extends MoodleQuickForm_group
 
     function toHtml()
     {
+        form_init_date_js();
         include_once('HTML/QuickForm/Renderer/Default.php');
         $renderer =& new HTML_QuickForm_Renderer_Default();
         $renderer->setElementTemplate('{element}');
index e5f4abe38504a804aa599b00d0058e918f2531db..e9d480fedfec15657a962cdb049d64cf3b6bc537 100644 (file)
@@ -197,6 +197,7 @@ class MoodleQuickForm_date_time_selector extends MoodleQuickForm_group{
 
     function toHtml()
     {
+        form_init_date_js();
         include_once('HTML/QuickForm/Renderer/Default.php');
         $renderer =& new HTML_QuickForm_Renderer_Default();
         $renderer->setElementTemplate('{element}');
index 1e7f9d2c30eb313a17aedc3d894e7f675487398d..731e776800c06388f90733504c3565a9f542953e 100644 (file)
@@ -43,6 +43,19 @@ if ($CFG->debug >= DEBUG_ALL){
     PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'pear_handle_error');
 }
 
+function form_init_date_js() {
+    global $CFG;
+    static $done = false;
+    if (!$done) {
+        echo '<style type="text/css">';
+        echo '@import "' . $CFG->httpswwwroot . '/lib/yui/calendar/assets/skins/sam/calendar.css";';
+        echo '@import "' . $CFG->httpswwwroot . '/lib/yui/calendar/assets/skins/sam/container.css";';
+        echo '</style>';
+        require_js(array('yui_yahoo', 'yui_dom', 'yui_event', 'yui_calendar', 'yui_container'));
+        print_delayed_js_call(1, 'init_date_selectors', array(get_string('firstdayofweek')));
+        $done = true;
+    }
+}
 
 /**
  * Moodle specific wrapper that separates quickforms syntax from moodle code. You won't directly
index efb68c660f348e8e31d2827ac646ecb6b611c3d2..de6996cf131a24b06fe50f5960b9ae67986bd141 100644 (file)
@@ -332,7 +332,194 @@ function unmaskPassword(id) {
   pw.parentNode.replaceChild(newpw, pw);
 }
 
-/*
+/**
+ * Search a Moodle form to find all the fdate_time_selector and fdate_selector
+ * elements, and add date_selector_calendar instance to each.
+ */
+function init_date_selectors(firstdayofweek) {
+    YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam');
+    var els = YAHOO.util.Dom.getElementsByClassName('fdate_time_selector', 'fieldset');
+    for (var i = 0; i < els.length; i++) {
+        new date_selector_calendar(els[i], firstdayofweek);
+    }
+    els = YAHOO.util.Dom.getElementsByClassName('fdate_selector', 'fieldset');
+    for (i = 0; i < els.length; i++) {
+        new date_selector_calendar(els[i], firstdayofweek);
+    }
+}
+
+/**
+ * Constructor for a JavaScritp object that connects to a fdate_time_selector
+ * or a fdate_selector in a Moodle form, and shows a popup calendar whenever
+ * that element has keyboard focus.
+ * @param el the fieldset class="fdate_time_selector" or "fdate_selector".
+ */
+function date_selector_calendar(el, firstdayofweek) {
+    // Ensure that the shared div and calendar exist.
+    if (!date_selector_calendar.panel) {
+        date_selector_calendar.panel = new YAHOO.widget.Panel('date_selector_calendar_panel',
+                {visible: false, close: false, draggable: false});
+        var div = document.createElement('div');
+        date_selector_calendar.panel.setBody(div);
+        date_selector_calendar.panel.render(document.body);
+
+        YAHOO.util.Event.addListener(document, 'click', date_selector_calendar.document_click);
+        date_selector_calendar.panel.showEvent.subscribe(function() {
+            date_selector_calendar.panel.fireEvent('changeContent');
+        });
+
+        date_selector_calendar.calendar = new YAHOO.widget.Calendar(div,
+                {iframe: false, hide_blank_weeks: true, start_weekday: firstdayofweek});
+        date_selector_calendar.calendar.renderEvent.subscribe(function() {
+            date_selector_calendar.panel.fireEvent('changeContent');
+        });
+
+        // TODO, find a way to hide the calendar when shift-tabbing.
+//        date_selector_calendar.calendar.render(); 
+//        var prev_month_link = YAHOO.util.Dom.getElementsByClassName('calnavleft', 'a', div)[0];
+//        YAHOO.util.Event.addBlurListener(prev_month_link, this.blur_event, this);
+    }
+
+    this.fieldset = el;
+    var controls = el.getElementsByTagName('select');
+    for (var i = 0; i < controls.length; i++) {
+        YAHOO.util.Event.addFocusListener(controls[i], this.focus_event, this);
+        YAHOO.util.Event.addBlurListener(controls[i], this.blur_event, this);
+        if (/\[year\]$/.test(controls[i].name)) {
+            this.yearselect = controls[i];
+        }
+        if (/\[month\]$/.test(controls[i].name)) {
+            this.monthselect = controls[i];
+        }
+        if (/\[day\]$/.test(controls[i].name)) {
+            this.dayselect = controls[i];
+        }
+    }
+    if (!(this.yearselect && this.monthselect && this.dayselect)) {
+        throw 'Failed to initialise calendar.';
+    }
+
+    this.enablecheckbox = el.getElementsByTagName('input')[0];
+    if (this.enablecheckbox) {
+        YAHOO.util.Event.addFocusListener(this.enablecheckbox, this.focus_event, this);
+        YAHOO.util.Event.addListener(this.enablecheckbox, 'change', this.focus_event, this);
+        YAHOO.util.Event.addBlurListener(this.enablecheckbox, this.blur_event, this);
+    }
+}
+
+/** The pop-up calendar that contains the calendar. */
+date_selector_calendar.panel = null;
+
+/** The shared YAHOO.widget.Calendar used by all date_selector_calendars. */
+date_selector_calendar.calendar = null;
+
+/** The date_selector_calendar that currently owns the shared stuff. */
+date_selector_calendar.currentowner = null;
+
+/** Used as a timeout when hiding the calendar on blur - so we don't hide the calendar
+ * if we are just jumping from on of our controls to another. */
+date_selector_calendar.hidetimeout = null;
+
+
+date_selector_calendar.prototype.fieldset = null;
+date_selector_calendar.prototype.yearselect = null;
+date_selector_calendar.prototype.monthselect = null;
+date_selector_calendar.prototype.dayselect = null;
+date_selector_calendar.prototype.enablecheckbox = null;
+
+date_selector_calendar.prototype.cancel_any_timeout = function() {
+    if (date_selector_calendar.hidetimeout) {
+        clearTimeout(date_selector_calendar.hidetimeout);
+        date_selector_calendar.hidetimeout = null;
+    }
+}
+
+date_selector_calendar.prototype.focus_event = function(e, me) {
+    me.cancel_any_timeout();
+    if (me.enablecheckbox == null || me.enablecheckbox.checked) {
+        me.claim_calendar();
+    } else {
+        if (date_selector_calendar.currentowner) {
+            date_selector_calendar.currentowner.release_calendar();
+        }
+    }
+}
+
+date_selector_calendar.prototype.blur_event = function(e, me) {
+    date_selector_calendar.hidetimeout = setTimeout(function() {me.release_calendar()}, 200);
+}
+
+date_selector_calendar.prototype.handle_select_change = function(e, me) {
+    me.set_date_from_selects();
+}
+
+date_selector_calendar.document_click = function(event) {
+    if (date_selector_calendar.currentowner) {
+        var currentcontainer = date_selector_calendar.currentowner.fieldset;
+        var eventarget = YAHOO.util.Event.getTarget(event);
+        if (!YAHOO.util.Dom.isAncestor(currentcontainer, eventarget)) {
+            date_selector_calendar.currentowner.release_calendar();
+        }
+    }
+} 
+
+date_selector_calendar.prototype.claim_calendar = function() {
+    this.cancel_any_timeout();
+    if (date_selector_calendar.currentowner == this) {
+        return;
+    }
+    if (date_selector_calendar.currentowner) {
+        date_selector_calendar.currentowner.release_calendar();
+    }
+
+    date_selector_calendar.calendar.cfg.setProperty('mindate', new Date(this.yearselect.options[0].value, 0, 1));
+    date_selector_calendar.calendar.cfg.setProperty('maxdate', new Date(this.yearselect.options[this.yearselect.options.length - 1].value, 11, 31));
+    this.fieldset.insertBefore(date_selector_calendar.panel.element, this.fieldset.firstChild);
+    this.set_date_from_selects();
+    date_selector_calendar.panel.show();
+    var me = this;
+    setTimeout(function() {me.cancel_any_timeout()}, 100);
+
+    if (date_selector_calendar.currentowner != this) {
+        this.connect_handlers();
+    }
+
+    date_selector_calendar.currentowner = this;
+}
+
+date_selector_calendar.prototype.set_date_from_selects = function() {
+    var year = parseInt(this.yearselect.value);
+    var month = parseInt(this.monthselect.value) - 1;
+    var day = parseInt(this.dayselect.value);
+    date_selector_calendar.calendar.select(new Date(year, month, day));
+    date_selector_calendar.calendar.setMonth(month);
+    date_selector_calendar.calendar.setYear(year);
+    date_selector_calendar.calendar.render(); 
+    date_selector_calendar.panel.cfg.setProperty('context', [this.fieldset, 'bl', 'tl']);
+}
+
+date_selector_calendar.prototype.set_selects_from_date = function(eventtype, args) {
+    var date = args[0][0];
+    var newyear = date[0];
+    var newindex = newyear - this.yearselect.options[0].value;
+    this.yearselect.selectedIndex = newindex;
+    this.monthselect.selectedIndex = date[1] - this.monthselect.options[0].value;
+    this.dayselect.selectedIndex = date[2] - this.dayselect.options[0].value;
+}
+
+date_selector_calendar.prototype.connect_handlers = function() {
+    YAHOO.util.Event.addListener([this.yearselect, this.monthselect, this.dayselect], 'change', this.handle_select_change, this);
+    date_selector_calendar.calendar.selectEvent.subscribe(this.set_selects_from_date, this, true);
+}
+
+date_selector_calendar.prototype.release_calendar = function() {
+    date_selector_calendar.panel.hide();
+    date_selector_calendar.currentowner = null;
+    YAHOO.util.Event.removeListener([this.yearselect, this.monthselect, this.dayselect], this.handle_select_change);
+    date_selector_calendar.calendar.selectEvent.unsubscribe(this.set_selects_from_date, this);
+}
+
+/**
     elementToggleHide (element, elementFinder)
 
     If elementFinder is not provided, toggles the "hidden" class for the specified element.
@@ -747,4 +934,4 @@ function close_window_reloading_opener() {
         close_window();
         // Intentionally, only try to close the window if there is some evidence we are in a popup.
     }
-}
\ No newline at end of file
+}
index 306943a7ecb3f980ff579bb41e1f7689347832b4..d145d57f2b70779ec5ebe233205d9228c73b8b9a 100644 (file)
@@ -655,6 +655,19 @@ fieldset.fdate_selector label {
   width: auto;
 }
 
+#date_selector_calendar_panel .bd {
+    padding: 0;
+}
+
+#date_selector_calendar_panel .yui-calcontainer {
+    border: none;
+    float: none;
+}
+/* Prevent border-collapse:collapse from bleeding through in IE6, IE7 */
+#date_selector_calendar_panel.yui-overlay-hidden table {
+    *display:none;
+}
+
 .mform div.felement,  .mform fieldset.felement{
   display: block;
   float: left;
@@ -4333,7 +4346,6 @@ body#mod-forum-search .introcontent {
   text-align: left;
   margin-top: 1.5em;
 }
-#mod-quiz-summary #quiz-timer,
 #mod-quiz-summary .submitbtns {
   margin-top: 1.5em;
 }
@@ -4345,11 +4357,10 @@ body#mod-forum-search .introcontent {
   height: 16px;
   vertical-align: middle;
 }
-#mod-quiz-summary #quiz-timer,
 #mod-quiz-attempt #quiz-timer {
-    display: none;
+  display: none;
 }
-#quiz-timer #quiz-time-left {
+#mod-quiz-attempt #quiz-time-left {
   font-weight: bold;
 }