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
19
gaia/apps/calendar/js/common/async_require.js
Executable file
19
gaia/apps/calendar/js/common/async_require.js
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
module.exports = function(ids) {
|
||||
if (!Array.isArray(ids)) {
|
||||
ids = [ids];
|
||||
}
|
||||
|
||||
// We want to find the "global" require that implements
|
||||
// https://github.com/amdjs/amdjs-api/wiki/require even though
|
||||
// it is not required by the amd spec nor is it implemented by all loaders.
|
||||
// First we'll try to find curl and then, if that doesn't work,
|
||||
// we'll try to find one that has require.toUrl().
|
||||
// Either way we want this to work in the app and also in unit tests.
|
||||
var requireFn = window.requirejs || window.require || require;
|
||||
return new Promise((resolve, reject) => requireFn(ids, resolve, reject));
|
||||
};
|
||||
|
||||
});
|
||||
57
gaia/apps/calendar/js/common/binsearch.js
Executable file
57
gaia/apps/calendar/js/common/binsearch.js
Executable file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Binary search utilities taken /w permission from :asuth
|
||||
*/
|
||||
define(function(require, exports) {
|
||||
'use strict';
|
||||
|
||||
exports.find = function(list, seekVal, cmpfunc, aLow, aHigh) {
|
||||
var low = ((aLow === undefined) ? 0 : aLow),
|
||||
high = ((aHigh === undefined) ? (list.length - 1) : aHigh),
|
||||
mid, cmpval;
|
||||
|
||||
while (low <= high) {
|
||||
mid = low + Math.floor((high - low) / 2);
|
||||
cmpval = cmpfunc(seekVal, list[mid]);
|
||||
if (cmpval < 0) {
|
||||
high = mid - 1;
|
||||
} else if (cmpval > 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.insert = function(list, seekVal, cmpfunc) {
|
||||
if (!list.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var low = 0, high = list.length - 1,
|
||||
mid, cmpval;
|
||||
|
||||
while (low <= high) {
|
||||
mid = low + Math.floor((high - low) / 2);
|
||||
cmpval = cmpfunc(seekVal, list[mid]);
|
||||
|
||||
if (cmpval < 0) {
|
||||
high = mid - 1;
|
||||
} else if (cmpval > 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmpval < 0) {
|
||||
return mid; // insertion is displacing, so use mid outright.
|
||||
} else if (cmpval > 0) {
|
||||
return mid + 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
578
gaia/apps/calendar/js/common/calc.js
Executable file
578
gaia/apps/calendar/js/common/calc.js
Executable file
|
|
@ -0,0 +1,578 @@
|
|||
/* global mozIntl */
|
||||
define(function(require, exports) {
|
||||
'use strict';
|
||||
|
||||
var Timespan = require('./timespan');
|
||||
var co = require('ext/co');
|
||||
|
||||
const SECOND = 1000;
|
||||
const MINUTE = (SECOND * 60);
|
||||
const HOUR = MINUTE * 60;
|
||||
|
||||
exports._hourDate = new Date();
|
||||
exports.startDay = 0;
|
||||
exports.FLOATING = 'floating';
|
||||
exports.ALLDAY = 'allday';
|
||||
exports.SECOND = SECOND;
|
||||
exports.MINUTE = MINUTE;
|
||||
exports.HOUR = HOUR;
|
||||
exports.PAST = 'past';
|
||||
exports.NEXT_MONTH = 'next-month';
|
||||
exports.OTHER_MONTH = 'other-month';
|
||||
exports.PRESENT = 'present';
|
||||
exports.FUTURE = 'future';
|
||||
|
||||
Object.defineProperty(exports, 'today', {
|
||||
get: function() {
|
||||
return new Date();
|
||||
}
|
||||
});
|
||||
|
||||
exports.daysInWeek = function() {
|
||||
// XXX: We need to add this to mozIntl.calendarInfo
|
||||
return 7;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates day of week when starting day is Monday.
|
||||
*/
|
||||
exports.dayOfWeekFromMonday = function(numeric) {
|
||||
var day = numeric - 1;
|
||||
if (day < 0) {
|
||||
return 6;
|
||||
}
|
||||
return day;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates day of week from startDay value
|
||||
* passed by the locale currently being used
|
||||
*/
|
||||
exports.dayOfWeekFromStartDay = function(numeric) {
|
||||
var day = numeric - exports.startDay;
|
||||
if (day < 0) {
|
||||
return 7 + day;
|
||||
}
|
||||
return day;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks is given date is today.
|
||||
*
|
||||
* @param {Date} date compare.
|
||||
* @return {Boolean} true when today.
|
||||
*/
|
||||
exports.isToday = function(date) {
|
||||
return exports.isSameDate(date, exports.today);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if date object only contains date information (not time).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var time = new Date(2012, 0, 1, 1);
|
||||
* this._isOnlyDate(time); // false
|
||||
*
|
||||
* var time = new Date(2012, 0, 1);
|
||||
* this._isOnlyDate(time); // true
|
||||
*
|
||||
* @param {Date} date to verify.
|
||||
* @return {Boolean} see above.
|
||||
*/
|
||||
exports.isOnlyDate = function(date) {
|
||||
if (
|
||||
date.getHours() === 0 &&
|
||||
date.getMinutes() === 0 &&
|
||||
date.getSeconds() === 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the difference between
|
||||
* two points in hours.
|
||||
*
|
||||
* @param {Date|Numeric} start start hour.
|
||||
* @param {Date|Numeric} end end hour.
|
||||
*/
|
||||
exports.hourDiff = function(start, end) {
|
||||
start = (start instanceof Date) ? start.valueOf() : start;
|
||||
end = (end instanceof Date) ? end.valueOf() : end;
|
||||
|
||||
start = start / HOUR;
|
||||
end = end / HOUR;
|
||||
|
||||
return end - start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates timespan for given day.
|
||||
*
|
||||
* @param {Date} date date of span.
|
||||
* @param {Boolean} includeTime uses given date
|
||||
* as the start time of the timespan
|
||||
* rather then the absolute start of
|
||||
* the day of the given date.
|
||||
*/
|
||||
exports.spanOfDay = function(date, includeTime) {
|
||||
if (typeof(includeTime) === 'undefined') {
|
||||
date = exports.createDay(date);
|
||||
}
|
||||
|
||||
var end = exports.createDay(date);
|
||||
end.setDate(end.getDate() + 1);
|
||||
return new Timespan(date, end);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates timespan for a given month.
|
||||
* Starts at the first week that occurs
|
||||
* in the given month. Ends at the
|
||||
* last day, minute, second of given month.
|
||||
*/
|
||||
exports.spanOfMonth = function(month) {
|
||||
month = exports.monthStart(month);
|
||||
var startDay = exports.getWeekStartDate(month);
|
||||
var endDay = exports.monthEnd(month);
|
||||
endDay = exports.getWeekEndDate(endDay);
|
||||
return new Timespan(startDay, endDay);
|
||||
};
|
||||
|
||||
exports.monthEnd = function(date, diff = 0) {
|
||||
var endDay = new Date(
|
||||
date.getFullYear(),
|
||||
date.getMonth() + diff + 1,
|
||||
1
|
||||
);
|
||||
endDay.setMilliseconds(-1);
|
||||
return endDay;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a date to UTC
|
||||
*/
|
||||
exports.getUTC = function(date) {
|
||||
return new Date(
|
||||
date.getUTCFullYear(),
|
||||
date.getUTCMonth(),
|
||||
date.getUTCDate(),
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
date.getUTCMilliseconds()
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts transport time into a JS Date object.
|
||||
*
|
||||
* @param {Object} transport date in transport format.
|
||||
* @return {Date} javascript date converts the transport into
|
||||
* the current time.
|
||||
*/
|
||||
exports.dateFromTransport = function(transport) {
|
||||
var utc = transport.utc;
|
||||
var offset = transport.offset;
|
||||
var zone = transport.tzid;
|
||||
|
||||
var date = new Date(
|
||||
// offset is expected to be 0 in the floating case
|
||||
parseInt(utc) - parseInt(offset)
|
||||
);
|
||||
|
||||
if (zone && zone === exports.FLOATING) {
|
||||
return exports.getUTC(date);
|
||||
}
|
||||
|
||||
return date;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts a date object into a transport value
|
||||
* which can be stored in the database or sent
|
||||
* to a service.
|
||||
*
|
||||
* When the tzid value is given an is the string
|
||||
* value of "floating" it will convert the local
|
||||
* time directly to UTC zero and record no offset.
|
||||
* This along with the tzid is understood to be
|
||||
* a "floating" time which will occur at that position
|
||||
* regardless of the current tzid's offset.
|
||||
*
|
||||
* @param {Date} date js date object.
|
||||
* @param {String} [tzid] optional tzid.
|
||||
* @param {Boolean} isDate true when is a "date" representation.
|
||||
*/
|
||||
exports.dateToTransport = function(date, tzid, isDate) {
|
||||
var result = Object.create(null);
|
||||
|
||||
if (isDate) {
|
||||
result.isDate = isDate;
|
||||
}
|
||||
|
||||
if (tzid) {
|
||||
result.tzid = tzid;
|
||||
}
|
||||
|
||||
var utc = Date.UTC(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate(),
|
||||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
date.getSeconds(),
|
||||
date.getMilliseconds()
|
||||
);
|
||||
|
||||
// remember a "date" is always a floating
|
||||
// point in time otherwise we don't use it...
|
||||
if (isDate || tzid && tzid === exports.FLOATING) {
|
||||
result.utc = utc;
|
||||
result.offset = 0;
|
||||
result.tzid = exports.FLOATING;
|
||||
} else {
|
||||
var localUtc = date.valueOf();
|
||||
var offset = utc - localUtc;
|
||||
|
||||
result.utc = utc;
|
||||
result.offset = offset;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if two date objects occur
|
||||
* on the same date (in the same month, year, day).
|
||||
* Disregards time.
|
||||
*
|
||||
* @param {Date} first date.
|
||||
* @param {Date} second date.
|
||||
* @return {Boolean} true when they are the same date.
|
||||
*/
|
||||
exports.isSameDate = function(first, second) {
|
||||
return first.getMonth() == second.getMonth() &&
|
||||
first.getDate() == second.getDate() &&
|
||||
first.getFullYear() == second.getFullYear();
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an identifier for a specific
|
||||
* date in time for a given date
|
||||
*
|
||||
* @param {Date} date to get id for.
|
||||
* @return {String} identifier.
|
||||
*/
|
||||
exports.getDayId = function(date) {
|
||||
return [
|
||||
'd',
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate()
|
||||
].join('-');
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a date object from
|
||||
* a string id for a date.
|
||||
*
|
||||
* @param {String} id identifier for date.
|
||||
* @return {Date} date output.
|
||||
*/
|
||||
exports.dateFromId = function(id) {
|
||||
var parts = id.split('-'),
|
||||
date,
|
||||
type;
|
||||
|
||||
if (parts.length > 1) {
|
||||
type = parts.shift();
|
||||
switch (type) {
|
||||
case 'd':
|
||||
date = new Date(parts[0], parts[1], parts[2]);
|
||||
break;
|
||||
case 'm':
|
||||
date = new Date(parts[0], parts[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an identifier for a specific
|
||||
* month in time for a given date.
|
||||
*
|
||||
* @return {String} identifier.
|
||||
*/
|
||||
exports.getMonthId = function(date) {
|
||||
return [
|
||||
'm',
|
||||
date.getFullYear(),
|
||||
date.getMonth()
|
||||
].join('-');
|
||||
};
|
||||
|
||||
exports.createDay = function(date, day, month, year) {
|
||||
return new Date(
|
||||
year != null ? year : date.getFullYear(),
|
||||
month != null ? month : date.getMonth(),
|
||||
day != null ? day : date.getDate()
|
||||
);
|
||||
};
|
||||
|
||||
exports.endOfDay = function(date) {
|
||||
var day = exports.createDay(date, date.getDate() + 1);
|
||||
day.setMilliseconds(-1);
|
||||
return day;
|
||||
};
|
||||
|
||||
exports.monthStart = function(date, diff = 0) {
|
||||
return new Date(date.getFullYear(), date.getMonth() + diff, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns localized day of week.
|
||||
*
|
||||
* @param {Date|Number} date numeric or date object.
|
||||
*/
|
||||
exports.dayOfWeek = function(date) {
|
||||
var number = date;
|
||||
|
||||
if (typeof(date) !== 'number') {
|
||||
number = date.getDay();
|
||||
}
|
||||
return exports.dayOfWeekFromStartDay(number);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds localized week start date of given date.
|
||||
*
|
||||
* @param {Date} date any day the week.
|
||||
* @return {Date} first date in the week of given date.
|
||||
*/
|
||||
exports.getWeekStartDate = function(date) {
|
||||
var currentDay = exports.dayOfWeek(date);
|
||||
var startDay = (date.getDate() - currentDay);
|
||||
|
||||
return exports.createDay(date, startDay);
|
||||
};
|
||||
|
||||
exports.getWeekEndDate = function(date) {
|
||||
// TODO: There are localization problems
|
||||
// with this approach as we assume a 7 day week.
|
||||
var start = exports.getWeekStartDate(date);
|
||||
start.setDate(start.getDate() + 7);
|
||||
start.setMilliseconds(-1);
|
||||
|
||||
return start;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of dates objects.
|
||||
* Inclusive. First and last are
|
||||
* the given instances.
|
||||
*
|
||||
* @param {Date} start starting day.
|
||||
* @param {Date} end ending day.
|
||||
* @param {Boolean} includeTime include times start/end ?
|
||||
*/
|
||||
exports.daysBetween = function(start, end, includeTime) {
|
||||
if (start instanceof Timespan) {
|
||||
if (end) {
|
||||
includeTime = end;
|
||||
}
|
||||
|
||||
end = new Date(start.end);
|
||||
start = new Date(start.start);
|
||||
}
|
||||
|
||||
if (start > end) {
|
||||
var tmp = end;
|
||||
end = start;
|
||||
start = tmp;
|
||||
tmp = null;
|
||||
}
|
||||
|
||||
var list = [];
|
||||
var last = start.getDate();
|
||||
|
||||
// handle the case where start & end dates
|
||||
// are the same date.
|
||||
if (exports.isSameDate(start, end)) {
|
||||
if (includeTime) {
|
||||
list.push(end);
|
||||
} else {
|
||||
list.push(exports.createDay(start));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var next = new Date(
|
||||
start.getFullYear(),
|
||||
start.getMonth(),
|
||||
++last
|
||||
);
|
||||
|
||||
if (next > end) {
|
||||
throw new Error(
|
||||
'sanity fails next is greater then end'
|
||||
);
|
||||
}
|
||||
|
||||
if (!exports.isSameDate(next, end)) {
|
||||
list.push(next);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (includeTime) {
|
||||
list.unshift(start);
|
||||
list.push(end);
|
||||
} else {
|
||||
list.unshift(exports.createDay(start));
|
||||
list.push(exports.createDay(end));
|
||||
}
|
||||
|
||||
return list;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an array of weekdays based on the start date.
|
||||
* Will always return the 7 daysof that week regardless of
|
||||
* what the start date isbut they will be returned
|
||||
* in the order of their localized getDay function.
|
||||
*
|
||||
* @param {Date} startDate point of origin.
|
||||
* @return {Array} a list of dates in order of getDay().
|
||||
*/
|
||||
exports.getWeeksDays = function(startDate) {
|
||||
//local day position
|
||||
var weeksDayStart = exports.getWeekStartDate(startDate);
|
||||
var result = [weeksDayStart];
|
||||
|
||||
for (var i = 1; i < 7; i++) {
|
||||
result.push(exports.createDay(weeksDayStart, weeksDayStart.getDate() + i));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if date is in the past
|
||||
*
|
||||
* @param {Date} date to check.
|
||||
* @return {Boolean} true when date is in the past.
|
||||
*/
|
||||
exports.isPast = function(date) {
|
||||
return (date.valueOf() < exports.today.valueOf());
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if date is in the future
|
||||
*
|
||||
* @param {Date} date to check.
|
||||
* @return {Boolean} true when date is in the future.
|
||||
*/
|
||||
exports.isFuture = function(date) {
|
||||
return !exports.isPast(date);
|
||||
};
|
||||
|
||||
/**
|
||||
* Based on the input date
|
||||
* will return one of the following states
|
||||
*
|
||||
* past, present, future
|
||||
*
|
||||
* @param {Date} day for compare.
|
||||
* @param {Date} month comparison month.
|
||||
* @return {String} state.
|
||||
*/
|
||||
exports.relativeState = function(day, month) {
|
||||
var states;
|
||||
//var today = exports.today;
|
||||
|
||||
// 1. the date is today (real time)
|
||||
if (exports.isToday(day)) {
|
||||
return exports.PRESENT;
|
||||
}
|
||||
|
||||
// 2. the date is in the past (real time)
|
||||
if (exports.isPast(day)) {
|
||||
states = exports.PAST;
|
||||
// 3. the date is in the future (real time)
|
||||
} else {
|
||||
states = exports.FUTURE;
|
||||
}
|
||||
|
||||
// 4. the date is not in the current month (relative time)
|
||||
if (day.getMonth() !== month.getMonth()) {
|
||||
states += ' ' + exports.OTHER_MONTH;
|
||||
}
|
||||
|
||||
return states;
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the relative hour (0...23.9999) inside the given day.
|
||||
* If `date` is on a different day than `baseDate` it will return `0`.
|
||||
* Used by week view to compute the position of the busytimes relative to
|
||||
* the top of the view.
|
||||
*/
|
||||
exports.relativeOffset = function(baseDate, date) {
|
||||
if (exports.isSameDate(baseDate, date)) {
|
||||
return date.getHours() + (date.getMinutes() / 60);
|
||||
}
|
||||
// different day!
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the relative duration between startDate and endDate inside
|
||||
* a given baseDate. Returns a number between 0 and 24.
|
||||
* Used by MultiDay view to compute the height of the busytimes relative to
|
||||
* the length inside the baseDate.
|
||||
*/
|
||||
exports.relativeDuration = function(baseDate, startDate, endDate) {
|
||||
if (!exports.isSameDate(startDate, endDate)) {
|
||||
if (exports.isSameDate(baseDate, startDate)) {
|
||||
endDate = exports.endOfDay(baseDate);
|
||||
} else if (exports.isSameDate(baseDate, endDate)) {
|
||||
startDate = exports.createDay(endDate);
|
||||
} else {
|
||||
// started before baseDate and ends on a different day
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
return exports.hourDiff(startDate, endDate);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if event spans thru the whole day.
|
||||
*/
|
||||
exports.isAllDay = function(baseDate, startDate, endDate) {
|
||||
// beginning reference point (start of given date)
|
||||
var refStart = exports.createDay(baseDate);
|
||||
var refEnd = exports.endOfDay(baseDate);
|
||||
|
||||
var startBefore = startDate <= refStart;
|
||||
var endsAfter = endDate >= refEnd;
|
||||
|
||||
// yahoo uses same start/end date for recurring all day events!!!
|
||||
return (startBefore && endsAfter) || Number(startDate) === Number(endDate);
|
||||
};
|
||||
|
||||
if (typeof(window) !== 'undefined') {
|
||||
window.addEventListener('localized', co.wrap(function *() {
|
||||
exports.startDay = yield mozIntl.calendarInfo('firstDayOfTheWeek');
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
16
gaia/apps/calendar/js/common/compare.js
Executable file
16
gaia/apps/calendar/js/common/compare.js
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
module.exports = function(a, b) {
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
});
|
||||
6
gaia/apps/calendar/js/common/constants.js
Executable file
6
gaia/apps/calendar/js/common/constants.js
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
define(function(require, exports) {
|
||||
'use strict';
|
||||
|
||||
exports.localCalendarId = 'local-first';
|
||||
|
||||
});
|
||||
16
gaia/apps/calendar/js/common/create_dom_promise.js
Executable file
16
gaia/apps/calendar/js/common/create_dom_promise.js
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @fileoverview Simple helper function to convert basic platform DOMRequest
|
||||
* into Promise. Deprecate once there is platform support for something
|
||||
* like DOMRequest.then().
|
||||
*/
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
module.exports = function createDOMPromise(request) {
|
||||
return new Promise((resolve, reject) => {
|
||||
request.onsuccess = resolve;
|
||||
request.onerror = reject;
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
13
gaia/apps/calendar/js/common/debug.js
Executable file
13
gaia/apps/calendar/js/common/debug.js
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
module.exports = function(name) {
|
||||
return function() {
|
||||
var args = Array.prototype.slice.call(arguments).map(JSON.stringify);
|
||||
args.unshift('[calendar] ');
|
||||
args.unshift(name);
|
||||
console.log.apply(console, args);
|
||||
};
|
||||
};
|
||||
|
||||
});
|
||||
37
gaia/apps/calendar/js/common/error.js
Executable file
37
gaia/apps/calendar/js/common/error.js
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* These errors are _not_ exceptions and are designed to be passed not thrown
|
||||
* in typical |throw new X| fashion.
|
||||
*/
|
||||
function Base(name, detail) {
|
||||
this.message = 'oops... why did you throw this?';
|
||||
this.name = name;
|
||||
this.detail = detail;
|
||||
}
|
||||
module.exports = Base;
|
||||
|
||||
Base.prototype = Object.create(Error.prototype);
|
||||
|
||||
function errorFactory(name, l10nID) {
|
||||
var error = function(detail) {
|
||||
this.name = name;
|
||||
this.detail = detail;
|
||||
/**
|
||||
* we need to use l10nID's for backwards compatibility
|
||||
* (not changing string IDs between releases).
|
||||
*/
|
||||
this.l10nID = l10nID || name;
|
||||
};
|
||||
|
||||
error.prototype = Object.create(Base.prototype);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* note names should _never_ change */
|
||||
Base.Authentication = errorFactory('authentication', 'unauthenticated');
|
||||
Base.InvalidServer = errorFactory('invalid-server', 'internal-server-error');
|
||||
Base.ServerFailure = errorFactory('server-failure', 'internal-server-error');
|
||||
|
||||
});
|
||||
14
gaia/apps/calendar/js/common/extend.js
Executable file
14
gaia/apps/calendar/js/common/extend.js
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
module.exports = function(target, input) {
|
||||
for (var key in input) {
|
||||
if (hasOwnProperty.call(input, key)) {
|
||||
target[key] = input[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
});
|
||||
11
gaia/apps/calendar/js/common/is_offline.js
Executable file
11
gaia/apps/calendar/js/common/is_offline.js
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Returns the offline status.
|
||||
*/
|
||||
module.exports = function() {
|
||||
return (navigator && 'onLine' in navigator) ? !navigator.onLine : true;
|
||||
};
|
||||
|
||||
});
|
||||
14
gaia/apps/calendar/js/common/next_tick.js
Executable file
14
gaia/apps/calendar/js/common/next_tick.js
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var resolved = Promise.resolve();
|
||||
|
||||
/**
|
||||
* Very similar to node's nextTick.
|
||||
* Much faster than setTimeout or window.postMessage
|
||||
*/
|
||||
module.exports = function(callback) {
|
||||
resolved.then(callback);
|
||||
};
|
||||
|
||||
});
|
||||
36
gaia/apps/calendar/js/common/object.js
Executable file
36
gaia/apps/calendar/js/common/object.js
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
exports.filter = function(obj, fn, thisArg) {
|
||||
var results = [];
|
||||
exports.forEach(obj, function(key, value) {
|
||||
if (fn.call(thisArg, key, value)) {
|
||||
results.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.forEach = function(obj, fn, thisArg) {
|
||||
exports.map(obj, fn, thisArg);
|
||||
};
|
||||
|
||||
exports.map = function(obj, fn, thisArg) {
|
||||
var results = [];
|
||||
Object.keys(obj).forEach((key) => {
|
||||
var value = obj[key];
|
||||
var result = fn.call(thisArg, key, value);
|
||||
results.push(result);
|
||||
});
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.values = function(obj) {
|
||||
return exports.map(obj, (key, value) => {
|
||||
return value;
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
20
gaia/apps/calendar/js/common/probably_parse_int.js
Executable file
20
gaia/apps/calendar/js/common/probably_parse_int.js
Executable file
|
|
@ -0,0 +1,20 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
var NUMERIC = /^[0-9]+$/;
|
||||
|
||||
/**
|
||||
* @param {number|string} id Some id.
|
||||
*/
|
||||
module.exports = function(id) {
|
||||
// by an unfortunate decision we have both
|
||||
// string ids and number ids.. based on the
|
||||
// input we run parseInt
|
||||
if (typeof id === 'string' && id.match(NUMERIC)) {
|
||||
return parseInt(id, 10);
|
||||
}
|
||||
|
||||
return id;
|
||||
};
|
||||
|
||||
});
|
||||
61
gaia/apps/calendar/js/common/promise.js
Executable file
61
gaia/apps/calendar/js/common/promise.js
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @fileoverview Utilities for converting async functions which use
|
||||
* node-style callbacks to also cater promises callers.
|
||||
*/
|
||||
define(function(require, exports) {
|
||||
'use strict';
|
||||
|
||||
function denodeify(fn) {
|
||||
// This is our new, denodeified function. You can interact with it using
|
||||
// node-style callbacks or promises.
|
||||
return function() {
|
||||
// Original arguments to fn.
|
||||
var args = Array.slice(arguments);
|
||||
if (args.length === fn.length) {
|
||||
// If consumer is trying to interact with node-style callback, let them.
|
||||
// If they were going for the promise, then the function would expect
|
||||
// one more arg than was provided (the callback arg).
|
||||
return fn.apply(this, args);
|
||||
}
|
||||
|
||||
// We need the defer style promise api here since we don't want to
|
||||
// accidentily step on functions that return things like DOMRequests...
|
||||
var deferred = defer();
|
||||
args.push(function(err, result) {
|
||||
if (err) {
|
||||
return deferred.reject(err);
|
||||
}
|
||||
|
||||
// we resolve with a single value (array) in case of multiple arguments
|
||||
if (arguments.length > 2) {
|
||||
result = Array.prototype.slice.call(arguments, 1);
|
||||
}
|
||||
deferred.resolve(result);
|
||||
});
|
||||
|
||||
// Return the promise <=> the function doesn't return an object.
|
||||
var returnValue = fn.apply(this, args);
|
||||
return typeof returnValue === 'object' ? returnValue : deferred.promise;
|
||||
};
|
||||
}
|
||||
exports.denodeify = denodeify;
|
||||
|
||||
function denodeifyAll(object, methods) {
|
||||
methods.forEach((method) => {
|
||||
object[method] = exports.denodeify(object[method]);
|
||||
});
|
||||
}
|
||||
exports.denodeifyAll = denodeifyAll;
|
||||
|
||||
function defer() {
|
||||
var deferred = {};
|
||||
var promise = new Promise((resolve, reject) => {
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
|
||||
deferred.promise = promise;
|
||||
return deferred;
|
||||
}
|
||||
|
||||
});
|
||||
236
gaia/apps/calendar/js/common/responder.js
Executable file
236
gaia/apps/calendar/js/common/responder.js
Executable file
|
|
@ -0,0 +1,236 @@
|
|||
// this code is from test-agent might use native dom events
|
||||
// or something else in the future to replace this.
|
||||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @param {Object} list of events to add onto responder.
|
||||
*/
|
||||
function Responder(events) {
|
||||
this._$events = Object.create(null);
|
||||
|
||||
// Buffer for emitWhenListener that hangs onto events dispatched for topics
|
||||
// no one is currently listening for. Inspired by email's function
|
||||
// of the same name.
|
||||
this.buffer = {};
|
||||
|
||||
if (typeof(events) !== 'undefined') {
|
||||
this.addEventListener(events);
|
||||
}
|
||||
}
|
||||
module.exports = Responder;
|
||||
|
||||
/**
|
||||
* Stringifies request to websocket
|
||||
*
|
||||
*
|
||||
* @param {String} command command name.
|
||||
* @param {Object} data object to be sent over the wire.
|
||||
* @return {String} json object.
|
||||
*/
|
||||
Responder.stringify = function stringify(command, data) {
|
||||
return JSON.stringify([command, data]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses request from WebSocket.
|
||||
*
|
||||
* @param {String} json json string to translate.
|
||||
* @return {Object} ex: { event: 'test', data: {} }.
|
||||
*/
|
||||
Responder.parse = function parse(json) {
|
||||
var data;
|
||||
try {
|
||||
data = (json.forEach) ? json : JSON.parse(json);
|
||||
} catch (e) {
|
||||
throw new Error('Could not parse json: "' + json + '"');
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
Responder.prototype = {
|
||||
parse: Responder.parse,
|
||||
stringify: Responder.stringify,
|
||||
|
||||
/**
|
||||
* Events on this instance
|
||||
*
|
||||
* @type Object
|
||||
*/
|
||||
events: null,
|
||||
|
||||
/**
|
||||
* Recieves json string event and dispatches an event.
|
||||
*
|
||||
* @param {String|Object} json data object to respond to.
|
||||
* @param {String} json.event event to emit.
|
||||
* @param {Object} json.data data to emit with event.
|
||||
* @param {Object} [params] option number of params to pass to emit.
|
||||
* @return {Object} result of WebSocketCommon.parse.
|
||||
*/
|
||||
respond: function respond(json) {
|
||||
var event = Responder.parse(json);
|
||||
var args = Array.prototype.slice.call(arguments).slice(1);
|
||||
this.emit.apply(this, event.concat(args));
|
||||
return event;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an event listener to this object.
|
||||
*
|
||||
* @param {String} type event name.
|
||||
* @param {Function} callback event callback.
|
||||
*/
|
||||
addEventListener: function addEventListener(type, callback) {
|
||||
var event;
|
||||
|
||||
if (typeof(callback) === 'undefined' && typeof(type) === 'object') {
|
||||
for (event in type) {
|
||||
if (type.hasOwnProperty(event)) {
|
||||
this.addEventListener(event, type[event]);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (!(type in this._$events)) {
|
||||
this._$events[type] = [];
|
||||
}
|
||||
|
||||
this._$events[type].push(callback);
|
||||
return this.flushTopicBuffer(type);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an event listener which will
|
||||
* only fire once and then remove itself.
|
||||
*
|
||||
*
|
||||
* @param {String} type event name.
|
||||
* @param {Function} callback fired when event is emitted.
|
||||
*/
|
||||
once: function once(type, callback) {
|
||||
var self = this;
|
||||
function onceCb() {
|
||||
/*jshint validthis:true */
|
||||
self.removeEventListener(type, onceCb);
|
||||
callback.apply(this, arguments);
|
||||
}
|
||||
|
||||
this.addEventListener(type, onceCb);
|
||||
return this.flushTopicBuffer(type);
|
||||
},
|
||||
|
||||
flushTopicBuffer: function flushTopicBuffer(topic) {
|
||||
if (!(topic in this.buffer)) {
|
||||
// Nothing to flush.
|
||||
return this;
|
||||
}
|
||||
|
||||
this.buffer[topic].forEach(args => {
|
||||
args.unshift(topic);
|
||||
this.emit.apply(this, args);
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Emits an event.
|
||||
*
|
||||
* Accepts any number of additional arguments to pass unto
|
||||
* event listener.
|
||||
*
|
||||
* @param {String} eventName name of the event to emit.
|
||||
* @param {Object} [arguments] additional arguments to pass.
|
||||
*/
|
||||
emit: function emit() {
|
||||
var args = Array.prototype.slice.call(arguments),
|
||||
event = args.shift(),
|
||||
eventList,
|
||||
self = this;
|
||||
|
||||
if (event in this._$events) {
|
||||
eventList = this._$events[event];
|
||||
|
||||
eventList.forEach(function(callback) {
|
||||
if (typeof(callback) === 'object' && callback.handleEvent) {
|
||||
callback.handleEvent({ type: event, data: args });
|
||||
} else {
|
||||
callback.apply(self, args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
emitWhenListener: function emitWhenListener() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var event = args.shift();
|
||||
|
||||
if (event in this._$events && this._$events[event].length) {
|
||||
// Someone is already listening for this event, so this is just
|
||||
// a regular old emit.
|
||||
return this.emit.apply(this, arguments);
|
||||
}
|
||||
|
||||
if (!(event in this.buffer)) {
|
||||
this.buffer[event] = [];
|
||||
}
|
||||
|
||||
// Now just push the call info onto the topic buffer.
|
||||
this.buffer[event].push(args);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all event listeners for a given event type
|
||||
*
|
||||
*
|
||||
* @param {String} event event type to remove.
|
||||
*/
|
||||
removeAllEventListeners: function removeAllEventListeners(name) {
|
||||
if (name in this._$events) {
|
||||
//reuse array
|
||||
this._$events[name].length = 0;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes a single event listener from a given event type
|
||||
* and callback function.
|
||||
*
|
||||
*
|
||||
* @param {String} eventName event name.
|
||||
* @param {Function} callback same instance of event handler.
|
||||
*/
|
||||
removeEventListener: function removeEventListener(name, callback) {
|
||||
var i, length, events;
|
||||
|
||||
if (!(name in this._$events)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
events = this._$events[name];
|
||||
|
||||
for (i = 0, length = events.length; i < length; i++) {
|
||||
if (events[i] && events[i] === callback) {
|
||||
events.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Responder.prototype.on = Responder.prototype.addEventListener;
|
||||
Responder.prototype.off = Responder.prototype.removeEventListener;
|
||||
|
||||
});
|
||||
114
gaia/apps/calendar/js/common/timespan.js
Executable file
114
gaia/apps/calendar/js/common/timespan.js
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
define(function(require, exports, module) {
|
||||
'use strict';
|
||||
|
||||
function Timespan(startDate, endDate) {
|
||||
this.start = startDate.valueOf();
|
||||
this.end = endDate.valueOf();
|
||||
}
|
||||
module.exports = Timespan;
|
||||
|
||||
Timespan.prototype = {
|
||||
isEqual: function(inputSpan) {
|
||||
return (
|
||||
this.start === inputSpan.start &&
|
||||
this.end === inputSpan.end
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* If given Timespan overlaps this timespan
|
||||
* return a new timespan with the overlapping
|
||||
* parts removed.
|
||||
*
|
||||
* See tests for examples...
|
||||
*/
|
||||
trimOverlap: function(span) {
|
||||
if (this.contains(span) || span.contains(this)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var start = span.start;
|
||||
var end = span.end;
|
||||
var ourEnd = this.end;
|
||||
var ourStart = this.start;
|
||||
|
||||
var overlapsBefore = start >= ourStart && start < ourEnd;
|
||||
var overlapsAfter = ourStart >= start && ourStart < end;
|
||||
|
||||
var newStart = span.start;
|
||||
var newEnd = span.end;
|
||||
|
||||
if (overlapsBefore) {
|
||||
newStart = ourEnd + 1;
|
||||
}
|
||||
|
||||
if (overlapsAfter) {
|
||||
newEnd = ourStart - 1;
|
||||
}
|
||||
|
||||
return new Timespan(newStart, newEnd);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if given time overlaps with
|
||||
* range.
|
||||
*
|
||||
* @param {Date|Numeric|Timespan} start range or one position.
|
||||
* @param {Date|Numeric} [end] do a span comparison.
|
||||
*/
|
||||
overlaps: function(start, end) {
|
||||
var ourStart = this.start;
|
||||
var ourEnd = this.end;
|
||||
|
||||
if (start instanceof Timespan) {
|
||||
end = start.end;
|
||||
start = start.start;
|
||||
} else {
|
||||
// start/end expected
|
||||
start = (start instanceof Date) ? start.valueOf() : start;
|
||||
end = (end instanceof Date) ? end.valueOf() : end;
|
||||
}
|
||||
|
||||
return (
|
||||
start >= ourStart && start < ourEnd ||
|
||||
ourStart >= start && ourStart < end
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* When given a date checks if
|
||||
* date is inside given range.
|
||||
*
|
||||
*
|
||||
* @param {Date} date date or event.
|
||||
*/
|
||||
contains: function(date) {
|
||||
var start = this.start;
|
||||
var end = this.end;
|
||||
|
||||
if (date instanceof Date) {
|
||||
return start <= date && end >= date;
|
||||
} else if (date instanceof Timespan) {
|
||||
return start <= date.start &&
|
||||
end >= date.end;
|
||||
} else {
|
||||
return this.containsNumeric(date);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Numeric comparison assumes
|
||||
* given seconds since epoch.
|
||||
*
|
||||
* @param {Numeric} timestamp numeric timestamp.
|
||||
*/
|
||||
containsNumeric: function(timestamp) {
|
||||
var start = this.start;
|
||||
var end = this.end;
|
||||
|
||||
return start <= timestamp &&
|
||||
end >= timestamp;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue