Skip to content

Commit

Permalink
Merge branch 'master' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
emorikawa committed Dec 5, 2016
2 parents b127782 + d8d1c53 commit 443c0d0
Show file tree
Hide file tree
Showing 16 changed files with 308 additions and 29 deletions.
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# N1 Changelog

### 0.4.401 (12/05/16)

- Fixes:

+ Fixes to issues with the Salesforce plugin
+ Will search for Salesforce Contacts by name in addition to email
+ Fixes to errors being thrown on spellcheck right-click

### 0.4.400 (11/22/16)

- Features:
+ New Salesforce private beta plugin.

- Fixes:

+ Improvements to quoted text folding
+ Fixes to the creation of bullets & lists in the composer
+ Send and Archive fixed in composer windows
+ Typing in the composer with misspelled words is now much faster

- Development:

+ We now use `electron-packager` to build N1
+ `script/bootstrap` has been replaced with a much simpler install flow built on `electron-compile`
+ Removed devDependencies from main package.json reducing file size
+ We no longer support Node 4 for building
+ New background worker to parallelize expensive database queries


### 0.4.204 (11/7/16)

- Features:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,10 @@ export default class SpellcheckComposerExtension extends ComposerExtension {
word,
onCorrect: (correction) => {
DOMUtils.Mutating.applyTextInRange(range, selection, correction);
SpellcheckComposerExtension.update(editor);
SpellcheckComposerExtension.onContentChanged({editor});
},
onDidLearn: () => {
SpellcheckComposerExtension.update(editor);
SpellcheckComposerExtension.onContentChanged({editor});
},
});
}
Expand Down
4 changes: 2 additions & 2 deletions internal_packages/main-calendar/lib/calendar-wrapper.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
Actions,
DestroyModelTask,
CalendarDataSource,
CalendarDraggingDataSource,
} from 'nylas-exports';
import {
NylasCalendar,
Expand All @@ -18,7 +18,7 @@ export default class CalendarWrapper extends React.Component {

constructor(props) {
super(props);
this._dataSource = new CalendarDataSource();
this._dataSource = new CalendarDraggingDataSource();
this.state = {selectedEvents: []};
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nylas",
"productName": "Nylas N1",
"version": "0.4.400",
"version": "0.4.401",
"description": "The best email app for people and teams at work",
"license": "GPL-3.0",
"main": "./src/browser/main.js",
Expand Down
1 change: 1 addition & 0 deletions src/components/evented-iframe.cjsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class EventedIFrame extends React.Component
return unless @props.searchable
node = ReactDOM.findDOMNode(@)
doc = node.contentDocument?.body ? node.contentDocument
return unless doc
searchIndex = SearchableComponentStore.getCurrentRegionIndex(@_regionId)
{searchTerm} = SearchableComponentStore.getCurrentSearchData()
if @lastSearchIndex isnt searchIndex or @lastSearchTerm isnt searchTerm
Expand Down
103 changes: 103 additions & 0 deletions src/components/nylas-calendar/calendar-dragging-data-source.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import Rx from 'rx-lite';
import {DatabaseStore, Event, Utils} from 'nylas-exports';
import CalendarDataSource from './calendar-data-source';

/* This is a modified version of the CalendarDataSource that incorporates mouse
events in order to allow us to render the dragging/resizing of an event across
an entire calendar view. It removes the targeted event from the results of the
CalendarDataSource and adds a clone of that event with the updated times. */

export default class CalendarDraggingDataSource extends CalendarDataSource {
buildObservable({startTime, endTime, disabledCalendars, mouseHandlerObserver}) {
this.observable = Rx.Observable.combineLatest(
super.buildObservable({startTime, endTime, disabledCalendars}),
mouseHandlerObserver,
)
.flatMapLatest(([superResult, mouseEventData]) => {
const results = Utils.deepClone(superResult);
const {calEventId, mouseDownCalEventId} = mouseEventData;

// Dragging
if (mouseDownCalEventId != null) {
const {event} = this._findEvent(results.events, mouseDownCalEventId, true);

// If we don't have the dragged event, find it in the database
if (!event) {
return Rx.Observable.fromPromise(
DatabaseStore.find(Event, mouseDownCalEventId).then((e) => {
this._dragAndAddEvent(e, mouseEventData, results);
return Promise.resolve(results);
})
)
}

this._dragAndAddEvent(event, mouseEventData, results);
}

// Hovering
if (calEventId != null && mouseDownCalEventId == null) {
const {event, index} = this._findEvent(results.events, calEventId);
if (event) {
event.hovered = true;
// Keep the events in order so that hovering over an overlapping event
// doesn't make it change positions.
results.events.splice(index, 1, event)
}
}
return Rx.Observable.from([results]);
})
return this.observable;
}

subscribe(callback) {
return this.observable.subscribe(callback)
}

/*
* Create a dragged version of the event, based on the mouseData, and add it
* to the results.
*
* event - the calendar event that should be dragged
* mouseData - the data from the mouse event
* allResults - the whole results object, should have an 'events' entry that
* stores an array of calendar event models
*/
_dragAndAddEvent(event, mouseData, allResults) {
let newEvent;
if (mouseData.time) {
newEvent = event.shiftTimes(mouseData.dragHandles, mouseData.mouseDownTime, mouseData.time);
} else {
newEvent = event.clone();
}
newEvent.hovered = true;
newEvent.dragged = true;
allResults.events.push(newEvent);
}

/*
* Given an array of events and an eventId, find the event with that id.
*
* events - an array of calendar event models
* eventId - the id of the desired event
* remove - a boolean indicating whether event should be removed from the
* events array
* Returns an object - {
* event: the matching event,
* index: the index of the event within the events array,
* }
*/
_findEvent(events, eventId, removeEvent) {
let event;
let i;
for (i = 0; i < events.length; i++) {
if (events[i].id === eventId) {
event = events[i]
if (removeEvent) {
events.splice(i, 1);
}
break;
}
}
return {event, index: i};
}
}
75 changes: 66 additions & 9 deletions src/components/nylas-calendar/calendar-event-container.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import moment from 'moment'

import React from 'react'
import ReactDOM from 'react-dom'
import {Actions, DatabaseStore, Event, SyncbackEventTask} from 'nylas-exports'

export default class CalendarEventContainer extends React.Component {
static displayName = "CalendarEventContainer";
Expand Down Expand Up @@ -30,26 +30,76 @@ export default class CalendarEventContainer extends React.Component {
if (!this._mouseIsDown) {
return
}
const data = this._dataFromMouseEvent(event);

// An event was dragged, persist and syncback the updated times
if (this._mouseDownCalEventId && data.time) {
const origTime = this._mouseDownTime; // Store current value for use in callback

DatabaseStore.find(Event, this._mouseDownCalEventId).then((calEvent) => {
const newCalEvent = calEvent.shiftTimes(this._dragHandles, origTime, data.time);

DatabaseStore.inTransaction((t) => {
t.persistModel(newCalEvent);
}).then(() => {
const task = new SyncbackEventTask(newCalEvent.clientId);
Actions.queueTask(task);
})
})
}

this._mouseIsDown = false;
this._runPropsHandler("onCalendarMouseUp", event)
this._mouseDownTime = null;
this._mouseDownCalEventId = null;
this._runPropsHandler("onCalendarMouseUp", event, data)
}

_onCalendarMouseDown = (event) => {
this._DOMCache = {};
this._mouseIsDown = true;
this._runPropsHandler("onCalendarMouseDown", event)

// Note that the values of _dragHandles are used to figure out which time fields
// in the Event model should be updated. Only 'start' and 'end' are valid values.
this._dragHandles = [];

const data = this._dataFromMouseEvent(event);
this._mouseDownTime = data.time;

if (data.calEventId) {
this._mouseDownCalEventId = data.calEventId;

const classList = event.target.classList;
if (classList.contains("top")) {
this._dragHandles.push("start");
} else if (classList.contains("bottom")) {
this._dragHandles.push("end");
} else {
this._dragHandles.push("start", "end");
}
}

this._runPropsHandler("onCalendarMouseDown", event, data)
}

_onCalendarMouseMove = (event) => {
this._runPropsHandler("onCalendarMouseMove", event)
}

_runPropsHandler(name, event) {

// data is an optional param for if the handler already ran
// this._dataFromMouseEvent() and can pass those results in. If not,
// this._dataFromMouseEvent() will be run here in this function.
_runPropsHandler(name, event, data) {
const propsFn = this.props[name]
if (!propsFn) { return }
const {time, x, y, width, height} = this._dataFromMouseEvent(event);
const {time, x, y, width, height, calEventId} = data || this._dataFromMouseEvent(event);
try {
propsFn({event, time, x, y, width, height, mouseIsDown: this._mouseIsDown})
const args = {event, time, x, y, width, height, calEventId};
args.mouseIsDown = this._mouseIsDown;
args.mouseDownTime = this._mouseDownTime;
args.mouseDownCalEventId = this._mouseDownCalEventId;
args.dragHandles = this._dragHandles;
propsFn(args);
} catch (error) {
NylasEnv.reportError(error)
}
Expand All @@ -62,15 +112,15 @@ export default class CalendarEventContainer extends React.Component {
let height = null;
let time = null;
if (!event.target || !event.target.closest) { return {x, y, width, height, time} }
const eventColumn = this._DOMCache.eventColumn || event.target.closest(".event-column");
const eventColumn = event.target.closest(".event-column");
const gridWrap = this._DOMCache.gridWrap || event.target.closest(".event-grid-wrap .scroll-region-content-inner");
const calWrap = this._DOMCache.calWrap || event.target.closest(".calendar-area-wrap")
if (!gridWrap || !eventColumn) { return {x, y, width, height, time} }

const rect = this._DOMCache.rect || gridWrap.getBoundingClientRect();
const calWrapRect = this._DOMCache.calWrapRect || calWrap.getBoundingClientRect();

this._DOMCache = {rect, eventColumn, gridWrap, calWrap}
this._DOMCache = {rect, gridWrap, calWrap}

y = (gridWrap.scrollTop + event.clientY - rect.top);
x = (calWrap.scrollLeft + event.clientX - calWrapRect.left);
Expand All @@ -79,7 +129,14 @@ export default class CalendarEventContainer extends React.Component {
const percentDay = y / height;
const diff = ((+eventColumn.dataset.end) - (+eventColumn.dataset.start))
time = moment(diff * percentDay + (+eventColumn.dataset.start));
return {x, y, width, height, time}

let calEventId;
const closestCalEvent = event.target.closest(".calendar-event");
if (closestCalEvent) {
calEventId = closestCalEvent.dataset.id;
}

return {x, y, width, height, time, calEventId}
}

_onWindowMouseUp = (event) => {
Expand Down
12 changes: 11 additions & 1 deletion src/components/nylas-calendar/calendar-event.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ export default class CalendarEvent extends React.Component {
top: d.left,
}
}
styles.backgroundColor = calcColor(this.props.event.calendarId);

if (this.props.event.dragged) {
styles.zIndex = 1;
}

const bgOpacity = this.props.event.hovered ? 1 : null;
styles.backgroundColor = calcColor(this.props.event.calendarId, bgOpacity);

return styles
}

Expand All @@ -107,7 +114,9 @@ export default class CalendarEvent extends React.Component {
className={`calendar-event ${direction} ${selected ? 'selected' : null}`}
onClick={(e) => onClick(e, event)}
onDoubleClick={() => onDoubleClick(event)}
data-id={event.id}
>
<div className="resize-handle top" />
<span className="default-header" style={{order: 0}}>
{event.displayTitle()}
</span>
Expand All @@ -118,6 +127,7 @@ export default class CalendarEvent extends React.Component {
exposedProps={{event: event}}
direction="row"
/>
<div className="resize-handle bottom" />
</div>
)
}
Expand Down
11 changes: 4 additions & 7 deletions src/components/nylas-calendar/calendar-helpers.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {Utils} from 'nylas-exports'

export function calcColor(calendarId) {
let bgColor = NylasEnv.config.get(`calendar.colors.${calendarId}`)
if (!bgColor) {
const hue = Utils.hueForString(calendarId);
bgColor = `hsla(${hue}, 50%, 45%, 0.35)`
}
return bgColor
export function calcColor(calendarId, opacity) {
const alpha = opacity || 0.35;
const hue = NylasEnv.config.get(`calendar.colors.${calendarId}`) || Utils.hueForString(calendarId);
return `hsla(${hue}, 50%, 45%, ${alpha})`
}
1 change: 1 addition & 0 deletions src/components/nylas-calendar/nylas-calendar.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Rx from 'rx-lite'
import React from 'react'
import moment from 'moment'
import 'moment-round'
import {DatabaseStore, AccountStore, Calendar} from 'nylas-exports'
import {ScrollRegion, ResizableRegion, MiniMonthView} from 'nylas-component-kit'
import WeekView from './week-view'
Expand Down
Loading

0 comments on commit 443c0d0

Please sign in to comment.