Merge branch 'MDL-48943-master' of git://github.com/andrewnicols/moodle
This commit is contained in:
+36
-33
@@ -179,7 +179,7 @@ function calendar_get_starting_weekday() {
|
||||
*/
|
||||
function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyear = false, $placement = false,
|
||||
$courseid = false, $time = 0) {
|
||||
global $CFG, $OUTPUT;
|
||||
global $CFG, $OUTPUT, $PAGE;
|
||||
|
||||
// Get the calendar type we are using.
|
||||
$calendartype = \core_calendar\type_factory::get_calendar_instance();
|
||||
@@ -289,7 +289,8 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
|
||||
// Accessibility: added summary and <abbr> elements.
|
||||
$summary = get_string('calendarheading', 'calendar', userdate($display->tstart, get_string('strftimemonthyear')));
|
||||
$content .= '<table class="minicalendar calendartable" summary="'.$summary.'">'; // Begin table.
|
||||
// Begin table.
|
||||
$content .= '<table class="minicalendar calendartable" summary="' . $summary . '">';
|
||||
if (($placement !== false) && ($courseid !== false)) {
|
||||
$content .= '<caption>'. calendar_top_controls($placement, array('id' => $courseid, 'time' => $time)) .'</caption>';
|
||||
}
|
||||
@@ -320,6 +321,7 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
// Now display all the calendar
|
||||
$daytime = strtotime('-1 day', $display->tstart);
|
||||
for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
|
||||
$cellattributes = array();
|
||||
$daytime = strtotime('+1 day', $daytime);
|
||||
if($dayweek > $display->maxwday) {
|
||||
// We need to change week (table row)
|
||||
@@ -336,8 +338,8 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
$class = 'day';
|
||||
}
|
||||
|
||||
// Special visual fx if an event is defined
|
||||
if(isset($eventsbyday[$day])) {
|
||||
if (isset($eventsbyday[$day])) {
|
||||
// There is at least one event on this day.
|
||||
|
||||
$class .= ' hasevent';
|
||||
$hrefparams['view'] = 'day';
|
||||
@@ -381,12 +383,12 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
$popupcontent .= html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
//Accessibility: functionality moved to calendar_get_popup.
|
||||
if($display->thismonth && $day == $d) {
|
||||
$popupid = calendar_get_popup(true, $events[$eventid]->timestart, $popupcontent);
|
||||
if ($display->thismonth && $day == $d) {
|
||||
$popupdata = calendar_get_popup(true, $events[$eventid]->timestart, $popupcontent);
|
||||
} else {
|
||||
$popupid = calendar_get_popup(false, $events[$eventid]->timestart, $popupcontent);
|
||||
$popupdata = calendar_get_popup(false, $events[$eventid]->timestart, $popupcontent);
|
||||
}
|
||||
$cellattributes = array_merge($cellattributes, $popupdata);
|
||||
|
||||
// Class and cell content
|
||||
if(isset($typesbyday[$day]['startglobal'])) {
|
||||
@@ -398,7 +400,7 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
} else if(isset($typesbyday[$day]['startuser'])) {
|
||||
$class .= ' calendar_event_user';
|
||||
}
|
||||
$cell = html_writer::link($dayhref, $day, array('id' => $popupid));
|
||||
$cell = html_writer::link($dayhref, $day);
|
||||
} else {
|
||||
$cell = $day;
|
||||
}
|
||||
@@ -432,25 +434,23 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
}
|
||||
}
|
||||
|
||||
// Special visual fx for today
|
||||
//Accessibility: hidden text for today, and popup.
|
||||
if($display->thismonth && $day == $d) {
|
||||
if ($display->thismonth && $day == $d) {
|
||||
// The current cell is for today - add appropriate classes and additional information for styling.
|
||||
$class .= ' today';
|
||||
$today = get_string('today', 'calendar').' '.userdate(time(), get_string('strftimedayshort'));
|
||||
|
||||
if(! isset($eventsbyday[$day])) {
|
||||
if (!isset($eventsbyday[$day])) {
|
||||
$class .= ' eventnone';
|
||||
$popupid = calendar_get_popup(true, false);
|
||||
$cell = html_writer::link('#', $day, array('id' => $popupid));
|
||||
$popupdata = calendar_get_popup(true, false);
|
||||
$cellattributes = array_merge($cellattributes, $popupdata);
|
||||
$cell = html_writer::link('#', $day);
|
||||
}
|
||||
$cell = get_accesshide($today.' ').$cell;
|
||||
$cell = get_accesshide($today . ' ') . $cell;
|
||||
}
|
||||
|
||||
// Just display it
|
||||
if(!empty($class)) {
|
||||
$class = ' class="'.$class.'"';
|
||||
}
|
||||
$content .= '<td'.$class.'>'.$cell."</td>\n";
|
||||
$cellattributes['class'] = $class;
|
||||
$content .= html_writer::tag('td', $cell, $cellattributes);
|
||||
}
|
||||
|
||||
// Paddding (the last week may have blank days at the end)
|
||||
@@ -461,6 +461,11 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
|
||||
$content .= '</table>'; // Tabular display of days ends
|
||||
|
||||
static $jsincluded = false;
|
||||
if (!$jsincluded) {
|
||||
$PAGE->requires->yui_module('moodle-calendar-info', 'Y.M.core_calendar.info.init');
|
||||
$jsincluded = true;
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
@@ -475,28 +480,26 @@ function calendar_get_mini($courses, $groups, $users, $calmonth = false, $calyea
|
||||
* @param string $popupcontent content for the popup window/layout.
|
||||
* @return string eventid for the calendar_tooltip popup window/layout.
|
||||
*/
|
||||
function calendar_get_popup($is_today, $event_timestart, $popupcontent='') {
|
||||
function calendar_get_popup($today = false, $timestart, $popupcontent = '') {
|
||||
global $PAGE;
|
||||
static $popupcount;
|
||||
if ($popupcount === null) {
|
||||
$popupcount = 1;
|
||||
}
|
||||
|
||||
$popupcaption = '';
|
||||
if($is_today) {
|
||||
$popupcaption = get_string('today', 'calendar').' ';
|
||||
if ($today) {
|
||||
$popupcaption = get_string('today', 'calendar') . ' ';
|
||||
}
|
||||
if (false === $event_timestart) {
|
||||
|
||||
if (false === $timestart) {
|
||||
$popupcaption .= userdate(time(), get_string('strftimedayshort'));
|
||||
$popupcontent = get_string('eventnone', 'calendar');
|
||||
|
||||
} else {
|
||||
$popupcaption .= get_string('eventsfor', 'calendar', userdate($event_timestart, get_string('strftimedayshort')));
|
||||
$popupcaption .= get_string('eventsfor', 'calendar', userdate($timestart, get_string('strftimedayshort')));
|
||||
}
|
||||
$id = 'calendar_tooltip_'.$popupcount;
|
||||
$PAGE->requires->yui_module('moodle-calendar-eventmanager', 'M.core_calendar.add_event', array(array('eventId'=>$id,'title'=>$popupcaption, 'content'=>$popupcontent)));
|
||||
|
||||
$popupcount++;
|
||||
return $id;
|
||||
return array(
|
||||
'data-core_calendar-title' => $popupcaption,
|
||||
'data-core_calendar-popupcontent' => $popupcontent,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,7 @@ use Behat\Gherkin\Node\TableNode as TableNode;
|
||||
class behat_calendar extends behat_base {
|
||||
|
||||
/**
|
||||
* Create event.
|
||||
* Create event when starting on the front page.
|
||||
*
|
||||
* @Given /^I create a calendar event with form data:$/
|
||||
* @param TableNode $data
|
||||
@@ -53,10 +53,60 @@ class behat_calendar extends behat_base {
|
||||
|
||||
return array(
|
||||
new Given('I follow "' . get_string('monththis', 'calendar') . '"'),
|
||||
new Given('I create a calendar event:', $data),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create event.
|
||||
*
|
||||
* @Given /^I create a calendar event:$/
|
||||
* @param TableNode $data
|
||||
* @return array the list of actions to perform
|
||||
*/
|
||||
public function i_create_a_calendar_event($data) {
|
||||
// Get the event name.
|
||||
$eventname = $data->getRow(1);
|
||||
$eventname = $eventname[1];
|
||||
|
||||
return array(
|
||||
new Given('I click on "' . get_string('newevent', 'calendar') .'" "button"'),
|
||||
new Given('I set the following fields to these values:', $data),
|
||||
new Given('I press "' . get_string('savechanges') . '"'),
|
||||
new Given('I should see "' . $eventname . '"')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hover over a specific day in the calendar.
|
||||
*
|
||||
* @Given /^I hover over day "(?P<dayofmonth>\d+)" of this month in the calendar$/
|
||||
* @param int $day The day of the current month
|
||||
* @return Given[]
|
||||
*/
|
||||
public function i_hover_over_day_of_this_month_in_calendar($day) {
|
||||
$summarytitle = get_string('calendarheading', 'calendar', userdate(time(), get_string('strftimemonthyear')));
|
||||
// The current month table.
|
||||
$currentmonth = "table[contains(concat(' ', normalize-space(@summary), ' '), ' {$summarytitle} ')]";
|
||||
|
||||
// Strings for the class cell match.
|
||||
$cellclasses = "contains(concat(' ', normalize-space(@class), ' '), ' day ')";
|
||||
$daycontains = "text()[contains(concat(' ', normalize-space(.), ' '), ' {$day} ')]";
|
||||
$daycell = "td[{$cellclasses}]";
|
||||
$dayofmonth = "a[{$daycontains}]";
|
||||
return array(
|
||||
new Given('I hover "//' . $currentmonth . '/descendant::' . $daycell . '/' . $dayofmonth . '" "xpath_element"'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hover over today in the calendar.
|
||||
*
|
||||
* @Given /^I hover over today in the calendar$/
|
||||
* @return Given[]
|
||||
*/
|
||||
public function i_hover_over_today_in_the_calendar() {
|
||||
$todaysday = trim(strftime('%e'));
|
||||
return $this->i_hover_over_day_of_this_month_in_calendar($todaysday);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
@core @core_calendar @arn
|
||||
Feature: Open calendar popup
|
||||
In order to view calendar information
|
||||
As a user
|
||||
I need to interact with the calendar
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "admin"
|
||||
|
||||
@javascript
|
||||
Scenario: I view calendar details of a day with multiple events
|
||||
Given I follow "This month"
|
||||
And I create a calendar event:
|
||||
| Type of event | site |
|
||||
| Event title | Event 1:1 |
|
||||
| timestart[day] | 1 |
|
||||
And I create a calendar event:
|
||||
| Type of event | site |
|
||||
| Event title | Event 1:2 |
|
||||
| timestart[day] | 1 |
|
||||
When I hover over day "1" of this month in the calendar
|
||||
Then I should see "Event 1:1"
|
||||
And I should see "Event 1:2"
|
||||
And I follow "Home"
|
||||
And I hover over day "1" of this month in the calendar
|
||||
And I should see "Event 1:1"
|
||||
And I should see "Event 1:2"
|
||||
|
||||
@javascript
|
||||
Scenario: I view calendar details for today
|
||||
Given I follow "This month"
|
||||
And I create a calendar event:
|
||||
| Type of event | site |
|
||||
| Event title | Today's event |
|
||||
When I hover over today in the calendar
|
||||
Then I should see "Today's event"
|
||||
And I follow "Home"
|
||||
And I hover over today in the calendar
|
||||
And I should see "Today's event"
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
YUI.add('moodle-calendar-eventmanager', function (Y, NAME) {
|
||||
|
||||
var ENAME = 'Calendar event',
|
||||
EVENTID = 'eventId',
|
||||
EVENTNODE = 'node',
|
||||
EVENTTITLE = 'title',
|
||||
EVENTCONTENT = 'content',
|
||||
EVENTDELAY = 'delay',
|
||||
SHOWTIMEOUT = 'showTimeout',
|
||||
HIDETIMEOUT = 'hideTimeout',
|
||||
|
||||
EVENT = function() {
|
||||
EVENT.superclass.constructor.apply(this, arguments);
|
||||
},
|
||||
EVENTMANAGER;
|
||||
|
||||
Y.extend(EVENT, Y.Base, {
|
||||
initpanelcalled : false,
|
||||
initializer : function(){
|
||||
this.get(EVENTID);
|
||||
var node = this.get(EVENTNODE),
|
||||
td;
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
td = node.ancestor('td');
|
||||
this.publish('showevent');
|
||||
this.publish('hideevent');
|
||||
td.on('mouseenter', this.startShow, this);
|
||||
td.on('mouseleave', this.startHide, this);
|
||||
td.on('focus', this.startShow, this);
|
||||
td.on('blur', this.startHide, this);
|
||||
return true;
|
||||
},
|
||||
initPanel : function() {
|
||||
if (!this.initpanelcalled) {
|
||||
this.initpanelcalled = true;
|
||||
var node = this.get(EVENTNODE),
|
||||
td = node.ancestor('td'),
|
||||
constraint = td.ancestor('div'),
|
||||
panel;
|
||||
panel = new Y.Overlay({
|
||||
constrain : constraint,
|
||||
align : {
|
||||
node : td,
|
||||
points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BC]
|
||||
},
|
||||
headerContent : Y.Node.create('<h2 class="eventtitle">'+this.get(EVENTTITLE)+'</h2>'),
|
||||
bodyContent : Y.Node.create('<div class="eventcontent">'+this.get(EVENTCONTENT)+'</div>'),
|
||||
visible : false,
|
||||
id : this.get(EVENTID)+'_panel',
|
||||
width : Math.floor(constraint.get('offsetWidth')*0.9)+"px"
|
||||
});
|
||||
panel.render(td);
|
||||
node.setAttribute('aria-controls', panel.get('id'));
|
||||
panel.get('boundingBox').addClass('calendar-event-panel');
|
||||
panel.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
this.on('showevent', panel.show, panel);
|
||||
this.on('showevent', this.setAriashow, panel);
|
||||
this.on('hideevent', this.setAriahide, panel);
|
||||
this.on('hideevent', panel.hide, panel);
|
||||
}
|
||||
},
|
||||
startShow : function() {
|
||||
this.cancelHide();
|
||||
if (this.get(SHOWTIMEOUT) !== null) {
|
||||
this.cancelShow();
|
||||
}
|
||||
var self = this;
|
||||
this.set(SHOWTIMEOUT, setTimeout(function(){self.show();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
cancelShow : function() {
|
||||
clearTimeout(this.get(SHOWTIMEOUT));
|
||||
},
|
||||
setAriashow : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'assertive');
|
||||
},
|
||||
setAriahide : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
},
|
||||
show : function() {
|
||||
this.initPanel();
|
||||
this.fire('showevent');
|
||||
},
|
||||
startHide : function() {
|
||||
this.cancelShow();
|
||||
if (this.get(HIDETIMEOUT) !== null) {
|
||||
this.cancelHide();
|
||||
}
|
||||
var self = this;
|
||||
this.set(HIDETIMEOUT, setTimeout(function(){self.hide();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
hide : function() {
|
||||
this.fire('hideevent');
|
||||
},
|
||||
cancelHide : function() {
|
||||
clearTimeout(this.get(HIDETIMEOUT));
|
||||
}
|
||||
}, {
|
||||
NAME : ENAME,
|
||||
ATTRS : {
|
||||
eventId : {
|
||||
setter : function(nodeid) {
|
||||
this.set(EVENTNODE, Y.one('#'+nodeid));
|
||||
return nodeid;
|
||||
},
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
node : {
|
||||
setter : function(node) {
|
||||
if (typeof(node) === 'string') {
|
||||
node = Y.one('#'+node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
},
|
||||
title : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
content : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
delay : {
|
||||
value : 300,
|
||||
validator : Y.Lang.isNumber
|
||||
},
|
||||
showTimeout : {
|
||||
value : null
|
||||
},
|
||||
hideTimeout : {
|
||||
value : null
|
||||
}
|
||||
}
|
||||
});
|
||||
Y.augment(EVENT, Y.EventTarget);
|
||||
|
||||
EVENTMANAGER = {
|
||||
add_event : function(config) {
|
||||
new EVENT(config);
|
||||
}
|
||||
};
|
||||
|
||||
M.core_calendar = M.core_calendar || {};
|
||||
Y.mix(M.core_calendar, EVENTMANAGER);
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event-mouseenter", "overlay", "moodle-calendar-eventmanager-skin"]});
|
||||
-1
@@ -1 +0,0 @@
|
||||
YUI.add("moodle-calendar-eventmanager",function(e,t){var n="Calendar event",r="eventId",i="node",s="title",o="content",u="delay",a="showTimeout",f="hideTimeout",l=function(){l.superclass.constructor.apply(this,arguments)},c;e.extend(l,e.Base,{initpanelcalled:!1,initializer:function(){this.get(r);var e=this.get(i),t;return e?(t=e.ancestor("td"),this.publish("showevent"),this.publish("hideevent"),t.on("mouseenter",this.startShow,this),t.on("mouseleave",this.startHide,this),t.on("focus",this.startShow,this),t.on("blur",this.startHide,this),!0):!1},initPanel:function(){if(!this.initpanelcalled){this.initpanelcalled=!0;var t=this.get(i),n=t.ancestor("td"),u=n.ancestor("div"),a;a=new e.Overlay({constrain:u,align:{node:n,points:[e.WidgetPositionAlign.TL,e.WidgetPositionAlign.BC]},headerContent:e.Node.create('<h2 class="eventtitle">'+this.get(s)+"</h2>"),bodyContent:e.Node.create('<div class="eventcontent">'+this.get(o)+"</div>"),visible:!1,id:this.get(r)+"_panel",width:Math.floor(u.get("offsetWidth")*.9)+"px"}),a.render(n),t.setAttribute("aria-controls",a.get("id")),a.get("boundingBox").addClass("calendar-event-panel"),a.get("boundingBox").setAttribute("aria-live","off"),this.on("showevent",a.show,a),this.on("showevent",this.setAriashow,a),this.on("hideevent",this.setAriahide,a),this.on("hideevent",a.hide,a)}},startShow:function(){this.cancelHide(),this.get(a)!==null&&this.cancelShow();var e=this;this.set(a,setTimeout(function(){e.show()},this.get(u)))},cancelShow:function(){clearTimeout(this.get(a))},setAriashow:function(){this.get("boundingBox").setAttribute("aria-live","assertive")},setAriahide:function(){this.get("boundingBox").setAttribute("aria-live","off")},show:function(){this.initPanel(),this.fire("showevent")},startHide:function(){this.cancelShow(),this.get(f)!==null&&this.cancelHide();var e=this;this.set(f,setTimeout(function(){e.hide()},this.get(u)))},hide:function(){this.fire("hideevent")},cancelHide:function(){clearTimeout(this.get(f))}},{NAME:n,ATTRS:{eventId:{setter:function(t){return this.set(i,e.one("#"+t)),t},validator:e.Lang.isString},node:{setter:function(t){return typeof t=="string"&&(t=e.one("#"+t)),t}},title:{validator:e.Lang.isString},content:{validator:e.Lang.isString},delay:{value:300,validator:e.Lang.isNumber},showTimeout:{value:null},hideTimeout:{value:null}}}),e.augment(l,e.EventTarget),c={add_event:function(e){new l(e)}},M.core_calendar=M.core_calendar||{},e.mix(M.core_calendar,c)},"@VERSION@",{requires:["base","node","event-mouseenter","overlay","moodle-calendar-eventmanager-skin"]});
|
||||
-147
@@ -1,147 +0,0 @@
|
||||
YUI.add('moodle-calendar-eventmanager', function (Y, NAME) {
|
||||
|
||||
var ENAME = 'Calendar event',
|
||||
EVENTID = 'eventId',
|
||||
EVENTNODE = 'node',
|
||||
EVENTTITLE = 'title',
|
||||
EVENTCONTENT = 'content',
|
||||
EVENTDELAY = 'delay',
|
||||
SHOWTIMEOUT = 'showTimeout',
|
||||
HIDETIMEOUT = 'hideTimeout',
|
||||
|
||||
EVENT = function() {
|
||||
EVENT.superclass.constructor.apply(this, arguments);
|
||||
},
|
||||
EVENTMANAGER;
|
||||
|
||||
Y.extend(EVENT, Y.Base, {
|
||||
initpanelcalled : false,
|
||||
initializer : function(){
|
||||
this.get(EVENTID);
|
||||
var node = this.get(EVENTNODE),
|
||||
td;
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
td = node.ancestor('td');
|
||||
this.publish('showevent');
|
||||
this.publish('hideevent');
|
||||
td.on('mouseenter', this.startShow, this);
|
||||
td.on('mouseleave', this.startHide, this);
|
||||
td.on('focus', this.startShow, this);
|
||||
td.on('blur', this.startHide, this);
|
||||
return true;
|
||||
},
|
||||
initPanel : function() {
|
||||
if (!this.initpanelcalled) {
|
||||
this.initpanelcalled = true;
|
||||
var node = this.get(EVENTNODE),
|
||||
td = node.ancestor('td'),
|
||||
constraint = td.ancestor('div'),
|
||||
panel;
|
||||
panel = new Y.Overlay({
|
||||
constrain : constraint,
|
||||
align : {
|
||||
node : td,
|
||||
points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BC]
|
||||
},
|
||||
headerContent : Y.Node.create('<h2 class="eventtitle">'+this.get(EVENTTITLE)+'</h2>'),
|
||||
bodyContent : Y.Node.create('<div class="eventcontent">'+this.get(EVENTCONTENT)+'</div>'),
|
||||
visible : false,
|
||||
id : this.get(EVENTID)+'_panel',
|
||||
width : Math.floor(constraint.get('offsetWidth')*0.9)+"px"
|
||||
});
|
||||
panel.render(td);
|
||||
node.setAttribute('aria-controls', panel.get('id'));
|
||||
panel.get('boundingBox').addClass('calendar-event-panel');
|
||||
panel.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
this.on('showevent', panel.show, panel);
|
||||
this.on('showevent', this.setAriashow, panel);
|
||||
this.on('hideevent', this.setAriahide, panel);
|
||||
this.on('hideevent', panel.hide, panel);
|
||||
}
|
||||
},
|
||||
startShow : function() {
|
||||
this.cancelHide();
|
||||
if (this.get(SHOWTIMEOUT) !== null) {
|
||||
this.cancelShow();
|
||||
}
|
||||
var self = this;
|
||||
this.set(SHOWTIMEOUT, setTimeout(function(){self.show();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
cancelShow : function() {
|
||||
clearTimeout(this.get(SHOWTIMEOUT));
|
||||
},
|
||||
setAriashow : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'assertive');
|
||||
},
|
||||
setAriahide : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
},
|
||||
show : function() {
|
||||
this.initPanel();
|
||||
this.fire('showevent');
|
||||
},
|
||||
startHide : function() {
|
||||
this.cancelShow();
|
||||
if (this.get(HIDETIMEOUT) !== null) {
|
||||
this.cancelHide();
|
||||
}
|
||||
var self = this;
|
||||
this.set(HIDETIMEOUT, setTimeout(function(){self.hide();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
hide : function() {
|
||||
this.fire('hideevent');
|
||||
},
|
||||
cancelHide : function() {
|
||||
clearTimeout(this.get(HIDETIMEOUT));
|
||||
}
|
||||
}, {
|
||||
NAME : ENAME,
|
||||
ATTRS : {
|
||||
eventId : {
|
||||
setter : function(nodeid) {
|
||||
this.set(EVENTNODE, Y.one('#'+nodeid));
|
||||
return nodeid;
|
||||
},
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
node : {
|
||||
setter : function(node) {
|
||||
if (typeof(node) === 'string') {
|
||||
node = Y.one('#'+node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
},
|
||||
title : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
content : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
delay : {
|
||||
value : 300,
|
||||
validator : Y.Lang.isNumber
|
||||
},
|
||||
showTimeout : {
|
||||
value : null
|
||||
},
|
||||
hideTimeout : {
|
||||
value : null
|
||||
}
|
||||
}
|
||||
});
|
||||
Y.augment(EVENT, Y.EventTarget);
|
||||
|
||||
EVENTMANAGER = {
|
||||
add_event : function(config) {
|
||||
new EVENT(config);
|
||||
}
|
||||
};
|
||||
|
||||
M.core_calendar = M.core_calendar || {};
|
||||
Y.mix(M.core_calendar, EVENTMANAGER);
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event-mouseenter", "overlay", "moodle-calendar-eventmanager-skin"]});
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
.calendar-event-panel {background-color:#666;border:2px solid #666;border-width: 0 2px 2px 0;}
|
||||
.calendar-event-panel .yui3-overlay-content {background-color:#fff;border:1px solid #555;margin-top:-5px;margin-left:-5px;}
|
||||
.calendar-event-panel .yui3-overlay-content h2.eventtitle {margin:3px 5px 2px;padding:0;text-align:center;}
|
||||
.calendar-event-panel .eventcontent {margin:5px;padding:0;text-align:center;}
|
||||
.calendar-event-panel .eventcontent {margin:5px;padding:0;text-align:center;}
|
||||
@@ -0,0 +1,295 @@
|
||||
YUI.add('moodle-calendar-info', function (Y, NAME) {
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle Calendar.
|
||||
*
|
||||
* @module moodle-core_calendar-info
|
||||
* @package core_calendar
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core_calendar-info
|
||||
*/
|
||||
|
||||
var ARIACONTROLS = 'aria-controls',
|
||||
ARIALIVE = 'aria-live',
|
||||
BOUNDINGBOX = 'boundingBox',
|
||||
CALENDAREVENT = '[data-core_calendar-title]',
|
||||
CALENDARTABLE = 'calendartable',
|
||||
DATAPREFIX = 'core_calendar-',
|
||||
DOT = '.',
|
||||
EVENTCONTENT = 'eventcontent',
|
||||
EVENTDELAY = 'delay',
|
||||
EVENTTITLE = 'eventtitle',
|
||||
INNERHTML = 'innerHTML',
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle calendar.
|
||||
*
|
||||
* @namespace M.core_calendar
|
||||
* @class Info
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
Info = function() {
|
||||
Info.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
|
||||
|
||||
Y.extend(Info, Y.Base, {
|
||||
/**
|
||||
* A pointer to the timer used for showing the panel.
|
||||
*
|
||||
* @property _showTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_showTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer to the timer used for hiding the panel.
|
||||
*
|
||||
* @property _hideTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_hideTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer for the Calendar Overlay.
|
||||
*
|
||||
* @property _panel
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_panel: null,
|
||||
|
||||
/**
|
||||
* A pointer to the cell containing the currently open calendar day.
|
||||
*
|
||||
* @property _currentDay
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_currentDay: null,
|
||||
|
||||
initializer: function() {
|
||||
var body = Y.one(Y.config.doc.body);
|
||||
body.delegate(['mouseenter', 'focus'], this._startShow, CALENDAREVENT, this);
|
||||
body.delegate(['mouseleave', 'blur'], this._startHide, CALENDAREVENT, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialise the Overlay in which information is displayed.
|
||||
*
|
||||
* @method __initOverlay
|
||||
* @chainable
|
||||
*/
|
||||
_initOverlay: function() {
|
||||
if (!this._panel) {
|
||||
this._panel = new Y.Overlay({
|
||||
headerContent: Y.Node.create('<h2 class="' + EVENTTITLE + '"/>'),
|
||||
bodyContent: Y.Node.create('<div class="' + EVENTCONTENT + '"/>'),
|
||||
visible: false,
|
||||
render: true
|
||||
});
|
||||
|
||||
this._panel.get(BOUNDINGBOX)
|
||||
.addClass('calendar-event-panel')
|
||||
.setAttribute(ARIALIVE, 'off');
|
||||
|
||||
this._panel.on('visibleChange', function(e) {
|
||||
// Assume showing.
|
||||
var state = 'assertive';
|
||||
if (e.prevVal && !e.newVal) {
|
||||
// Hiding.
|
||||
state = 'off';
|
||||
}
|
||||
this.get(BOUNDINGBOX).setAttribute(ARIALIVE, state);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to show the Overlay, and kick off the jobs that cause it to be shown.
|
||||
*
|
||||
* @method _startShow
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startShow: function(e) {
|
||||
if (this._isCurrentDayVisible(e.currentTarget)) {
|
||||
// Only start the show if the current day isn't already visible.
|
||||
return;
|
||||
}
|
||||
|
||||
this._cancelHide()
|
||||
._cancelShow()
|
||||
|
||||
// Initialise the panel now - this will only happen once. This way
|
||||
// it's ready for when the timer times out.
|
||||
._initOverlay();
|
||||
|
||||
|
||||
this._showTimer = setTimeout(Y.bind(function() {
|
||||
var calendarCell = e.target.ancestor(CALENDAREVENT, true);
|
||||
this._show(calendarCell);
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the Overlay immediately.
|
||||
*
|
||||
* @method _show
|
||||
* @param {Node} dayCell The location that the Overlay should be displayed.
|
||||
*/
|
||||
_show: function(dayCell) {
|
||||
var bb = this._panel.get(BOUNDINGBOX),
|
||||
widgetPositionAlign = Y.WidgetPositionAlign,
|
||||
calendarParent = dayCell.ancestor(DOT + CALENDARTABLE);
|
||||
|
||||
bb.one(DOT + EVENTTITLE).set(INNERHTML, dayCell.getData(DATAPREFIX + 'title'));
|
||||
bb.one(DOT + EVENTCONTENT).set(INNERHTML, dayCell.getData(DATAPREFIX + 'popupcontent'));
|
||||
|
||||
// Set the ARIA attributes for the owning cell.
|
||||
if (this._currentDay) {
|
||||
this._currentDay.setAttribute(ARIACONTROLS, null);
|
||||
}
|
||||
dayCell.setAttribute(ARIACONTROLS, dayCell.get('id'));
|
||||
|
||||
// Move the panel to the current target.
|
||||
dayCell.appendChild(bb);
|
||||
|
||||
// Keep track of the new day being shown.
|
||||
this._currentDay = dayCell;
|
||||
|
||||
this._panel.constrain(calendarParent);
|
||||
this._panel
|
||||
.set('width', calendarParent.get('offsetWidth') + 'px')
|
||||
// Align it with the area clicked.
|
||||
.align(calendarParent, [
|
||||
widgetPositionAlign.TC,
|
||||
widgetPositionAlign.TC
|
||||
])
|
||||
// Show it.
|
||||
.show();
|
||||
|
||||
bb.setAttribute('tabindex', '0')
|
||||
.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be shown.
|
||||
*
|
||||
* @method _cancelShow
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelShow: function() {
|
||||
if (this._showTimer) {
|
||||
clearTimeout(this._showTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to hide the Overlay, and kick off the jobs that cause it to be hidden.
|
||||
*
|
||||
* @method _startHide
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startHide: function(e) {
|
||||
if (e.type === 'blur' && e.currentTarget.contains(e.target)) {
|
||||
return;
|
||||
}
|
||||
this._cancelShow()
|
||||
._cancelHide();
|
||||
this._hideTimer = setTimeout(Y.bind(function() {
|
||||
this._hide();
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the Overlay immediately.
|
||||
*
|
||||
* @method _hide
|
||||
*/
|
||||
_hide: function() {
|
||||
if (this._panel) {
|
||||
this._panel.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be hidden.
|
||||
*
|
||||
* @method _cancelHide
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelHide: function() {
|
||||
if (this._hideTimer) {
|
||||
clearTimeout(this._hideTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the specified day is currently visible.
|
||||
*
|
||||
* @method _isCurrentDayVisible
|
||||
* @param specifiedDay {Node} The Node to check visibility for.
|
||||
* @private
|
||||
*/
|
||||
_isCurrentDayVisible: function(specifiedDay) {
|
||||
if (!this._panel || !this._panel.get('visible')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specifiedDay !== this._currentDay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
NAME: 'calendarInfo',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The delay to use before showing or hiding the calendar.
|
||||
*
|
||||
* @attribute delay
|
||||
* @type Number
|
||||
* @default 300
|
||||
*/
|
||||
delay: {
|
||||
value: 300
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Y.namespace('M.core_calendar.info').init = function(config) {
|
||||
return new Info(config);
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event-mouseenter", "event-key", "overlay", "moodle-calendar-info-skin"]});
|
||||
@@ -0,0 +1 @@
|
||||
YUI.add("moodle-calendar-info",function(e,t){var n="aria-controls",r="aria-live",i="boundingBox",s="[data-core_calendar-title]",o="calendartable",u="core_calendar-",a=".",f="eventcontent",l="delay",c="eventtitle",h="innerHTML",p=function(){p.superclass.constructor.apply(this,arguments)};e.extend(p,e.Base,{_showTimer:null,_hideTimer:null,_panel:null,_currentDay:null,initializer:function(){var t=e.one(e.config.doc.body);t.delegate(["mouseenter","focus"],this._startShow,s,this),t.delegate(["mouseleave","blur"],this._startHide,s,this)},_initOverlay:function(){return this._panel||(this._panel=new e.Overlay({headerContent:e.Node.create('<h2 class="'+c+'"/>'),bodyContent:e.Node.create('<div class="'+f+'"/>'),visible:!1,render:!0}),this._panel.get(i).addClass("calendar-event-panel").setAttribute(r,"off"),this._panel.on("visibleChange",function(e){var t="assertive";e.prevVal&&!e.newVal&&(t="off"),this.get(i).setAttribute(r,t)})),this},_startShow:function(t){if(this._isCurrentDayVisible(t.currentTarget))return;this._cancelHide()._cancelShow()._initOverlay(),this._showTimer=setTimeout(e.bind(function(){var e=t.target.ancestor(s,!0);this._show(e)},this),this.get(l))},_show:function(t){var r=this._panel.get(i),s=e.WidgetPositionAlign,l=t.ancestor(a+o);r.one(a+c).set(h,t.getData(u+"title")),r.one(a+f).set(h,t.getData(u+"popupcontent")),this._currentDay&&this._currentDay.setAttribute(n,null),t.setAttribute(n,t.get("id")),t.appendChild(r),this._currentDay=t,this._panel.constrain(l),this._panel.set("width",l.get("offsetWidth")+"px").align(l,[s.TC,s.TC]).show(),r.setAttribute("tabindex","0").focus()},_cancelShow:function(){return this._showTimer&&clearTimeout(this._showTimer),this},_startHide:function(t){if(t.type==="blur"&&t.currentTarget.contains(t.target))return;this._cancelShow()._cancelHide(),this._hideTimer=setTimeout(e.bind(function(){this._hide()},this),this.get(l))},_hide:function(){this._panel&&this._panel.hide()},_cancelHide:function(){return this._hideTimer&&clearTimeout(this._hideTimer),this},_isCurrentDayVisible:function(e){return!this._panel||!this._panel.get("visible")?!1:e!==this._currentDay?!1:!0}},{NAME:"calendarInfo",ATTRS:{delay:{value:300}}}),e.namespace("M.core_calendar.info").init=function(e){return new p(e)}},"@VERSION@",{requires:["base","node","event-mouseenter","event-key","overlay","moodle-calendar-info-skin"]});
|
||||
@@ -0,0 +1,295 @@
|
||||
YUI.add('moodle-calendar-info', function (Y, NAME) {
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle Calendar.
|
||||
*
|
||||
* @module moodle-core_calendar-info
|
||||
* @package core_calendar
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core_calendar-info
|
||||
*/
|
||||
|
||||
var ARIACONTROLS = 'aria-controls',
|
||||
ARIALIVE = 'aria-live',
|
||||
BOUNDINGBOX = 'boundingBox',
|
||||
CALENDAREVENT = '[data-core_calendar-title]',
|
||||
CALENDARTABLE = 'calendartable',
|
||||
DATAPREFIX = 'core_calendar-',
|
||||
DOT = '.',
|
||||
EVENTCONTENT = 'eventcontent',
|
||||
EVENTDELAY = 'delay',
|
||||
EVENTTITLE = 'eventtitle',
|
||||
INNERHTML = 'innerHTML',
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle calendar.
|
||||
*
|
||||
* @namespace M.core_calendar
|
||||
* @class Info
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
Info = function() {
|
||||
Info.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
|
||||
|
||||
Y.extend(Info, Y.Base, {
|
||||
/**
|
||||
* A pointer to the timer used for showing the panel.
|
||||
*
|
||||
* @property _showTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_showTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer to the timer used for hiding the panel.
|
||||
*
|
||||
* @property _hideTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_hideTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer for the Calendar Overlay.
|
||||
*
|
||||
* @property _panel
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_panel: null,
|
||||
|
||||
/**
|
||||
* A pointer to the cell containing the currently open calendar day.
|
||||
*
|
||||
* @property _currentDay
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_currentDay: null,
|
||||
|
||||
initializer: function() {
|
||||
var body = Y.one(Y.config.doc.body);
|
||||
body.delegate(['mouseenter', 'focus'], this._startShow, CALENDAREVENT, this);
|
||||
body.delegate(['mouseleave', 'blur'], this._startHide, CALENDAREVENT, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialise the Overlay in which information is displayed.
|
||||
*
|
||||
* @method __initOverlay
|
||||
* @chainable
|
||||
*/
|
||||
_initOverlay: function() {
|
||||
if (!this._panel) {
|
||||
this._panel = new Y.Overlay({
|
||||
headerContent: Y.Node.create('<h2 class="' + EVENTTITLE + '"/>'),
|
||||
bodyContent: Y.Node.create('<div class="' + EVENTCONTENT + '"/>'),
|
||||
visible: false,
|
||||
render: true
|
||||
});
|
||||
|
||||
this._panel.get(BOUNDINGBOX)
|
||||
.addClass('calendar-event-panel')
|
||||
.setAttribute(ARIALIVE, 'off');
|
||||
|
||||
this._panel.on('visibleChange', function(e) {
|
||||
// Assume showing.
|
||||
var state = 'assertive';
|
||||
if (e.prevVal && !e.newVal) {
|
||||
// Hiding.
|
||||
state = 'off';
|
||||
}
|
||||
this.get(BOUNDINGBOX).setAttribute(ARIALIVE, state);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to show the Overlay, and kick off the jobs that cause it to be shown.
|
||||
*
|
||||
* @method _startShow
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startShow: function(e) {
|
||||
if (this._isCurrentDayVisible(e.currentTarget)) {
|
||||
// Only start the show if the current day isn't already visible.
|
||||
return;
|
||||
}
|
||||
|
||||
this._cancelHide()
|
||||
._cancelShow()
|
||||
|
||||
// Initialise the panel now - this will only happen once. This way
|
||||
// it's ready for when the timer times out.
|
||||
._initOverlay();
|
||||
|
||||
|
||||
this._showTimer = setTimeout(Y.bind(function() {
|
||||
var calendarCell = e.target.ancestor(CALENDAREVENT, true);
|
||||
this._show(calendarCell);
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the Overlay immediately.
|
||||
*
|
||||
* @method _show
|
||||
* @param {Node} dayCell The location that the Overlay should be displayed.
|
||||
*/
|
||||
_show: function(dayCell) {
|
||||
var bb = this._panel.get(BOUNDINGBOX),
|
||||
widgetPositionAlign = Y.WidgetPositionAlign,
|
||||
calendarParent = dayCell.ancestor(DOT + CALENDARTABLE);
|
||||
|
||||
bb.one(DOT + EVENTTITLE).set(INNERHTML, dayCell.getData(DATAPREFIX + 'title'));
|
||||
bb.one(DOT + EVENTCONTENT).set(INNERHTML, dayCell.getData(DATAPREFIX + 'popupcontent'));
|
||||
|
||||
// Set the ARIA attributes for the owning cell.
|
||||
if (this._currentDay) {
|
||||
this._currentDay.setAttribute(ARIACONTROLS, null);
|
||||
}
|
||||
dayCell.setAttribute(ARIACONTROLS, dayCell.get('id'));
|
||||
|
||||
// Move the panel to the current target.
|
||||
dayCell.appendChild(bb);
|
||||
|
||||
// Keep track of the new day being shown.
|
||||
this._currentDay = dayCell;
|
||||
|
||||
this._panel.constrain(calendarParent);
|
||||
this._panel
|
||||
.set('width', calendarParent.get('offsetWidth') + 'px')
|
||||
// Align it with the area clicked.
|
||||
.align(calendarParent, [
|
||||
widgetPositionAlign.TC,
|
||||
widgetPositionAlign.TC
|
||||
])
|
||||
// Show it.
|
||||
.show();
|
||||
|
||||
bb.setAttribute('tabindex', '0')
|
||||
.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be shown.
|
||||
*
|
||||
* @method _cancelShow
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelShow: function() {
|
||||
if (this._showTimer) {
|
||||
clearTimeout(this._showTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to hide the Overlay, and kick off the jobs that cause it to be hidden.
|
||||
*
|
||||
* @method _startHide
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startHide: function(e) {
|
||||
if (e.type === 'blur' && e.currentTarget.contains(e.target)) {
|
||||
return;
|
||||
}
|
||||
this._cancelShow()
|
||||
._cancelHide();
|
||||
this._hideTimer = setTimeout(Y.bind(function() {
|
||||
this._hide();
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the Overlay immediately.
|
||||
*
|
||||
* @method _hide
|
||||
*/
|
||||
_hide: function() {
|
||||
if (this._panel) {
|
||||
this._panel.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be hidden.
|
||||
*
|
||||
* @method _cancelHide
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelHide: function() {
|
||||
if (this._hideTimer) {
|
||||
clearTimeout(this._hideTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the specified day is currently visible.
|
||||
*
|
||||
* @method _isCurrentDayVisible
|
||||
* @param specifiedDay {Node} The Node to check visibility for.
|
||||
* @private
|
||||
*/
|
||||
_isCurrentDayVisible: function(specifiedDay) {
|
||||
if (!this._panel || !this._panel.get('visible')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specifiedDay !== this._currentDay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
NAME: 'calendarInfo',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The delay to use before showing or hiding the calendar.
|
||||
*
|
||||
* @attribute delay
|
||||
* @type Number
|
||||
* @default 300
|
||||
*/
|
||||
delay: {
|
||||
value: 300
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Y.namespace('M.core_calendar.info').init = function(config) {
|
||||
return new Info(config);
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event-mouseenter", "event-key", "overlay", "moodle-calendar-info-skin"]});
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "moodle-calendar-eventmanager",
|
||||
"builds": {
|
||||
"moodle-calendar-eventmanager": {
|
||||
"jsfiles": [
|
||||
"eventmanager.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
var ENAME = 'Calendar event',
|
||||
EVENTID = 'eventId',
|
||||
EVENTNODE = 'node',
|
||||
EVENTTITLE = 'title',
|
||||
EVENTCONTENT = 'content',
|
||||
EVENTDELAY = 'delay',
|
||||
SHOWTIMEOUT = 'showTimeout',
|
||||
HIDETIMEOUT = 'hideTimeout',
|
||||
|
||||
EVENT = function() {
|
||||
EVENT.superclass.constructor.apply(this, arguments);
|
||||
},
|
||||
EVENTMANAGER;
|
||||
|
||||
Y.extend(EVENT, Y.Base, {
|
||||
initpanelcalled : false,
|
||||
initializer : function(){
|
||||
this.get(EVENTID);
|
||||
var node = this.get(EVENTNODE),
|
||||
td;
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
td = node.ancestor('td');
|
||||
this.publish('showevent');
|
||||
this.publish('hideevent');
|
||||
td.on('mouseenter', this.startShow, this);
|
||||
td.on('mouseleave', this.startHide, this);
|
||||
td.on('focus', this.startShow, this);
|
||||
td.on('blur', this.startHide, this);
|
||||
return true;
|
||||
},
|
||||
initPanel : function() {
|
||||
if (!this.initpanelcalled) {
|
||||
this.initpanelcalled = true;
|
||||
var node = this.get(EVENTNODE),
|
||||
td = node.ancestor('td'),
|
||||
constraint = td.ancestor('div'),
|
||||
panel;
|
||||
panel = new Y.Overlay({
|
||||
constrain : constraint,
|
||||
align : {
|
||||
node : td,
|
||||
points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BC]
|
||||
},
|
||||
headerContent : Y.Node.create('<h2 class="eventtitle">'+this.get(EVENTTITLE)+'</h2>'),
|
||||
bodyContent : Y.Node.create('<div class="eventcontent">'+this.get(EVENTCONTENT)+'</div>'),
|
||||
visible : false,
|
||||
id : this.get(EVENTID)+'_panel',
|
||||
width : Math.floor(constraint.get('offsetWidth')*0.9)+"px"
|
||||
});
|
||||
panel.render(td);
|
||||
node.setAttribute('aria-controls', panel.get('id'));
|
||||
panel.get('boundingBox').addClass('calendar-event-panel');
|
||||
panel.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
this.on('showevent', panel.show, panel);
|
||||
this.on('showevent', this.setAriashow, panel);
|
||||
this.on('hideevent', this.setAriahide, panel);
|
||||
this.on('hideevent', panel.hide, panel);
|
||||
}
|
||||
},
|
||||
startShow : function() {
|
||||
this.cancelHide();
|
||||
if (this.get(SHOWTIMEOUT) !== null) {
|
||||
this.cancelShow();
|
||||
}
|
||||
var self = this;
|
||||
this.set(SHOWTIMEOUT, setTimeout(function(){self.show();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
cancelShow : function() {
|
||||
clearTimeout(this.get(SHOWTIMEOUT));
|
||||
},
|
||||
setAriashow : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'assertive');
|
||||
},
|
||||
setAriahide : function() {
|
||||
this.get('boundingBox').setAttribute('aria-live', 'off');
|
||||
},
|
||||
show : function() {
|
||||
this.initPanel();
|
||||
this.fire('showevent');
|
||||
},
|
||||
startHide : function() {
|
||||
this.cancelShow();
|
||||
if (this.get(HIDETIMEOUT) !== null) {
|
||||
this.cancelHide();
|
||||
}
|
||||
var self = this;
|
||||
this.set(HIDETIMEOUT, setTimeout(function(){self.hide();}, this.get(EVENTDELAY)));
|
||||
},
|
||||
hide : function() {
|
||||
this.fire('hideevent');
|
||||
},
|
||||
cancelHide : function() {
|
||||
clearTimeout(this.get(HIDETIMEOUT));
|
||||
}
|
||||
}, {
|
||||
NAME : ENAME,
|
||||
ATTRS : {
|
||||
eventId : {
|
||||
setter : function(nodeid) {
|
||||
this.set(EVENTNODE, Y.one('#'+nodeid));
|
||||
return nodeid;
|
||||
},
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
node : {
|
||||
setter : function(node) {
|
||||
if (typeof(node) === 'string') {
|
||||
node = Y.one('#'+node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
},
|
||||
title : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
content : {
|
||||
validator : Y.Lang.isString
|
||||
},
|
||||
delay : {
|
||||
value : 300,
|
||||
validator : Y.Lang.isNumber
|
||||
},
|
||||
showTimeout : {
|
||||
value : null
|
||||
},
|
||||
hideTimeout : {
|
||||
value : null
|
||||
}
|
||||
}
|
||||
});
|
||||
Y.augment(EVENT, Y.EventTarget);
|
||||
|
||||
EVENTMANAGER = {
|
||||
add_event : function(config) {
|
||||
new EVENT(config);
|
||||
}
|
||||
};
|
||||
|
||||
M.core_calendar = M.core_calendar || {};
|
||||
Y.mix(M.core_calendar, EVENTMANAGER);
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
.calendar-event-panel {background-color:#666;border:2px solid #666;border-width: 0 2px 2px 0;}
|
||||
.calendar-event-panel .yui3-overlay-content {background-color:#fff;border:1px solid #555;margin-top:-5px;margin-left:-5px;}
|
||||
.calendar-event-panel .yui3-overlay-content h2.eventtitle {margin:3px 5px 2px;padding:0;text-align:center;}
|
||||
.calendar-event-panel .eventcontent {margin:5px;padding:0;text-align:center;}
|
||||
.calendar-event-panel .eventcontent {margin:5px;padding:0;text-align:center;}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "moodle-calendar-info",
|
||||
"builds": {
|
||||
"moodle-calendar-info": {
|
||||
"jsfiles": [
|
||||
"info.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+290
@@ -0,0 +1,290 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle Calendar.
|
||||
*
|
||||
* @module moodle-core_calendar-info
|
||||
* @package core_calendar
|
||||
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @main moodle-core_calendar-info
|
||||
*/
|
||||
|
||||
var ARIACONTROLS = 'aria-controls',
|
||||
ARIALIVE = 'aria-live',
|
||||
BOUNDINGBOX = 'boundingBox',
|
||||
CALENDAREVENT = '[data-core_calendar-title]',
|
||||
CALENDARTABLE = 'calendartable',
|
||||
DATAPREFIX = 'core_calendar-',
|
||||
DOT = '.',
|
||||
EVENTCONTENT = 'eventcontent',
|
||||
EVENTDELAY = 'delay',
|
||||
EVENTTITLE = 'eventtitle',
|
||||
INNERHTML = 'innerHTML',
|
||||
|
||||
/**
|
||||
* Overlay manager for the Moodle calendar.
|
||||
*
|
||||
* @namespace M.core_calendar
|
||||
* @class Info
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
Info = function() {
|
||||
Info.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
|
||||
|
||||
Y.extend(Info, Y.Base, {
|
||||
/**
|
||||
* A pointer to the timer used for showing the panel.
|
||||
*
|
||||
* @property _showTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_showTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer to the timer used for hiding the panel.
|
||||
*
|
||||
* @property _hideTimer
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_hideTimer: null,
|
||||
|
||||
/**
|
||||
* A pointer for the Calendar Overlay.
|
||||
*
|
||||
* @property _panel
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_panel: null,
|
||||
|
||||
/**
|
||||
* A pointer to the cell containing the currently open calendar day.
|
||||
*
|
||||
* @property _currentDay
|
||||
* @type object
|
||||
* @private
|
||||
*/
|
||||
_currentDay: null,
|
||||
|
||||
initializer: function() {
|
||||
var body = Y.one(Y.config.doc.body);
|
||||
body.delegate(['mouseenter', 'focus'], this._startShow, CALENDAREVENT, this);
|
||||
body.delegate(['mouseleave', 'blur'], this._startHide, CALENDAREVENT, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialise the Overlay in which information is displayed.
|
||||
*
|
||||
* @method __initOverlay
|
||||
* @chainable
|
||||
*/
|
||||
_initOverlay: function() {
|
||||
if (!this._panel) {
|
||||
this._panel = new Y.Overlay({
|
||||
headerContent: Y.Node.create('<h2 class="' + EVENTTITLE + '"/>'),
|
||||
bodyContent: Y.Node.create('<div class="' + EVENTCONTENT + '"/>'),
|
||||
visible: false,
|
||||
render: true
|
||||
});
|
||||
|
||||
this._panel.get(BOUNDINGBOX)
|
||||
.addClass('calendar-event-panel')
|
||||
.setAttribute(ARIALIVE, 'off');
|
||||
|
||||
this._panel.on('visibleChange', function(e) {
|
||||
// Assume showing.
|
||||
var state = 'assertive';
|
||||
if (e.prevVal && !e.newVal) {
|
||||
// Hiding.
|
||||
state = 'off';
|
||||
}
|
||||
this.get(BOUNDINGBOX).setAttribute(ARIALIVE, state);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to show the Overlay, and kick off the jobs that cause it to be shown.
|
||||
*
|
||||
* @method _startShow
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startShow: function(e) {
|
||||
if (this._isCurrentDayVisible(e.currentTarget)) {
|
||||
// Only start the show if the current day isn't already visible.
|
||||
return;
|
||||
}
|
||||
|
||||
this._cancelHide()
|
||||
._cancelShow()
|
||||
|
||||
// Initialise the panel now - this will only happen once. This way
|
||||
// it's ready for when the timer times out.
|
||||
._initOverlay();
|
||||
|
||||
|
||||
this._showTimer = setTimeout(Y.bind(function() {
|
||||
var calendarCell = e.target.ancestor(CALENDAREVENT, true);
|
||||
this._show(calendarCell);
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Display the Overlay immediately.
|
||||
*
|
||||
* @method _show
|
||||
* @param {Node} dayCell The location that the Overlay should be displayed.
|
||||
*/
|
||||
_show: function(dayCell) {
|
||||
var bb = this._panel.get(BOUNDINGBOX),
|
||||
widgetPositionAlign = Y.WidgetPositionAlign,
|
||||
calendarParent = dayCell.ancestor(DOT + CALENDARTABLE);
|
||||
|
||||
bb.one(DOT + EVENTTITLE).set(INNERHTML, dayCell.getData(DATAPREFIX + 'title'));
|
||||
bb.one(DOT + EVENTCONTENT).set(INNERHTML, dayCell.getData(DATAPREFIX + 'popupcontent'));
|
||||
|
||||
// Set the ARIA attributes for the owning cell.
|
||||
if (this._currentDay) {
|
||||
this._currentDay.setAttribute(ARIACONTROLS, null);
|
||||
}
|
||||
dayCell.setAttribute(ARIACONTROLS, dayCell.get('id'));
|
||||
|
||||
// Move the panel to the current target.
|
||||
dayCell.appendChild(bb);
|
||||
|
||||
// Keep track of the new day being shown.
|
||||
this._currentDay = dayCell;
|
||||
|
||||
this._panel.constrain(calendarParent);
|
||||
this._panel
|
||||
.set('width', calendarParent.get('offsetWidth') + 'px')
|
||||
// Align it with the area clicked.
|
||||
.align(calendarParent, [
|
||||
widgetPositionAlign.TC,
|
||||
widgetPositionAlign.TC
|
||||
])
|
||||
// Show it.
|
||||
.show();
|
||||
|
||||
bb.setAttribute('tabindex', '0')
|
||||
.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be shown.
|
||||
*
|
||||
* @method _cancelShow
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelShow: function() {
|
||||
if (this._showTimer) {
|
||||
clearTimeout(this._showTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare to hide the Overlay, and kick off the jobs that cause it to be hidden.
|
||||
*
|
||||
* @method _startHide
|
||||
* @param {EventFacade} e
|
||||
* @private
|
||||
*/
|
||||
_startHide: function(e) {
|
||||
if (e.type === 'blur' && e.currentTarget.contains(e.target)) {
|
||||
return;
|
||||
}
|
||||
this._cancelShow()
|
||||
._cancelHide();
|
||||
this._hideTimer = setTimeout(Y.bind(function() {
|
||||
this._hide();
|
||||
}, this), this.get(EVENTDELAY));
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide the Overlay immediately.
|
||||
*
|
||||
* @method _hide
|
||||
*/
|
||||
_hide: function() {
|
||||
if (this._panel) {
|
||||
this._panel.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the timers which would cause the overlay to be hidden.
|
||||
*
|
||||
* @method _cancelHide
|
||||
* @chainable
|
||||
* @private
|
||||
*/
|
||||
_cancelHide: function() {
|
||||
if (this._hideTimer) {
|
||||
clearTimeout(this._hideTimer);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine whether the specified day is currently visible.
|
||||
*
|
||||
* @method _isCurrentDayVisible
|
||||
* @param specifiedDay {Node} The Node to check visibility for.
|
||||
* @private
|
||||
*/
|
||||
_isCurrentDayVisible: function(specifiedDay) {
|
||||
if (!this._panel || !this._panel.get('visible')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (specifiedDay !== this._currentDay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}, {
|
||||
NAME: 'calendarInfo',
|
||||
ATTRS: {
|
||||
/**
|
||||
* The delay to use before showing or hiding the calendar.
|
||||
*
|
||||
* @attribute delay
|
||||
* @type Number
|
||||
* @default 300
|
||||
*/
|
||||
delay: {
|
||||
value: 300
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Y.namespace('M.core_calendar.info').init = function(config) {
|
||||
return new Info(config);
|
||||
};
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"moodle-calendar-eventmanager": {
|
||||
"moodle-calendar-info": {
|
||||
"requires": [
|
||||
"base",
|
||||
"node",
|
||||
"event-mouseenter",
|
||||
"event-key",
|
||||
"overlay",
|
||||
"moodle-calendar-eventmanager-skin"
|
||||
"moodle-calendar-info-skin"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -315,6 +315,11 @@
|
||||
&.weekend {
|
||||
.muted;
|
||||
}
|
||||
a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
caption {
|
||||
font-size: inherit;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user