Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
219
gaia/apps/calendar/js/views/single_day.js
Executable file
219
gaia/apps/calendar/js/views/single_day.js
Executable file
|
|
@ -0,0 +1,219 @@
|
|||
/* global IntlHelper */
|
||||
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var Overlap = require('utils/overlap');
|
||||
var buildElement = require('utils/dom').buildElement;
|
||||
var core = require('core');
|
||||
var isSameDate = require('common/calc').isSameDate;
|
||||
var relativeDuration = require('common/calc').relativeDuration;
|
||||
var relativeOffset = require('common/calc').relativeOffset;
|
||||
var spanOfDay = require('common/calc').spanOfDay;
|
||||
var template = require('templates/multi_day');
|
||||
|
||||
var _id = 0;
|
||||
|
||||
IntlHelper.define('longDateFormat', 'datetime', {
|
||||
weekday: 'long',
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
});
|
||||
|
||||
function SingleDay(config) {
|
||||
this.date = config.date;
|
||||
this._hourHeight = config.hourHeight;
|
||||
this._daysHolder = config.daysHolder;
|
||||
this._allDayIcon = config.allDayIcon;
|
||||
this._alldaysHolder = config.alldaysHolder;
|
||||
this._oneDayLabelFormat = config.oneDayLabelFormat;
|
||||
this._render = this._render.bind(this);
|
||||
this._instanceID = _id++;
|
||||
this.overlaps = new Overlap();
|
||||
}
|
||||
module.exports = SingleDay;
|
||||
|
||||
SingleDay.prototype = {
|
||||
_isActive: false,
|
||||
_borderWidth: 0.1,
|
||||
_attached: false,
|
||||
_observer: null,
|
||||
|
||||
setup: function() {
|
||||
this.day = buildElement(template.day.render({
|
||||
date: this.date
|
||||
}));
|
||||
this.allday = buildElement(template.allday.render({
|
||||
date: this.date,
|
||||
id: this._instanceID
|
||||
}));
|
||||
this._dayName = this.allday.querySelector('.md__day-name');
|
||||
this._alldayEvents = this.allday.querySelector('.md__allday-events');
|
||||
|
||||
this._updateDayName();
|
||||
|
||||
this.onactive();
|
||||
},
|
||||
|
||||
_updateDayName: function() {
|
||||
// we can't use [data-l10n-date-format] because format might change based
|
||||
// on locale
|
||||
this._dayName.textContent = this.date.toLocaleString(navigator.languages, {
|
||||
weekday: 'short',
|
||||
day: 'numeric'
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent: function(evt) {
|
||||
switch(evt.type) {
|
||||
case 'localized':
|
||||
this._updateDayName();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
append: function() {
|
||||
this._daysHolder.appendChild(this.day);
|
||||
this._alldaysHolder.appendChild(this.allday);
|
||||
this._attached = true;
|
||||
},
|
||||
|
||||
onactive: function() {
|
||||
if (this._isActive) {
|
||||
return;
|
||||
}
|
||||
this._observer = core.bridge.observeDay(this.date);
|
||||
this._observer.listen(this._render);
|
||||
window.addEventListener('localized', this);
|
||||
this._isActive = true;
|
||||
},
|
||||
|
||||
_render: function(records) {
|
||||
this._alldayEvents.innerHTML = '';
|
||||
records.allday.forEach(this._renderAlldayEvent, this);
|
||||
this.overlaps.reset();
|
||||
this.day.innerHTML = '';
|
||||
records.basic.forEach(this._renderEvent, this);
|
||||
if (this._alldayEvents.children.length > 0) {
|
||||
// If there are all day events, the section acts as a listbox.
|
||||
this._alldayEvents.setAttribute('role', 'listbox');
|
||||
this._alldayEvents.setAttribute('aria-labelledby', this._allDayIcon.id +
|
||||
' ' + this._dayName.id);
|
||||
} else {
|
||||
// If there are no all day events, the section acts as a create new all
|
||||
// day event button.
|
||||
this._alldayEvents.setAttribute('role', 'button');
|
||||
this._alldayEvents.setAttribute('data-l10n-id', 'create-all-day-event');
|
||||
this._alldayEvents.setAttribute('aria-describedby', this._dayName.id);
|
||||
}
|
||||
},
|
||||
|
||||
_renderEvent: function(record) {
|
||||
var el = this._buildEventElement(record);
|
||||
|
||||
var {busytime} = record;
|
||||
var {startDate, endDate} = busytime;
|
||||
|
||||
// we don't set the height on the template because we use the same markup
|
||||
// for all day events as well
|
||||
var duration = relativeDuration(this.date, startDate, endDate);
|
||||
// we subtract border to keep a margin between consecutive events
|
||||
var hei = duration * this._hourHeight - this._borderWidth;
|
||||
|
||||
// It doesn't make sense to set height less than 1 px, so we set it to 1 px
|
||||
// in order to show events correctly.
|
||||
hei = Math.max(1, hei);
|
||||
|
||||
el.style.height = hei + 'px';
|
||||
|
||||
if (duration < 1) {
|
||||
el.classList.add('is-partial');
|
||||
var size = '';
|
||||
// we need to toggle layout if event lasts less than 20, 30 and 45min
|
||||
if (duration < 0.3) {
|
||||
size = 'micro';
|
||||
} else if (duration < 0.5) {
|
||||
size = 'tiny';
|
||||
} else if (duration < 0.75) {
|
||||
size = 'small';
|
||||
}
|
||||
if (size) {
|
||||
el.classList.add('is-partial-' + size);
|
||||
}
|
||||
}
|
||||
|
||||
var offset = relativeOffset(this.date, startDate);
|
||||
el.style.top = (offset * this._hourHeight) + 'px';
|
||||
|
||||
this.overlaps.add(busytime, el);
|
||||
this.day.appendChild(el);
|
||||
},
|
||||
|
||||
_buildEventElement: function(record) {
|
||||
var {title, location, alarms} = record.event.remote;
|
||||
var {startDate, endDate, _id} = record.busytime;
|
||||
|
||||
// screen reader should be aware if the event spans multiple dates and also
|
||||
// know the event duration without having the open it
|
||||
var labelFormat = isSameDate(startDate, endDate) ? this._oneDayLabelFormat :
|
||||
'event-multiple-day-duration';
|
||||
|
||||
var longDateFormat = IntlHelper.get('longDateFormat');
|
||||
var shortTimeFormat = IntlHelper.get('shortTimeFormat');
|
||||
var labelFormatArgs = JSON.stringify({
|
||||
startDate: longDateFormat.format(startDate),
|
||||
startTime: shortTimeFormat.format(startDate),
|
||||
endDate: longDateFormat.format(endDate),
|
||||
endTime: shortTimeFormat.format(endDate)
|
||||
});
|
||||
|
||||
return buildElement(template.event.render({
|
||||
id: _id,
|
||||
instance: this._instanceID,
|
||||
title: title,
|
||||
location: location,
|
||||
hasAlarms: alarms && alarms.length,
|
||||
color: record.color,
|
||||
labelFormat: labelFormat,
|
||||
labelFormatArgs: labelFormatArgs
|
||||
}));
|
||||
},
|
||||
|
||||
_renderAlldayEvent: function(record) {
|
||||
var el = this._buildEventElement(record);
|
||||
el.classList.add('is-allday');
|
||||
el.setAttribute('role', 'option');
|
||||
this._alldayEvents.appendChild(el);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.oninactive();
|
||||
this._detach();
|
||||
},
|
||||
|
||||
_detach: function() {
|
||||
if (this._attached) {
|
||||
this._daysHolder.removeChild(this.day);
|
||||
this._alldaysHolder.removeChild(this.allday);
|
||||
this._attached = false;
|
||||
}
|
||||
},
|
||||
|
||||
oninactive: function() {
|
||||
if (!this._isActive) {
|
||||
return;
|
||||
}
|
||||
this._observer.cancel();
|
||||
window.removeEventListener('localized', this);
|
||||
this._isActive = false;
|
||||
},
|
||||
|
||||
setVisibleForScreenReader: function(visibleRange) {
|
||||
var visible = visibleRange.contains(spanOfDay(this.date));
|
||||
this.day.setAttribute('aria-hidden', !visible);
|
||||
this.allday.setAttribute('aria-hidden', !visible);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue