Bug 1554646 - [de-xbl] convert calendar-editable-item binding and derivatives to custom elements. r=pmorris

This commit is contained in:
Khushil Mistry 2019-08-15 20:10:00 +02:00
Родитель 90fbaeb677
Коммит d6b527b5c5
19 изменённых файлов: 855 добавлений и 868 удалений

Просмотреть файл

@ -163,10 +163,12 @@
let multiDayImage = this.querySelector(".agenda-multiDayEvent-image");
multiDayImage.setAttribute("type", iconType);
// class wrap causes allday items to wrap its text in today-pane
let addWrap = document.getAnonymousElementByAttribute(this.mAllDayItem, "anonid", "eventbox");
addWrap.classList.add("wrap");
addWrap = document.getAnonymousElementByAttribute(this.mAllDayItem, "anonid", "event-detail-box");
addWrap.classList.add("wrap");
let eventBoxContainer = this.mAllDayItem.querySelector(".calendar-event-box-container");
eventBoxContainer.classList.add("wrap");
let eventDetailBox = this.mAllDayItem.querySelector("event-detail-box");
if (eventDetailBox) {
eventDetailBox.classList.add("wrap");
}
allDayDateLabel.value = date;
}
get occurrence() {

Просмотреть файл

@ -0,0 +1,424 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global MozElements, MozXULElement, setBooleanAttribute, onMouseOverItem
invokeEventDragSession, setElementValue */
"use strict";
// Wrap in a block to prevent leaking to window scope.
{
var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* The MozCalendarEditableItem widget is used as a full day event item in the
* Day and Week views of the calendar. It displays the event name, alarm icon
* and the category type color. It gets displayed in the header container of
* the respective view of the calendar.
*
* @extends MozXULElement
*/
class MozCalendarEditableItem extends MozXULElement {
static get inheritedAttributes() {
return {
".calendar-event-box-container": "readonly,flashing,alarm,allday,priority,progress,status,calendar,categories",
".calendar-category-box": "categories",
".alarm-icons-box": "flashing",
".calendar-event-details > vbox": "context",
};
}
constructor() {
super();
this.mOccurrence = null;
this.mSelected = false;
this.mCalendarView = null;
this.addEventListener("contextmenu", (event) => {
// If the middle/right button was used for click just select the item.
if (!this.selected) {
this.select(event);
}
}, true);
this.addEventListener("click", (event) => {
if (event.button != 0 || this.mEditing) {
return;
}
// If the left button was used and the item is already selected
// and there are no multiple items selected start
// the 'single click edit' timeout. Otherwise select the item too.
// Also, check if the calendar is readOnly or we are offline.
if (this.selected && !(event.ctrlKey || event.metaKey) &&
cal.acl.isCalendarWritable(this.mOccurrence.calendar)) {
if (this.editingTimer) {
clearTimeout(this.editingTimer);
}
this.editingTimer = setTimeout(() => this.startEditing(), 350);
} else {
this.select(event);
if (!this.closest("richlistitem")) {
event.stopPropagation();
}
}
});
this.addEventListener("dblclick", (event) => {
if (event.button != 0) {
return;
}
event.stopPropagation();
// Stop 'single click edit' timeout (if started).
if (this.editingTimer) {
clearTimeout(this.editingTimer);
this.editingTimer = null;
}
if (this.calendarView && this.calendarView.controller) {
let item = event.ctrlKey ? this.mOccurrence.parentItem : this.mOccurrence;
this.calendarView.controller.modifyOccurrence(item);
}
});
this.addEventListener("mouseover", (event) => {
if (this.calendarView && this.calendarView.controller) {
event.stopPropagation();
onMouseOverItem(event);
}
});
// We have two event listeners for dragstart. This event listener is for the capturing phase.
this.addEventListener("dragstart", (event) => {
if (document.monthDragEvent.localName == "calendar-event-box") {
return;
}
let item = this.occurrence;
let isInvitation = item.calendar instanceof Ci.calISchedulingSupport && item.calendar.isInvitation(item);
if (!cal.acl.isCalendarWritable(item.calendar) || !cal.acl.userCanModifyItem(item) || isInvitation) {
return;
}
if (!this.selected) {
this.select(event);
}
invokeEventDragSession(item, this);
});
}
connectedCallback() {
if (this.delayConnectedCallback() || this.hasChildNodes()) {
return;
}
this.appendChild(MozXULElement.parseXULToFragment(`
<vbox flex="1">
<hbox>
<box class="calendar-color-box"
flex="1">
<box class="calendar-event-selection"
orient="horizontal"
flex="1">
<stack class="calendar-event-box-container"
flex="1">
<hbox class="calendar-event-details">
<vbox align="left"
flex="1">
<label class="event-name-label"
crop="end"
style="margin: 0;">
</label>
<textbox class="calendar-event-details-core title-desc"
hidden="true"
style="background: transparent !important;"
wrap="true">
</textbox>
<label crop="end"
class="calendar-event-details-core location-desc">
</label>
<spacer flex="1">
</spacer>
</vbox>
<stack>
<hbox class="calendar-category-box category-color-box calendar-event-selection"
flex="1" pack="end">
<image class="calendar-category-box-gradient">
</image>
</hbox>
<hbox align="center">
<hbox class="alarm-icons-box"
align="center">
</hbox>
<image class="item-classification-box"
pack="end">
</image>
</hbox>
</stack>
</hbox>
</stack>
</box>
</box>
</hbox>
</vbox>
`));
// We have two event listeners for dragstart. This event listener is for the bubbling phase
// where we are setting up the document.monthDragEvent which will be used in the event listener
// in the capturing phase.
this.addEventListener("dragstart", (event) => {
document.monthDragEvent = this;
}, true);
this.setAttribute("mousethrough", "never");
this.setAttribute("tooltip", "itemTooltip");
this.setAttribute("tabindex", "-1");
this.addEventNameTextboxListener();
this.initializeAttributeInheritance();
}
set parentBox(val) {
this.mParentBox = val;
}
get parentBox() {
return this.mParentBox;
}
set selected(val) {
if (val && !this.mSelected) {
this.mSelected = true;
this.setAttribute("selected", "true");
} else if (!val && this.mSelected) {
this.mSelected = false;
this.removeAttribute("selected");
}
return val;
}
get selected() {
return this.mSelected;
}
set calendarView(val) {
this.mCalendarView = val;
return val;
}
get calendarView() {
return this.mCalendarView;
}
set occurrence(val) {
this.mOccurrence = val;
this.setEditableLabel();
this.setLocationLabel();
this.setCSSClasses();
return val;
}
get occurrence() {
return this.mOccurrence;
}
get eventNameLabel() {
return this.querySelector(".event-name-label");
}
get eventNameTextbox() {
return this.querySelector(".title-desc");
}
addEventNameTextboxListener() {
let stopPropagationIfEditing = (event) => {
if (this.mEditing) {
event.stopPropagation();
}
};
// While editing, single click positions cursor, so don't propagate.
this.eventNameTextbox.onclick = stopPropagationIfEditing;
// While editing, double click selects words, so don't propagate.
this.eventNameTextbox.ondblclick = stopPropagationIfEditing;
// While editing, don't propagate mousedown/up (selects calEvent).
this.eventNameTextbox.onmousedown = stopPropagationIfEditing;
this.eventNameTextbox.onmouseup = stopPropagationIfEditing;
this.eventNameTextbox.onblur = () => {
this.stopEditing(true);
};
this.eventNameTextbox.onkeypress = (event) => {
if (event.key == "Enter") { // Save on enter.
this.stopEditing(true);
} else if (event.key == "Escape") { // Abort on escape.
this.stopEditing(false);
}
};
}
setEditableLabel() {
let label = this.eventNameLabel;
let item = this.mOccurrence;
label.value = item.title ? item.title.replace(/\n/g, " ")
: cal.l10n.getCalString("eventUntitled");
}
setLocationLabel() {
let locationLabel = this.querySelector(".location-desc");
let location = this.mOccurrence.getProperty("LOCATION");
let showLocation = Services.prefs.getBoolPref("calendar.view.showLocation", false);
locationLabel.value = (showLocation && location) ? location : "";
setBooleanAttribute(locationLabel, "hidden", !showLocation || !location);
}
setCSSClasses() {
let item = this.mOccurrence;
let cssSafeId = cal.view.formatStringForCSSRule(item.calendar.id);
this.style.setProperty("--item-backcolor", `var(--calendar-${cssSafeId}-backcolor)`);
this.style.setProperty("--item-forecolor", `var(--calendar-${cssSafeId}-forecolor)`);
let categoriesArray = item.getCategories({});
if (categoriesArray.length > 0) {
let cssClassesArray = categoriesArray.map(cal.view.formatStringForCSSRule);
this.setAttribute("categories", cssClassesArray.join(" "));
let categoriesBox = this.querySelector(".calendar-category-box");
categoriesBox.style.backgroundColor = `var(--category-${cssClassesArray[0]}-color)`;
}
// Add alarm icons as needed.
let alarms = item.getAlarms({});
if (alarms.length && Services.prefs.getBoolPref("calendar.alarms.indicator.show", true)) {
let iconsBox = this.querySelector(".alarm-icons-box");
cal.alarms.addReminderImages(iconsBox, alarms);
// Set suppressed status on the icons box.
setElementValue(iconsBox,
item.calendar.getProperty("suppressAlarms") || false,
"suppressed");
}
// Item classification / privacy.
let classificationBox = this.querySelector(".item-classification-box");
if (classificationBox) {
classificationBox.setAttribute("classification", item.privacy || "PUBLIC");
}
// Set up event box attributes for use in css selectors. Note if
// something is added here, it should also be inherited correctly
// in the <content> section of this custom element, and all that inherit it.
// Event type specific properties.
if (cal.item.isEvent(item)) {
if (item.startDate.isDate) {
this.setAttribute("allday", "true");
}
this.setAttribute("itemType", "event");
} else if (cal.item.isToDo(item)) {
// Progress attribute.
this.setAttribute("progress", cal.item.getProgressAtom(item));
// Attribute for tasks and tasks image.
this.setAttribute("itemType", "todo");
if (item.entryDate && !item.dueDate) {
this.setAttribute("todoType", "start");
} else if (!item.entryDate && item.dueDate) {
this.setAttribute("todoType", "end");
}
}
if (this.calendarView &&
item.hashId in this.calendarView.mFlashingEvents) {
this.setAttribute("flashing", "true");
}
if (alarms.length) {
this.setAttribute("alarm", "true");
}
// Priority.
if (item.priority > 0 && item.priority < 5) {
this.setAttribute("priority", "high");
} else if (item.priority > 5 && item.priority < 10) {
this.setAttribute("priority", "low");
}
// Status attribute.
if (item.status) {
this.setAttribute("status", item.status.toUpperCase());
}
// Item class.
if (item.hasProperty("CLASS")) {
this.setAttribute("itemclass", item.getProperty("CLASS"));
}
// Calendar name.
this.setAttribute("calendar", item.calendar.name.toLowerCase());
// Invitation.
if (cal.itip.isInvitation(item)) {
this.setAttribute("invitation-status", cal.itip.getInvitedAttendee(item).participationStatus);
this.setAttribute("readonly", "true");
} else if (!cal.acl.isCalendarWritable(item.calendar)) {
this.setAttribute("readonly", "true");
}
}
startEditing() {
this.editingTimer = null;
this.mOriginalTextLabel = this.mOccurrence.title;
this.eventNameLabel.setAttribute("hidden", "true");
this.mEditing = true;
this.eventNameTextbox.value = this.mOriginalTextLabel;
this.eventNameTextbox.removeAttribute("hidden");
this.eventNameTextbox.select();
}
select(event) {
if (!this.calendarView) {
return;
}
let items = this.calendarView.mSelectedItems.slice();
if (event.ctrlKey || event.metaKey) {
if (this.selected) {
let pos = items.indexOf(this.mOccurrence);
items.splice(pos, 1);
} else {
items.push(this.mOccurrence);
}
} else {
items = [this.mOccurrence];
}
this.calendarView.setSelectedItems(items.length, items);
}
stopEditing(saveChanges) {
if (!this.mEditing) {
return;
}
this.mEditing = false;
if (saveChanges && (this.eventNameTextbox.value != this.mOriginalTextLabel)) {
this.calendarView.controller.modifyOccurrence(this.mOccurrence,
null, null,
this.eventNameTextbox.value);
// Note that as soon as we do the modifyItem, this element ceases to exist,
// so don't bother trying to modify anything further here! ('this' exists,
// because it's being kept alive, but our child content etc. is all gone).
return;
}
this.eventNameTextbox.setAttribute("hidden", "true");
this.eventNameLabel.removeAttribute("hidden");
}
}
MozElements.MozCalendarEditableItem = MozCalendarEditableItem;
customElements.define("calendar-editable-item", MozCalendarEditableItem);
}

Просмотреть файл

@ -56,7 +56,7 @@
});
this.addEventListener("click", (event) => {
if (event.button != 0 || event.button != 2) {
if (event.button != 0 && event.button != 2) {
return;
}
@ -622,7 +622,6 @@
chunkBox.setAttribute("context",
this.getAttribute("item-context") ||
this.getAttribute("context"));
chunkBox.setAttribute("orient", orient);
// Set the gripBars visibility in the chunk. Keep it
// hidden for tasks with only entry date OR due date.
@ -642,6 +641,7 @@
}
innerColumn.appendChild(chunkBox);
chunkBox.setAttribute("orient", orient);
chunkBox.calendarView = this.calendarView;
chunkBox.occurrence = chunk.event;
chunkBox.parentColumn = this;
@ -1208,7 +1208,7 @@
// rotated), calculate the difference and start accelerating the
// scrollbar.
let diffStart, diffEnd;
let orient = event.target.getAttribute("orient");
let orient = document.calendarEventColumnDragging.getAttribute("orient");
let scrollbox = currentView().scrollbox;
let boundingRect = scrollbox.getBoundingClientRect();
if (orient == "vertical") {
@ -1262,7 +1262,7 @@
// If we leave the view, then stop our internal sweeping and start a
// real drag session. Someday we need to fix the sweep to soely be a
// drag session, no sweeping.
let boundingRect = event.target.getBoundingClientRect();
let boundingRect = currentView().scrollbox.getBoundingClientRect();
if (event.clientX < (boundingRect.x) ||
event.clientX > (boundingRect.x + boundingRect.width) ||
event.clientY < (boundingRect.y) ||
@ -1279,7 +1279,7 @@
document.calendarEventColumnDragging = null;
col.mDragState = null;
var item = dragState.dragOccurrence;
let item = dragState.dragOccurrence;
// The multiday view currently exhibits a less than optimal strategy
// in terms of item selection. items don't get automatically selected
@ -1456,8 +1456,6 @@
window.removeEventListener("mouseup", col.onEventSweepMouseUp);
window.removeEventListener("keypress", col.onEventSweepKeypress);
document.calendarEventColumnDragging = null;
// If the user didn't sweep out at least a few pixels, ignore
// unless we're in a different column.
if (dragState.origColumn == col) {

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals currentView MozElements MozXULElement */
/* globals currentView MozElements MozXULElement onMouseOverItem invokeEventDragSession */
/* import-globals-from calendar-ui-utils.js */
@ -256,4 +256,140 @@
}
}
customElements.define("calendar-month-day-box", CalendarMonthDayBox);
/**
* The MozCalendarMonthDayBoxItem widget is used as event item in the
* Multiweek and Month views of the calendar. It displays the event name,
* alarm icon and the category type color.
*
* @extends {MozElements.MozCalendarEditableItem}
*/
class MozCalendarMonthDayBoxItem extends MozElements.MozCalendarEditableItem {
static get inheritedAttributes() {
return {
".calendar-event-box-container": "readonly,flashing,alarm,allday,priority,progress,status,calendar,categories",
".calendar-item-image": "progress,allday,itemType,todoType",
".calendar-month-day-box-item-label": "context",
".event-name-label-container": "context",
".alarm-icons-box": "flashing",
".calendar-category-box": "categories",
};
}
connectedCallback() {
if (this.delayConnectedCallback() || this.hasChildNodes()) {
return;
}
this.appendChild(MozXULElement.parseXULToFragment(`
<vbox flex="1">
<hbox>
<box class="calendar-color-box"
flex="1">
<box class="calendar-event-selection"
orient="horizontal"
flex="1">
<stack class="calendar-event-box-container"
flex="1">
<hbox class="calendar-event-details">
<vbox pack="center">
<image class="calendar-item-image"></image>
</vbox>
<label class="calendar-month-day-box-item-label"></label>
<vbox class="event-name-label-container"
align="left" flex="1">
<label class="event-name-label"
crop="end"
flex="1"
style="margin: 0;">
</label>
<textbox class="plain calendar-event-name-textbox title-desc"
crop="end"
hidden="true"
wrap="true">
</textbox>
<spacer flex="1"></spacer>
</vbox>
<stack class="category-box-stack">
<hbox class="calendar-category-box category-color-box calendar-event-selection"
flex="1"
pack="end">
<image class="calendar-category-box-gradient"></image>
</hbox>
<hbox align="center">
<hbox class="alarm-icons-box"
pack="end"
align="top">
</hbox>
<image class="item-classification-box"
pack="end">
</image>
</hbox>
</stack>
</hbox>
</stack>
</box>
</box>
</hbox>
</vbox>
`));
// We have two event listeners for dragstart. This event listener is for the bubbling phase
// where we are setting up the document.monthDragEvent which will be used in the event listener
// in the capturing phase which is set up in the calendar-editable-item.
this.addEventListener("dragstart", (event) => {
document.monthDragEvent = this;
}, true);
this.setAttribute("mousethrough", "never");
this.setAttribute("tooltip", "itemTooltip");
this.addEventNameTextboxListener();
this.initializeAttributeInheritance();
}
set occurrence(val) {
cal.ASSERT(!this.mOccurrence, "Code changes needed to set the occurrence twice", true);
this.mOccurrence = val;
if (cal.item.isEvent(val) && !val.startDate.isDate) {
let icon = this.querySelector(".calendar-item-image");
let label = this.querySelector(".calendar-month-day-box-item-label");
let formatter = Cc["@mozilla.org/calendar/datetime-formatter;1"]
.getService(Ci.calIDateTimeFormatter);
let timezone = this.calendarView ? this.calendarView.mTimezone
: cal.dtz.defaultTimezone;
let parentDate = this.parentBox.date;
let parentTime = cal.createDateTime();
parentTime.resetTo(parentDate.year, parentDate.month, parentDate.day, 0, 0, 0, timezone);
let startTime = val.startDate.getInTimezone(timezone);
let endTime = val.endDate.getInTimezone(timezone);
let nextDay = parentTime.clone();
nextDay.day++;
let comp = endTime.compare(nextDay);
if (startTime.compare(parentTime) == -1) {
if (comp == 1) {
icon.setAttribute("type", "continue");
} else if (comp == 0) {
icon.setAttribute("type", "start");
} else {
icon.setAttribute("type", "end");
label.value = formatter.formatTime(endTime);
}
} else if (comp == 1) {
icon.setAttribute("type", "start");
label.value = formatter.formatTime(startTime);
} else {
label.value = formatter.formatTime(startTime);
}
label.setAttribute("time", "true");
}
this.setEditableLabel();
this.setCSSClasses();
return val;
}
get occurrence() {
return this.mOccurrence;
}
}
customElements.define("calendar-month-day-box-item", MozCalendarMonthDayBoxItem);
}

Просмотреть файл

@ -1,128 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- import-globals-from calendar-views-utils.js -->
<!DOCTYPE bindings SYSTEM "chrome://global/locale/global.dtd" >
<bindings id="calendar-month-view-bindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="calendar-month-day-box-item" extends="chrome://calendar/content/calendar-view-core.xml#calendar-editable-item">
<content mousethrough="never" tooltip="itemTooltip">
<xul:vbox flex="1">
<xul:hbox>
<xul:box anonid="event-container"
class="calendar-color-box"
flex="1">
<xul:box class="calendar-event-selection" orient="horizontal" flex="1">
<xul:stack anonid="eventbox"
class="calendar-event-box-container"
xbl:inherits="readonly,flashing,alarm,allday,priority,progress,status,calendar,categories"
flex="1">
<xul:hbox anonid="event-detail-box"
class="calendar-event-details">
<xul:vbox pack="center">
<xul:image anonid="item-icon"
class="calendar-item-image"
xbl:inherits="progress,allday,itemType,todoType"/>
</xul:vbox>
<xul:label anonid="item-label"
class="calendar-month-day-box-item-label"
xbl:inherits="context"/>
<xul:vbox align="left"
flex="1"
xbl:inherits="context">
<xul:label anonid="event-name"
crop="end"
flex="1"
style="margin: 0;"/>
<xul:textbox anonid="event-name-textbox"
class="plain calendar-event-name-textbox"
crop="end"
hidden="true"
wrap="true"/>
<xul:spacer flex="1"/>
</xul:vbox>
<xul:stack anonid="category-box-stack">
<xul:hbox anonid="category-box"
class="calendar-category-box category-color-box calendar-event-selection"
xbl:inherits="categories"
flex="1"
pack="end">
<xul:image class="calendar-category-box-gradient"/>
</xul:hbox>
<xul:hbox align="center">
<xul:hbox anonid="alarm-icons-box"
class="alarm-icons-box"
pack="end"
align="top"
xbl:inherits="flashing"/>
<xul:image anonid="item-classification-box"
class="item-classification-box"
pack="end"/>
</xul:hbox>
</xul:stack>
</xul:hbox>
</xul:stack>
</xul:box>
</xul:box>
</xul:hbox>
</xul:vbox>
</content>
<implementation>
<property name="occurrence">
<getter><![CDATA[
return this.mOccurrence;
]]></getter>
<setter><![CDATA[
cal.ASSERT(!this.mOccurrence, "Code changes needed to set the occurrence twice", true);
this.mOccurrence = val;
if (cal.item.isEvent(val)) {
if (!val.startDate.isDate) {
let icon = document.getAnonymousElementByAttribute(this, "anonid", "item-icon");
let label = document.getAnonymousElementByAttribute(this, "anonid", "item-label");
let formatter = Cc["@mozilla.org/calendar/datetime-formatter;1"]
.getService(Ci.calIDateTimeFormatter);
let timezone = this.calendarView ? this.calendarView.mTimezone
: cal.dtz.defaultTimezone;
let parentDate = this.parentBox.date;
let parentTime = cal.createDateTime();
parentTime.resetTo(parentDate.year, parentDate.month, parentDate.day, 0, 0, 0, timezone);
let startTime = val.startDate.getInTimezone(timezone);
let endTime = val.endDate.getInTimezone(timezone);
let nextDay = parentTime.clone();
nextDay.day++;
let comp = endTime.compare(nextDay);
if (startTime.compare(parentTime) == -1) {
if (comp == 1) {
icon.setAttribute("type", "continue");
} else if (comp == 0) {
icon.setAttribute("type", "start");
} else {
icon.setAttribute("type", "end");
label.value = formatter.formatTime(endTime);
}
} else if (comp == 1) {
icon.setAttribute("type", "start");
label.value = formatter.formatTime(startTime);
} else {
label.value = formatter.formatTime(startTime);
}
label.setAttribute("time", "true");
}
}
this.setEditableLabel();
this.setCSSClasses();
return val;
]]></setter>
</property>
</implementation>
</binding>
</bindings>

Просмотреть файл

@ -872,14 +872,15 @@
for (const item of this.mSelectedItems) {
for (const occ of this.getItemOccurrencesInView(item)) {
const cols = this.findColumnsForItem(occ);
if (cols.length > 0) {
const start = item.startDate || item.entryDate || item.dueDate;
for (const col of cols) {
if (start.isDate) {
col.header.selectOccurrence(occ);
} else {
col.column.selectOccurrence(occ);
}
if (cols.length == 0) {
continue;
}
const start = item.startDate || item.entryDate || item.dueDate;
for (const col of cols) {
if (start.isDate) {
col.header.selectOccurrence(occ);
} else {
col.column.selectOccurrence(occ);
}
}
}

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals currentView MozElements MozXULElement */
/* globals currentView, MozElements, MozXULElement, onMouseOverItem */
/* import-globals-from calendar-ui-utils.js */
@ -152,4 +152,247 @@
}
}
customElements.define("calendar-header-container", CalendarHeaderContainer);
/**
* The MozCalendarMonthDayBoxItem widget is used as event item in the
* Day and Week views of the calendar. It displays the event name,
* alarm icon and the category type color. It also displays the gripbar
* components on hovering over the event. It is used to change the event
* timings.
*
* @extends {MozElements.MozCalendarEditableItem}
*/
class MozCalendarEventBox extends MozElements.MozCalendarEditableItem {
static get inheritedAttributes() {
return {
".calendar-color-box": "orient,readonly,flashing,alarm,allday,priority,progress,status,calendar,categories,todoType",
".calendar-event-box": "orient,width,height",
".calendar-event-box-container": "context,parentorient=orient,readonly,flashing,alarm,allday,priority,progress,status,calendar,categories",
".calendar-item-image": "progress,allday,itemType,todoType",
".alarm-icons-box": "flashing",
".category-color-box": "categories",
".calendar-event-box-grippy-top": "parentorient=orient",
".calendar-event-box-grippy-bottom": "parentorient=orient",
".calendar-event-gripbar-container": "orient",
};
}
constructor() {
super();
this.mParentColumn = null;
this.addEventListener("mousedown", (event) => {
if (event.button != 0) {
return;
}
event.stopPropagation();
if (this.mEditing) {
return;
}
this.parentColumn.calendarView.selectedDay = this.parentColumn.mDate;
this.mMouseX = event.screenX;
this.mMouseY = event.screenY;
let whichside = event.whichside;
if (whichside) {
this.calendarView.setSelectedItems(1, [event.ctrlKey ? this.mOccurrence.parentItem : this.mOccurrence]);
let snapIntMin = (event.shiftKey &&
!event.ctrlKey &&
!event.altKey &&
!event.metaKey) ? 1 : 15;
// Start edge resize drag
this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, whichside,
event.screenX, event.screenY,
snapIntMin);
} else {
// May be click or drag,
// So wait for mousemove (or mouseout if fast) to start item move drag.
this.mInMouseDown = true;
}
});
this.addEventListener("mousemove", (event) => {
if (!this.mInMouseDown) {
return;
}
let deltaX = Math.abs(event.screenX - this.mMouseX);
let deltaY = Math.abs(event.screenY - this.mMouseY);
// More than a 3 pixel move?
const movedMoreThan3Pixels = (deltaX * deltaX + deltaY * deltaY) > 9;
if (movedMoreThan3Pixels && this.parentColumn) {
this.startItemDrag();
}
});
this.addEventListener("mouseout", (event) => {
if (!this.mEditing && this.mInMouseDown && this.parentColumn) {
this.startItemDrag();
}
});
this.addEventListener("mouseup", (event) => {
if (!this.mEditing) {
this.mInMouseDown = false;
}
});
this.addEventListener("mouseover", (event) => {
if (this.calendarView && this.calendarView.controller) {
event.stopPropagation();
onMouseOverItem(event);
}
});
// We have two event listeners for dragstart. This event listener is for the bubbling phase
// where we are setting up the document.monthDragEvent which will be used in the event listener
// in the capturing phase which is set up in the calendar-editable-item.
this.addEventListener("dragstart", (event) => {
document.monthDragEvent = this;
}, true);
}
connectedCallback() {
if (this.delayConnectedCallback() || this.hasChildNodes()) {
return;
}
this.appendChild(MozXULElement.parseXULToFragment(`
<box class="calendar-event-box"
flex="1">
<box class="calendar-color-box"
flex="1">
<box class="calendar-event-selection"
orient="horizontal"
flex="1">
<stack class="calendar-event-box-container"
flex="1">
<hbox class="calendar-event-details"
align="start">
<image class="calendar-item-image">
</image>
<vbox flex="1">
<label class="calendar-event-details-core event-name-label"
crop="end">
</label>
<textbox class="plain calendar-event-details-core calendar-event-name-textbox title-desc"
hidden="true"
wrap="true">
</textbox>
<label class="calendar-event-details-core location-desc"
crop="end">
</label>
</vbox>
<hbox class="alarm-icons-box"
align="top">
</hbox>
<image class="item-classification-box">
</image>
</hbox>
<stack mousethrough="always"
class="calendar-category-box-stack">
<hbox class="calendar-category-box category-color-box calendar-event-selection"
flex="1"
pack="end">
<image class="calendar-category-box-gradient">
</image>
</hbox>
</stack>
<box class="calendar-event-gripbar-container">
<calendar-event-gripbar class="calendar-event-box-grippy-top"
mousethrough="never"
whichside="start">
</calendar-event-gripbar>
<spacer mousethrough="always"
flex="1">
</spacer>
<calendar-event-gripbar class="calendar-event-box-grippy-bottom"
mousethrough="never"
whichside="end">
</calendar-event-gripbar>
</box>
</stack>
</box>
</box>
</box>
`));
this.setAttribute("mousethrough", "never");
this.setAttribute("tooltip", "itemTooltip");
this.orient = this.getAttribute("orient");
this.addEventNameTextboxListener();
this.initializeAttributeInheritance();
}
set parentColumn(val) {
this.mParentColumn = val;
return val;
}
get parentColumn() {
return this.mParentColumn;
}
get startMinute() {
if (!this.mOccurrence) {
return 0;
}
let startDate = this.mOccurrence.startDate || this.mOccurrence.entryDate;
return startDate.hour * 60 + startDate.minute;
}
get endMinute() {
if (!this.mOccurrence) {
return 0;
}
let endDate = this.mOccurrence.endDate || this.mOccurrence.dueDate;
return endDate.hour * 60 + endDate.minute;
}
getOptimalMinSize() {
if (this.getAttribute("orient") == "vertical") {
let minHeight = getOptimalMinimumHeight(this.eventNameLabel) +
getSummarizedStyleValues(this.querySelector(".calendar-event-box-container"), ["margin-bottom", "margin-top"]) +
getSummarizedStyleValues(this, ["border-bottom-width", "border-top-width"]);
this.setAttribute("minheight", minHeight);
this.setAttribute("minwidth", "1");
return minHeight;
}
this.eventNameLabel.setAttribute("style", "min-width: 2em");
let minWidth = getOptimalMinimumWidth(this.eventNameLabel);
this.setAttribute("minwidth", minWidth);
this.setAttribute("minheight", "1");
return minWidth;
}
setEditableLabel() {
let label = this.eventNameLabel;
let item = this.mOccurrence;
label.textContent = item.title || cal.l10n.getCalString("eventUntitled");
let gripbar = this.querySelector(".calendar-event-box-grippy-top").getBoundingClientRect().height;
let height = this.querySelector(".calendar-event-box-container").getBoundingClientRect().height;
label.setAttribute("style", "max-height: " + Math.max(0, height - gripbar * 2) + "px");
}
startItemDrag() {
if (this.editingTimer) {
clearTimeout(this.editingTimer);
this.editingTimer = null;
}
this.calendarView.setSelectedItems(1, [this.mOccurrence]);
this.mEditing = false;
this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, "middle", this.mMouseX, this.mMouseY);
this.mInMouseDown = false;
}
}
customElements.define("calendar-event-box", MozCalendarEventBox);
}

Просмотреть файл

@ -1,274 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- import-globals-from ../../resources/content/mouseoverPreviews.js -->
<!-- import-globals-from calendar-dnd-listener.js -->
<!-- import-globals-from calendar-ui-utils.js -->
<!-- import-globals-from calendar-views-utils.js -->
<!DOCTYPE bindings SYSTEM "chrome://global/locale/global.dtd" >
<bindings id="calendar-multiday-view-bindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<!--
- An individual event box, to be inserted into a column.
-->
<binding id="calendar-event-box" extends="chrome://calendar/content/calendar-view-core.xml#calendar-editable-item">
<content mousethrough="never" tooltip="itemTooltip">
<xul:box xbl:inherits="orient,width,height" flex="1">
<xul:box anonid="event-container"
class="calendar-color-box"
xbl:inherits="orient,readonly,flashing,alarm,allday,priority,progress,
status,calendar,categories,todoType"
flex="1">
<xul:box class="calendar-event-selection" orient="horizontal" flex="1">
<xul:stack anonid="eventbox"
class="calendar-event-box-container"
flex="1"
xbl:inherits="context,parentorient=orient,readonly,flashing,alarm,allday,priority,progress,status,calendar,categories">
<xul:hbox class="calendar-event-details"
anonid="calendar-event-details"
align="start">
<xul:image anonid="item-icon"
class="calendar-item-image"
xbl:inherits="progress,allday,itemType,todoType"/>
<xul:vbox flex="1">
<xul:label anonid="event-name" class="calendar-event-details-core title-desc" crop="end"/>
<xul:textbox anonid="event-name-textbox"
class="plain calendar-event-details-core calendar-event-name-textbox"
hidden="true"
wrap="true"/>
<xul:label anonid="event-location" class="calendar-event-details-core location-desc" crop="end"/>
</xul:vbox>
<xul:hbox anonid="alarm-icons-box"
class="alarm-icons-box"
align="top"
xbl:inherits="flashing"/>
<xul:image anonid="item-classification-box"
class="item-classification-box"/>
</xul:hbox>
<xul:stack mousethrough="always" class="calendar-category-box-stack">
<xul:hbox anonid="category-box"
class="calendar-category-box category-color-box calendar-event-selection"
xbl:inherits="categories"
flex="1"
pack="end">
<xul:image class="calendar-category-box-gradient"/>
</xul:hbox>
</xul:stack>
<xul:box xbl:inherits="orient">
<xul:calendar-event-gripbar anonid="gripbar1"
class="calendar-event-box-grippy-top"
mousethrough="never"
whichside="start"
xbl:inherits="parentorient=orient"/>
<xul:spacer mousethrough="always" flex="1"/>
<xul:calendar-event-gripbar anonid="gripbar2"
class="calendar-event-box-grippy-bottom"
mousethrough="never"
whichside="end"
xbl:inherits="parentorient=orient"/>
</xul:box>
<!-- Do not insert anything here, otherwise the event boxes will
not be resizable using the gripbars. If you want to insert
additional elements, do so above the box with the gripbars. -->
</xul:stack>
</xul:box>
</xul:box>
</xul:box>
</content>
<implementation>
<constructor><![CDATA[
this.orient = this.getAttribute("orient");
]]></constructor>
<!-- fields -->
<field name="mParentColumn">null</field>
<!-- methods/properties -->
<method name="setAttribute">
<parameter name="aAttr"/>
<parameter name="aVal"/>
<body><![CDATA[
let needsrelayout = false;
if (aAttr == "orient") {
if (this.getAttribute("orient") != aVal) {
needsrelayout = true;
}
}
// this should be done using lookupMethod(), see bug 286629
let ret = XULElement.prototype.setAttribute.call(this, aAttr, aVal);
if (needsrelayout) {
let eventbox = document.getAnonymousElementByAttribute(this, "anonid", "eventbox");
eventbox.setAttribute("orient", aVal);
let gb1 = document.getAnonymousElementByAttribute(this, "anonid", "gripbar1");
gb1.parentorient = aVal;
let gb2 = document.getAnonymousElementByAttribute(this, "anonid", "gripbar2");
gb2.parentorient = aVal;
}
return ret;
]]></body>
</method>
<method name="getOptimalMinSize">
<body><![CDATA[
if (this.getAttribute("orient") == "vertical") {
let minHeight = getOptimalMinimumHeight(this.eventNameLabel) +
getSummarizedStyleValues(document.getAnonymousElementByAttribute(this, "anonid", "eventbox"), ["margin-bottom", "margin-top"]) +
getSummarizedStyleValues(this, ["border-bottom-width", "border-top-width"]);
this.setAttribute("minheight", minHeight);
this.setAttribute("minwidth", "1");
return minHeight;
} else {
this.eventNameLabel.setAttribute("style", "min-width: 2em");
let minWidth = getOptimalMinimumWidth(this.eventNameLabel);
this.setAttribute("minwidth", minWidth);
this.setAttribute("minheight", "1");
return minWidth;
}
]]></body>
</method>
<property name="parentColumn"
onget="return this.mParentColumn;"
onset="return (this.mParentColumn = val);"/>
<property name="startMinute" readonly="true">
<getter><![CDATA[
if (!this.mOccurrence) {
return 0;
}
let startDate = this.mOccurrence.startDate || this.mOccurrence.entryDate;
return startDate.hour * 60 + startDate.minute;
]]></getter>
</property>
<property name="endMinute" readonly="true">
<getter><![CDATA[
if (!this.mOccurrence) {
return 0;
}
let endDate = this.mOccurrence.endDate || this.mOccurrence.dueDate;
return endDate.hour * 60 + endDate.minute;
]]></getter>
</property>
<method name="setEditableLabel">
<body><![CDATA[
let evl = this.eventNameLabel;
let item = this.mOccurrence;
if (item.title && item.title != "") {
// Use <description> textContent so it can wrap.
evl.textContent = item.title;
} else {
evl.textContent = cal.l10n.getCalString("eventUntitled");
}
let gripbar = document.getAnonymousElementByAttribute(this, "anonid", "gripbar1").getBoundingClientRect().height;
let height = document.getAnonymousElementByAttribute(this, "anonid", "eventbox").getBoundingClientRect().height;
evl.setAttribute("style", "max-height: " + Math.max(0, height-gripbar * 2) + "px");
]]></body>
</method>
</implementation>
<handlers>
<handler event="mousedown" button="0"><![CDATA[
event.stopPropagation();
if (this.mEditing) {
return;
}
this.parentColumn.calendarView.selectedDay = this.parentColumn.mDate;
this.mMouseX = event.screenX;
this.mMouseY = event.screenY;
let whichside = event.whichside;
if (whichside) {
this.calendarView.setSelectedItems(1,
[event.ctrlKey ? this.mOccurrence.parentItem : this.mOccurrence]);
let snapIntMin = (event.shiftKey &&
!event.ctrlKey &&
!event.altKey &&
!event.metaKey) ? 1 : 15;
// start edge resize drag
this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, whichside,
event.screenX, event.screenY,
snapIntMin);
} else {
// may be click or drag,
// so wait for mousemove (or mouseout if fast) to start item move drag
this.mInMouseDown = true;
}
]]></handler>
<handler event="mousemove"><![CDATA[
if (!this.mInMouseDown) {
return;
}
let deltaX = Math.abs(event.screenX - this.mMouseX);
let deltaY = Math.abs(event.screenY - this.mMouseY);
// more than a 3 pixel move?
if ((deltaX * deltaX + deltaY * deltaY) > 9) {
if (this.parentColumn) {
if (this.editingTimer) {
clearTimeout(this.editingTimer);
this.editingTimer = null;
}
this.calendarView.setSelectedItems(1, [this.mOccurrence]);
this.mEditing = false;
this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, "middle", this.mMouseX, this.mMouseY);
this.mInMouseDown = false;
}
}
]]></handler>
<handler event="mouseout"><![CDATA[
if (!this.mEditing && this.mInMouseDown && this.parentColumn) {
if (this.editingTimer) {
clearTimeout(this.editingTimer);
this.editingTimer = null;
}
this.calendarView.setSelectedItems(1, [this.mOccurrence]);
this.mEditing = false;
this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, "middle", this.mMouseX, this.mMouseY);
this.mInMouseDown = false;
}
]]></handler>
<handler event="mouseup"><![CDATA[
if (this.mEditing) {
return;
}
this.mInMouseDown = false;
]]></handler>
<handler event="mouseover"><![CDATA[
if (this.calendarView && this.calendarView.controller) {
event.stopPropagation();
onMouseOverItem(event);
}
]]></handler>
</handlers>
</binding>
</bindings>

Просмотреть файл

@ -1,28 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
calendar-event-box {
-moz-binding: url(chrome://calendar/content/calendar-multiday-view.xml#calendar-event-box);
}
calendar-day-label {
display: -moz-box;
}
/* Month View */
calendar-month-day-box-item {
-moz-binding: url(chrome://calendar/content/calendar-month-view.xml#calendar-month-day-box-item);
}
/* View core */
calendar-editable-item {
-moz-binding: url(chrome://calendar/content/calendar-view-core.xml#calendar-editable-item);
}
calendar-shadow-box {
-moz-binding: url(chrome://calendar/content/calendar-view-core.xml#calendar-shadow-box);
}

Просмотреть файл

@ -1,388 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- import-globals-from ../../resources/content/mouseoverPreviews.js -->
<!-- import-globals-from calendar-dnd-listener.js -->
<!-- import-globals-from calendar-views-utils.js -->
<bindings id="calendar-core-view-bindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="calendar-editable-item">
<content mousethrough="never"
tooltip="itemTooltip"
tabindex="-1">
<xul:vbox flex="1">
<xul:hbox>
<xul:box anonid="event-container"
class="calendar-color-box"
flex="1">
<xul:box class="calendar-event-selection" orient="horizontal" flex="1">
<xul:stack anonid="eventbox"
class="calendar-event-box-container"
flex="1"
xbl:inherits="readonly,flashing,alarm,allday,priority,progress,status,calendar,categories">
<xul:hbox class="calendar-event-details">
<xul:vbox align="left" flex="1" xbl:inherits="context">
<xul:label anonid="event-name" crop="end" style="margin: 0;"/>
<xul:textbox anonid="event-name-textbox"
class="calendar-event-details-core title-desc"
hidden="true"
style="background: transparent !important;"
wrap="true"/>
<xul:label anonid="event-location"
crop="end"
class="calendar-event-details-core location-desc"/>
<xul:spacer flex="1"/>
</xul:vbox>
<xul:stack>
<xul:hbox anonid="category-box"
class="calendar-category-box category-color-box calendar-event-selection"
xbl:inherits="categories"
flex="1"
pack="end">
<xul:image class="calendar-category-box-gradient"/>
</xul:hbox>
<xul:hbox align="center">
<xul:hbox anonid="alarm-icons-box"
class="alarm-icons-box"
align="center"
xbl:inherits="flashing"/>
<xul:image anonid="item-classification-box"
class="item-classification-box"
pack="end"/>
</xul:hbox>
</xul:stack>
</xul:hbox>
</xul:stack>
</xul:box>
</xul:box>
</xul:hbox>
</xul:vbox>
</content>
<implementation>
<constructor><![CDATA[
this.eventNameTextbox.onblur = () => {
this.stopEditing(true);
};
this.eventNameTextbox.onkeypress = (event) => {
// save on enter
if (event.key == "Enter") {
this.stopEditing(true);
// abort on escape
} else if (event.key == "Escape") {
this.stopEditing(false);
}
};
let stopPropagationIfEditing = (event) => {
if (this.mEditing) {
event.stopPropagation();
}
};
// while editing, single click positions cursor, so don't propagate.
this.eventNameTextbox.onclick = stopPropagationIfEditing;
// while editing, double click selects words, so don't propagate.
this.eventNameTextbox.ondblclick = stopPropagationIfEditing;
// while editing, don't propagate mousedown/up (selects calEvent).
this.eventNameTextbox.onmousedown = stopPropagationIfEditing;
this.eventNameTextbox.onmouseup = stopPropagationIfEditing;
]]></constructor>
<field name="mOccurrence">null</field>
<field name="mSelected">false</field>
<field name="mCalendarView">null</field>
<property name="parentBox"
onget="return this.mParentBox;"
onset="this.mParentBox = val;"/>
<property name="selected">
<getter><![CDATA[
return this.mSelected;
]]></getter>
<setter><![CDATA[
if (val && !this.mSelected) {
this.mSelected = true;
this.setAttribute("selected", "true");
} else if (!val && this.mSelected) {
this.mSelected = false;
this.removeAttribute("selected");
}
return val;
]]></setter>
</property>
<property name="calendarView">
<getter><![CDATA[
return this.mCalendarView;
]]></getter>
<setter><![CDATA[
this.mCalendarView = val;
return val;
]]></setter>
</property>
<property name="occurrence">
<getter><![CDATA[
return this.mOccurrence;
]]></getter>
<setter><![CDATA[
this.mOccurrence = val;
this.setEditableLabel();
this.setLocationLabel();
this.setCSSClasses();
return val;
]]></setter>
</property>
<property name="eventNameLabel" readonly="true"
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'event-name');"/>
<property name="eventNameTextbox" readonly="true"
onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'event-name-textbox');"/>
<method name="setEditableLabel">
<body><![CDATA[
let evl = this.eventNameLabel;
let item = this.mOccurrence;
evl.value = (item.title ? item.title.replace(/\n/g, " ")
: cal.l10n.getCalString("eventUntitled"));
]]></body>
</method>
<method name="setLocationLabel">
<body><![CDATA[
let locationLabel = document.getAnonymousElementByAttribute(this, "anonid", "event-location");
let location = this.mOccurrence.getProperty("LOCATION");
let showLocation = Services.prefs.getBoolPref("calendar.view.showLocation", false);
locationLabel.value = showLocation && location ? location : "";
setBooleanAttribute(locationLabel, "hidden", !showLocation || !location);
]]></body>
</method>
<method name="setCSSClasses">
<body><![CDATA[
let item = this.mOccurrence;
let cssSafeId = cal.view.formatStringForCSSRule(item.calendar.id);
this.style.setProperty("--item-backcolor", `var(--calendar-${cssSafeId}-backcolor)`);
this.style.setProperty("--item-forecolor", `var(--calendar-${cssSafeId}-forecolor)`);
let categoriesArray = item.getCategories({});
if (categoriesArray.length > 0) {
let cssClassesArray = categoriesArray.map(cal.view.formatStringForCSSRule);
this.setAttribute("categories", cssClassesArray.join(" "));
let categoriesBox = document.getAnonymousElementByAttribute(this, "anonid", "category-box");
categoriesBox.style.backgroundColor = `var(--category-${cssClassesArray[0]}-color)`;
}
// Add alarm icons as needed.
let alarms = item.getAlarms({});
if (alarms.length && Services.prefs.getBoolPref("calendar.alarms.indicator.show", true)) {
let iconsBox = document.getAnonymousElementByAttribute(this, "anonid", "alarm-icons-box");
cal.alarms.addReminderImages(iconsBox, alarms);
// Set suppressed status on the icons box
setElementValue(iconsBox,
item.calendar.getProperty("suppressAlarms") || false,
"suppressed");
}
// Item classification / privacy
let classificationBox = document.getAnonymousElementByAttribute(this, "anonid", "item-classification-box");
if (classificationBox) {
classificationBox.setAttribute("classification", item.privacy || "PUBLIC");
}
// Set up event box attributes for use in css selectors. Note if
// something is added here, it should also be xbl:inherited correctly
// in the <content> section of this binding, and all that inherit it.
// Event type specific properties
if (cal.item.isEvent(item)) {
if (item.startDate.isDate) {
this.setAttribute("allday", "true");
}
this.setAttribute("itemType", "event");
} else if (cal.item.isToDo(item)) {
// progress attribute
this.setAttribute("progress", cal.item.getProgressAtom(item));
// Attribute for tasks and tasks image.
this.setAttribute("itemType", "todo");
if (item.entryDate && !item.dueDate) {
this.setAttribute("todoType", "start");
} else if (!item.entryDate && item.dueDate) {
this.setAttribute("todoType", "end");
}
}
if (this.calendarView &&
item.hashId in this.calendarView.mFlashingEvents) {
this.setAttribute("flashing", "true");
}
if (alarms.length) {
this.setAttribute("alarm", "true");
}
// priority
if (item.priority > 0 && item.priority < 5) {
this.setAttribute("priority", "high");
} else if (item.priority > 5 && item.priority < 10) {
this.setAttribute("priority", "low");
}
// status attribute
if (item.status) {
this.setAttribute("status", item.status.toUpperCase());
}
// item class
if (item.hasProperty("CLASS")) {
this.setAttribute("itemclass", item.getProperty("CLASS"));
}
// calendar name
this.setAttribute("calendar", item.calendar.name.toLowerCase());
// Invitation
if (cal.itip.isInvitation(item)) {
this.setAttribute("invitation-status", cal.itip.getInvitedAttendee(item).participationStatus);
this.setAttribute("readonly", "true");
} else if (!cal.acl.isCalendarWritable(item.calendar)) {
this.setAttribute("readonly", "true");
}
]]></body>
</method>
<method name="startEditing">
<body><![CDATA[
this.editingTimer = null;
this.mOriginalTextLabel = this.mOccurrence.title;
this.eventNameLabel.setAttribute("hidden", "true");
this.mEditing = true;
this.eventNameTextbox.value = this.mOriginalTextLabel;
this.eventNameTextbox.removeAttribute("hidden");
this.eventNameTextbox.select();
]]></body>
</method>
<method name="select">
<parameter name="event"/>
<body><![CDATA[
if (!this.calendarView) {
return;
}
let items = this.calendarView.mSelectedItems.slice();
if (event.ctrlKey || event.metaKey) {
if (this.selected) {
let pos = items.indexOf(this.mOccurrence);
items.splice(pos, 1);
} else {
items.push(this.mOccurrence);
}
} else {
items = [this.mOccurrence];
}
this.calendarView.setSelectedItems(items.length, items);
]]></body>
</method>
<method name="stopEditing">
<parameter name="saveChanges"/>
<body><![CDATA[
if (!this.mEditing) {
return;
}
this.mEditing = false;
if (saveChanges && (this.eventNameTextbox.value != this.mOriginalTextLabel)) {
this.calendarView.controller.modifyOccurrence(this.mOccurrence,
null, null,
this.eventNameTextbox.value);
// Note that as soon as we do the modifyItem, this element ceases to exist,
// so don't bother trying to modify anything further here! ('this' exists,
// because it's being kept alive, but our child content etc. is all gone)
return;
}
this.eventNameTextbox.setAttribute("hidden", "true");
this.eventNameLabel.removeAttribute("hidden");
]]></body>
</method>
</implementation>
<handlers>
<handler event="contextmenu" phase="capturing"><![CDATA[
// If the middle/right button was used for click just select the item.
if (!this.selected) {
this.select(event);
}
]]></handler>
<handler event="click" button="0"><![CDATA[
if (this.mEditing) {
return;
}
// If the left button was used and the item is already selected
// and there are no multiple items selected start
// the 'single click edit' timeout. Otherwise select the item too.
// Also, check if the calendar is readOnly or we are offline.
if (this.selected && !(event.ctrlKey || event.metaKey) &&
cal.acl.isCalendarWritable(this.mOccurrence.calendar)) {
if (this.editingTimer) {
clearTimeout(this.editingTimer);
}
this.editingTimer = setTimeout(() => this.startEditing(), 350);
} else {
this.select(event);
if (!this.closest("richlistitem")) {
event.stopPropagation();
}
}
]]></handler>
<handler event="dblclick" button="0"><![CDATA[
event.stopPropagation();
// stop 'single click edit' timeout (if started)
if (this.editingTimer) {
clearTimeout(this.editingTimer);
this.editingTimer = null;
}
if (this.calendarView && this.calendarView.controller) {
let item = event.ctrlKey ? this.mOccurrence.parentItem : this.mOccurrence;
this.calendarView.controller.modifyOccurrence(item);
}
]]></handler>
<handler event="mouseover"><![CDATA[
if (this.calendarView && this.calendarView.controller) {
event.stopPropagation();
onMouseOverItem(event);
}
]]></handler>
<handler event="dragstart"><![CDATA[
if (event.target.localName == "calendar-event-box") {
return;
}
let item = this.occurrence;
let isInvitation = item.calendar instanceof Ci.calISchedulingSupport && item.calendar.isInvitation(item);
if (!cal.acl.isCalendarWritable(item.calendar) || !cal.acl.userCanModifyItem(item) || isInvitation) {
return;
}
if (!this.selected) {
this.select(event);
}
invokeEventDragSession(item, this);
]]></handler>
</handlers>
</binding>
</bindings>

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* global MozElements, MozXULElement, Services, timeIndicator */
/* global MozElements, MozXULElement, timeIndicator */
"use strict";
@ -17,6 +17,7 @@
// Wrap in a block to prevent leaking to window scope.
{
var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
/**
* The calendar view for viewing a single day.
*
@ -31,7 +32,7 @@
super.connectedCallback();
}
// calICalendarView Methods and Properties
// calICalendarView Methods and Properties.
get observerID() {
return "day-view-observer";
@ -61,7 +62,7 @@
}
}
// End calICalendarView Methods and Properties
// End calICalendarView Methods and Properties.
}
MozXULElement.implementCustomInterface(CalendarDayView, [Ci.calICalendarView]);
@ -101,7 +102,7 @@
}, { once: true });
}
// calICalendarView Methods and Properties
// calICalendarView Methods and Properties.
get observerID() {
return "week-view-observer";
@ -132,7 +133,7 @@
}
}
// End calICalendarView Methods and Properties
// End calICalendarView Methods and Properties.
}
MozXULElement.implementCustomInterface(CalendarWeekView, [Ci.calICalendarView]);
@ -166,7 +167,7 @@
return this.mWeeksInView;
}
// calICalendarView Methods and Properties
// calICalendarView Methods and Properties.
get supportsZoom() {
return true;
@ -236,7 +237,7 @@
}
}
// End calICalendarView Methods and Properties
// End calICalendarView Methods and Properties.
}
MozXULElement.implementCustomInterface(CalendarMultiweekView, [Ci.calICalendarView]);
@ -257,7 +258,7 @@
super.connectedCallback();
}
// calICalendarView Methods and Properties
// calICalendarView Methods and Properties.
get observerID() {
return "month-view-observer";
@ -312,7 +313,7 @@
}
}
// End calICalendarView Methods and Properties
// End calICalendarView Methods and Properties.
}
MozXULElement.implementCustomInterface(CalendarMonthView, [Ci.calICalendarView]);

Просмотреть файл

@ -18,7 +18,7 @@
class CalendarDnDContainer extends MozXULElement {
constructor() {
super();
this.addEventListener("dragstart", this.onDragStart, true);
this.addEventListener("dragstart", this.onDragStart);
this.addEventListener("dragover", this.onDragOver);
this.addEventListener("dragenter", this.onDragEnter);
this.addEventListener("drop", this.onDrop);
@ -134,8 +134,8 @@
}
onDragStart(event) {
let draggedDOMNode = event.target;
if (!draggedDOMNode || (draggedDOMNode.parentNode != this &&
let draggedDOMNode = document.monthDragEvent || event.target;
if (!draggedDOMNode || !draggedDOMNode.parentNode || (draggedDOMNode.parentNode != this &&
!draggedDOMNode.parentNode.classList.contains("calendar-day-items"))) {
return;
}

Просмотреть файл

@ -27,10 +27,8 @@ calendar.jar:
content/calendar-menus.js (content/calendar-menus.js)
content/calendar-month-base-view.js (content/calendar-month-base-view.js)
content/calendar-month-view.js (content/calendar-month-view.js)
content/calendar-month-view.xml (content/calendar-month-view.xml)
content/calendar-multiday-base-view.js (content/calendar-multiday-base-view.js)
content/calendar-multiday-view.js (content/calendar-multiday-view.js)
content/calendar-multiday-view.xml (content/calendar-multiday-view.xml)
content/calendar-statusbar.js (content/calendar-statusbar.js)
content/calendar-task-editing.js (content/calendar-task-editing.js)
content/calendar-task-tree-utils.js (content/calendar-task-tree-utils.js)
@ -43,10 +41,9 @@ calendar.jar:
content/calendar-unifinder-todo.xul (content/calendar-unifinder-todo.xul)
content/calendar-unifinder.js (content/calendar-unifinder.js)
content/calendar-unifinder.xul (content/calendar-unifinder.xul)
content/calendar-view-bindings.css (content/calendar-view-bindings.css)
content/calendar-view-core.xml (content/calendar-view-core.xml)
content/calendar-views-utils.js (content/calendar-views-utils.js)
content/calendar-views.js (content/calendar-views.js)
content/calendar-editable-item.js (content/calendar-editable-item.js)
content/calendar-views.xul (content/calendar-views.xul)
content/calendar-alarm-dialog.js (content/dialogs/calendar-alarm-dialog.js)
content/calendar-alarm-dialog.xul (content/dialogs/calendar-alarm-dialog.xul)

Просмотреть файл

@ -53,11 +53,12 @@
<script src="chrome://calendar/content/calendar-base-view.js"/>
<script src="chrome://calendar/content/calendar-month-base-view.js"/>
<script src="chrome://calendar/content/widgets/calendar-dnd-widgets.js"/>
<script src="chrome://calendar/content/calendar-month-view.js"/>
<script src="chrome://calendar/content/calendar-event-column.js"/>
<script src="chrome://calendar/content/calendar-multiday-base-view.js"/>
<script src="chrome://calendar/content/calendar-multiday-view.js"/>
<script src="chrome://calendar/content/calendar-views.js"/>
<script src="chrome://calendar/content/calendar-editable-item.js"/>
<script src="chrome://calendar/content/calendar-month-view.js"/>
<script src="chrome://calendar/content/calendar-multiday-view.js"/>
<script src="chrome://calendar/content/calendar-event-column.js"/>
<script src="chrome://calendar/content/calendar-creation.js"/>
<script src="chrome://calendar/content/calendar-dnd-listener.js"/>

Просмотреть файл

@ -66,8 +66,8 @@ var EVENTPATH = `
`;
// Used after "${EVENTPATH}/${getEventDetails([view])}/".
var ALARM_ICON_PATH = `
anon({"anonid":"category-box-stack"})/anon({"align":"center"})/
anon({"anonid":"alarm-icons-box"})/anon({"class":"reminder-icon"})
anon({"class":"category-box-stack"})/anon({"align":"center"})/
anon({"class":"alarm-icons-box"})/anon({"class":"reminder-icon"})
`;
var plan_for_modal_dialog, wait_for_modal_dialog, close_window;
@ -387,14 +387,14 @@ function getEventBoxPath(controller, view, option, row, column, hour) {
function getEventDetails(view) {
if (view == "day" || view == "week") {
return `
anon({"flex":"1"})/anon({"anonid":"event-container"})/
{"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
anon({"flex":"1"})/anon({"class":"calendar-color-box"})/
{"class":"calendar-event-selection"}/anon({"class":"calendar-event-box-container"})/
{"class":"calendar-event-details"}
`;
} else {
return `
anon({"flex":"1"})/[0]/anon({"anonid":"event-container"})/
{"class":"calendar-event-selection"}/anon({"anonid":"eventbox"})/
anon({"flex":"1"})/[0]/anon({"class":"calendar-color-box"})/
{"class":"calendar-event-selection"}/anon({"class":"calendar-event-box-container"})/
{"class":"calendar-event-details"}
`;
}

Просмотреть файл

@ -95,7 +95,8 @@ function testDayView() {
// Check if name was saved.
let eventName = lookupEventBox("day", EVENT_BOX, null, 1, null,
`${EVENTPATH}/${getEventDetails("day")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
`${EVENTPATH}/${getEventDetails("day")}/anon({"flex":"1"})/
anon({"class":"calendar-event-details-core event-name-label"})`
);
controller.waitForElement(eventName);
controller.assertJSProperty(eventName, "textContent", TITLE2);

Просмотреть файл

@ -102,7 +102,7 @@ function testMonthView() {
// Check if name was saved.
let eventName = lookupEventBox("month", CANVAS_BOX, 1, 5, null,
`${EVENTPATH}/${getEventDetails("month")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
`${EVENTPATH}/${getEventDetails("month")}/anon({"flex":"1"})/anon({"class":"event-name-label"})`
);
controller.waitForElement(eventName);

Просмотреть файл

@ -103,7 +103,7 @@ function testMultiWeekView() {
// Check if name was saved.
let eventName = lookupEventBox("multiweek", CANVAS_BOX, 1, 5, null,
`${EVENTPATH}/${getEventDetails("multiweek")}/anon({"flex":"1"})/
anon({"anonid":"event-name"})`
anon({"class":"event-name-label"})`
);
controller.waitForElement(eventName);

Просмотреть файл

@ -100,7 +100,8 @@ function testWeekView() {
// Check if name was saved.
let eventName = lookupEventBox("week", EVENT_BOX, null, 5, null,
`${EVENTPATH}/${getEventDetails("week")}/anon({"flex":"1"})/anon({"anonid":"event-name"})`
`${EVENTPATH}/${getEventDetails("week")}/anon({"flex":"1"})/
anon({"class":"calendar-event-details-core event-name-label"})`
);
controller.waitForElement(eventName);
controller.assertJSProperty(eventName, "textContent", TITLE2);