diff --git a/docs/THIRDPARTY b/docs/THIRDPARTY index 32550264ba..59e8d3bd2b 100644 --- a/docs/THIRDPARTY +++ b/docs/THIRDPARTY @@ -187,10 +187,6 @@ Files: static/third/spectrum/* Copyright: 2013 Brian Grinstead License: Expat -Files: static/third/xdate/* -Copyright: 2010 C. F., Wong -License: Expat - Files: static/third/zocial/* Copyright: Sam Collins License: Expat diff --git a/frontend_tests/node_tests/message_edit.js b/frontend_tests/node_tests/message_edit.js index ae86e236dc..7a06d07b6e 100644 --- a/frontend_tests/node_tests/message_edit.js +++ b/frontend_tests/node_tests/message_edit.js @@ -2,7 +2,7 @@ set_global('document', null); set_global('page_params', {}); add_dependencies({ - XDate: 'third/xdate/xdate.dev.js', + XDate: 'node_modules/xdate/src/xdate.js', }); var message_edit = require('js/message_edit.js'); diff --git a/frontend_tests/node_tests/message_list_view.js b/frontend_tests/node_tests/message_list_view.js index 0ec8dfe883..a2306d4c39 100644 --- a/frontend_tests/node_tests/message_list_view.js +++ b/frontend_tests/node_tests/message_list_view.js @@ -3,7 +3,7 @@ var MessageListView = require('js/message_list_view.js'); add_dependencies({ $: 'jquery', - XDate: 'third/xdate/xdate.dev.js', + XDate: 'node_modules/xdate/src/xdate.js', util: 'js/util.js', }); diff --git a/package.json b/package.json index 448de926e5..e783fb5972 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "underscore": "1.8.3", "webpack": "1.12.2", "winchan": "0.2.0", + "xdate": "0.8.0", "zxcvbn": "4.4.1" }, "devDependencies": { diff --git a/static/third/xdate/xdate.dev.js b/static/third/xdate/xdate.dev.js deleted file mode 100644 index fcb089bb2a..0000000000 --- a/static/third/xdate/xdate.dev.js +++ /dev/null @@ -1,860 +0,0 @@ -/** @preserve - Software from "XDate v0.8", a wrapper around JavaScript's Date object, is - Copyright (c) 2010 C. F., Wong and is provided under the following license: - -- - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -- -*/ - -/** - * XDate v0.8 - * Docs & Licensing: http://arshaw.com/xdate/ - */ - -/* - * Internal Architecture - * --------------------- - * An XDate wraps a native Date. The native Date is stored in the '0' property of the object. - * UTC-mode is determined by whether the internal native Date's toString method is set to - * Date.prototype.toUTCString (see getUTCMode). - * - */ - -var XDate = (function(Date, Math, Array, undefined) { - - -/** @const */ var FULLYEAR = 0; -/** @const */ var MONTH = 1; -/** @const */ var DATE = 2; -/** @const */ var HOURS = 3; -/** @const */ var MINUTES = 4; -/** @const */ var SECONDS = 5; -/** @const */ var MILLISECONDS = 6; -/** @const */ var DAY = 7; -/** @const */ var YEAR = 8; -/** @const */ var WEEK = 9; -/** @const */ var DAY_MS = 86400000; -var ISO_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss(.fff)"; -var ISO_FORMAT_STRING_TZ = ISO_FORMAT_STRING + "zzz"; - - -var methodSubjects = [ - 'FullYear', // 0 - 'Month', // 1 - 'Date', // 2 - 'Hours', // 3 - 'Minutes', // 4 - 'Seconds', // 5 - 'Milliseconds', // 6 - 'Day', // 7 - 'Year' // 8 -]; -var subjectPlurals = [ - 'Years', // 0 - 'Months', // 1 - 'Days' // 2 -]; -var unitsWithin = [ - 12, // months in year - 31, // days in month (sort of) - 24, // hours in day - 60, // minutes in hour - 60, // seconds in minute - 1000, // milliseconds in second - 1 // -]; -var formatStringRE = new RegExp( - "(([a-zA-Z])\\2*)|" + // 1, 2 - "(\\(" + "(('.*?'|\\(.*?\\)|.)*?)" + "\\))|" + // 3, 4, 5 (allows for 1 level of inner quotes or parens) - "('(.*?)')" // 6, 7 -); -var UTC = Date.UTC; -var toUTCString = Date.prototype.toUTCString; -var proto = XDate.prototype; - - - -// This makes an XDate look pretty in Firebug and Web Inspector. -// It makes an XDate seem array-like, and displays [ .toString() ] -proto.length = 1; -proto.splice = Array.prototype.splice; - - - - -/* Constructor ----------------------------------------------------------------------------------*/ - -// TODO: in future, I'd change signature for the constructor regarding the `true` utc-mode param. ~ashaw -// I'd move the boolean to be the *first* argument. Still optional. Seems cleaner. -// I'd remove it from the `xdate`, `nativeDate`, and `milliseconds` constructors. -// (because you can simply call .setUTCMode(true) after) -// And I'd only leave it for the y/m/d/h/m/s/m and `dateString` constructors -// (because those are the only constructors that need it for DST-gap data-loss reasons) -// Should do this for 1.0 - -function XDate() { - return init( - (this instanceof XDate) ? this : new XDate(), - arguments - ); -} - - -function init(xdate, args) { - var len = args.length; - var utcMode; - if (isBoolean(args[len-1])) { - utcMode = args[--len]; - args = slice(args, 0, len); - } - if (!len) { - xdate[0] = new Date(); - } - else if (len == 1) { - var arg = args[0]; - if (arg instanceof Date || isNumber(arg)) { - xdate[0] = new Date(+arg); - } - else if (arg instanceof XDate) { - xdate[0] = _clone(arg); - } - else if (isString(arg)) { - xdate[0] = new Date(0); - xdate = parse(arg, utcMode || false, xdate); - } - } - else { - xdate[0] = new Date(UTC.apply(Date, args)); - if (!utcMode) { - xdate[0] = coerceToLocal(xdate[0]); - } - } - if (isBoolean(utcMode)) { - setUTCMode(xdate, utcMode); - } - return xdate; -} - - - -/* UTC Mode Methods ----------------------------------------------------------------------------------*/ - - -proto.getUTCMode = methodize(getUTCMode); -function getUTCMode(xdate) { - return xdate[0].toString === toUTCString; -}; - - -proto.setUTCMode = methodize(setUTCMode); -function setUTCMode(xdate, utcMode, doCoercion) { - if (utcMode) { - if (!getUTCMode(xdate)) { - if (doCoercion) { - xdate[0] = coerceToUTC(xdate[0]); - } - xdate[0].toString = toUTCString; - } - }else{ - if (getUTCMode(xdate)) { - if (doCoercion) { - xdate[0] = coerceToLocal(xdate[0]); - }else{ - xdate[0] = new Date(+xdate[0]); - } - // toString will have been cleared - } - } - return xdate; // for chaining -} - - -proto.getTimezoneOffset = function() { - if (getUTCMode(this)) { - return 0; - }else{ - return this[0].getTimezoneOffset(); - } -}; - - - -/* get / set / add / diff Methods (except for week-related) ----------------------------------------------------------------------------------*/ - - -each(methodSubjects, function(subject, fieldIndex) { - - proto['get' + subject] = function() { - return _getField(this[0], getUTCMode(this), fieldIndex); - }; - - if (fieldIndex != YEAR) { // because there is no getUTCYear - - proto['getUTC' + subject] = function() { - return _getField(this[0], true, fieldIndex); - }; - - } - - if (fieldIndex != DAY) { // because there is no setDay or setUTCDay - // and the add* and diff* methods use DATE instead - - proto['set' + subject] = function(value) { - _set(this, fieldIndex, value, arguments, getUTCMode(this)); - return this; // for chaining - }; - - if (fieldIndex != YEAR) { // because there is no setUTCYear - // and the add* and diff* methods use FULLYEAR instead - - proto['setUTC' + subject] = function(value) { - _set(this, fieldIndex, value, arguments, true); - return this; // for chaining - }; - - proto['add' + (subjectPlurals[fieldIndex] || subject)] = function(delta, preventOverflow) { - _add(this, fieldIndex, delta, preventOverflow); - return this; // for chaining - }; - - proto['diff' + (subjectPlurals[fieldIndex] || subject)] = function(otherDate) { - return _diff(this, otherDate, fieldIndex); - }; - - } - - } - -}); - - -function _set(xdate, fieldIndex, value, args, useUTC) { - var getField = curry(_getField, xdate[0], useUTC); - var setField = curry(_setField, xdate[0], useUTC); - var expectedMonth; - var preventOverflow = false; - if (args.length == 2 && isBoolean(args[1])) { - preventOverflow = args[1]; - args = [ value ]; - } - if (fieldIndex == MONTH) { - expectedMonth = (value % 12 + 12) % 12; - }else{ - expectedMonth = getField(MONTH); - } - setField(fieldIndex, args); - if (preventOverflow && getField(MONTH) != expectedMonth) { - setField(MONTH, [ getField(MONTH) - 1 ]); - setField(DATE, [ getDaysInMonth(getField(FULLYEAR), getField(MONTH)) ]); - } -} - - -function _add(xdate, fieldIndex, delta, preventOverflow) { - delta = Number(delta); - var intDelta = Math.floor(delta); - xdate['set' + methodSubjects[fieldIndex]]( - xdate['get' + methodSubjects[fieldIndex]]() + intDelta, - preventOverflow || false - ); - if (intDelta != delta && fieldIndex < MILLISECONDS) { - _add(xdate, fieldIndex+1, (delta-intDelta)*unitsWithin[fieldIndex], preventOverflow); - } -} - - -function _diff(xdate1, xdate2, fieldIndex) { // fieldIndex=FULLYEAR is for years, fieldIndex=DATE is for days - xdate1 = xdate1.clone().setUTCMode(true, true); - xdate2 = XDate(xdate2).setUTCMode(true, true); - var v = 0; - if (fieldIndex == FULLYEAR || fieldIndex == MONTH) { - for (var i=MILLISECONDS, methodName; i>=fieldIndex; i--) { - v /= unitsWithin[i]; - v += _getField(xdate2, false, i) - _getField(xdate1, false, i); - } - if (fieldIndex == MONTH) { - v += (xdate2.getFullYear() - xdate1.getFullYear()) * 12; - } - } - else if (fieldIndex == DATE) { - var clear1 = xdate1.toDate().setUTCHours(0, 0, 0, 0); // returns an ms value - var clear2 = xdate2.toDate().setUTCHours(0, 0, 0, 0); // returns an ms value - v = Math.round((clear2 - clear1) / DAY_MS) + ((xdate2 - clear2) - (xdate1 - clear1)) / DAY_MS; - } - else { - v = (xdate2 - xdate1) / [ - 3600000, // milliseconds in hour - 60000, // milliseconds in minute - 1000, // milliseconds in second - 1 // - ][fieldIndex - 3]; - } - return v; -} - - - -/* Week Methods ----------------------------------------------------------------------------------*/ - - -proto.getWeek = function() { - return _getWeek(curry(_getField, this, false)); -}; - - -proto.getUTCWeek = function() { - return _getWeek(curry(_getField, this, true)); -}; - - -proto.setWeek = function(n, year) { - _setWeek(this, n, year, false); - return this; // for chaining -}; - - -proto.setUTCWeek = function(n, year) { - _setWeek(this, n, year, true); - return this; // for chaining -}; - - -proto.addWeeks = function(delta) { - return this.addDays(Number(delta) * 7); -}; - - -proto.diffWeeks = function(otherDate) { - return _diff(this, otherDate, DATE) / 7; -}; - - -function _getWeek(getField) { - return getWeek(getField(FULLYEAR), getField(MONTH), getField(DATE)); -} - - -function getWeek(year, month, date) { - var d = new Date(UTC(year, month, date)); - var week1 = getWeek1( - getWeekYear(year, month, date) - ); - return Math.floor(Math.round((d - week1) / DAY_MS) / 7) + 1; -} - - -function getWeekYear(year, month, date) { // get the year that the date's week # belongs to - var d = new Date(UTC(year, month, date)); - if (d < getWeek1(year)) { - return year - 1; - } - else if (d >= getWeek1(year + 1)) { - return year + 1; - } - return year; -} - - -function getWeek1(year) { // returns Date of first week of year, in UTC - var d = new Date(UTC(year, 0, 4)); - d.setUTCDate(d.getUTCDate() - (d.getUTCDay() + 6) % 7); // make it Monday of the week - return d; -} - - -function _setWeek(xdate, n, year, useUTC) { - var getField = curry(_getField, xdate, useUTC); - var setField = curry(_setField, xdate, useUTC); - - if (year === undefined) { - year = getWeekYear( - getField(FULLYEAR), - getField(MONTH), - getField(DATE) - ); - } - - var week1 = getWeek1(year); - if (!useUTC) { - week1 = coerceToLocal(week1); - } - - xdate.setTime(+week1); - setField(DATE, [ getField(DATE) + (n-1) * 7 ]); // would have used xdate.addUTCWeeks :( - // n-1 because n is 1-based -} - - - -/* Parsing ----------------------------------------------------------------------------------*/ - - -XDate.parsers = [ - parseISO -]; - - -XDate.parse = function(str) { - return +XDate(''+str); -}; - - -function parse(str, utcMode, xdate) { - var parsers = XDate.parsers; - var i = 0; - var res; - for (; i=0; i--) { - uniqueness.push(getField(i)); - } - } - return getField(fieldIndex); - } - - return _format(xdate, formatString, getFieldAndTrace, getSetting, useUTC); -} - - -function _format(xdate, formatString, getField, getSetting, useUTC) { - var m; - var subout; - var out = ''; - while (m = formatString.match(formatStringRE)) { - out += formatString.substr(0, m.index); - if (m[1]) { // consecutive alphabetic characters - out += processTokenString(xdate, m[1], getField, getSetting, useUTC); - } - else if (m[3]) { // parenthesis - subout = _format(xdate, m[4], getField, getSetting, useUTC); - if (parseInt(subout.replace(/\D/g, ''), 10)) { // if any of the numbers are non-zero. or no numbers at all - out += subout; - } - } - else { // else if (m[6]) { // single quotes - out += m[7] || "'"; // if inner is blank, meaning 2 consecutive quotes = literal single quote - } - formatString = formatString.substr(m.index + m[0].length); - } - return out + formatString; -} - - -function processTokenString(xdate, tokenString, getField, getSetting, useUTC) { - var end = tokenString.length; - var replacement; - var out = ''; - while (end > 0) { - replacement = getTokenReplacement(xdate, tokenString.substr(0, end), getField, getSetting, useUTC); - if (replacement !== undefined) { - out += replacement; - tokenString = tokenString.substr(end); - end = tokenString.length; - }else{ - end--; - } - } - return out + tokenString; -} - - -function getTokenReplacement(xdate, token, getField, getSetting, useUTC) { - var formatter = XDate.formatters[token]; - if (isString(formatter)) { - return _format(xdate, formatter, getField, getSetting, useUTC); - } - else if (isFunction(formatter)) { - return formatter(xdate, useUTC || false, getSetting); - } - switch (token) { - case 'fff' : return zeroPad(getField(MILLISECONDS), 3); - case 's' : return getField(SECONDS); - case 'ss' : return zeroPad(getField(SECONDS)); - case 'm' : return getField(MINUTES); - case 'mm' : return zeroPad(getField(MINUTES)); - case 'h' : return getField(HOURS) % 12 || 12; - case 'hh' : return zeroPad(getField(HOURS) % 12 || 12); - case 'H' : return getField(HOURS); - case 'HH' : return zeroPad(getField(HOURS)); - case 'd' : return getField(DATE); - case 'dd' : return zeroPad(getField(DATE)); - case 'ddd' : return getSetting('dayNamesShort')[getField(DAY)] || ''; - case 'dddd' : return getSetting('dayNames')[getField(DAY)] || ''; - case 'M' : return getField(MONTH) + 1; - case 'MM' : return zeroPad(getField(MONTH) + 1); - case 'MMM' : return getSetting('monthNamesShort')[getField(MONTH)] || ''; - case 'MMMM' : return getSetting('monthNames')[getField(MONTH)] || ''; - case 'yy' : return (getField(FULLYEAR)+'').substring(2); - case 'yyyy' : return getField(FULLYEAR); - case 't' : return _getDesignator(getField, getSetting).substr(0, 1).toLowerCase(); - case 'tt' : return _getDesignator(getField, getSetting).toLowerCase(); - case 'T' : return _getDesignator(getField, getSetting).substr(0, 1); - case 'TT' : return _getDesignator(getField, getSetting); - case 'z' : - case 'zz' : - case 'zzz' : return useUTC ? 'Z' : _getTZString(xdate, token); - case 'w' : return _getWeek(getField); - case 'ww' : return zeroPad(_getWeek(getField)); - case 'S' : - var d = getField(DATE); - if (d > 10 && d < 20) return 'th'; - return ['st', 'nd', 'rd'][d % 10 - 1] || 'th'; - } -} - - -function _getTZString(xdate, token) { - var tzo = xdate.getTimezoneOffset(); - var sign = tzo < 0 ? '+' : '-'; - var hours = Math.floor(Math.abs(tzo) / 60); - var minutes = Math.abs(tzo) % 60; - var out = hours; - if (token == 'zz') { - out = zeroPad(hours); - } - else if (token == 'zzz') { - out = zeroPad(hours) + ':' + zeroPad(minutes); - } - return sign + out; -} - - -function _getDesignator(getField, getSetting) { - return getField(HOURS) < 12 ? getSetting('amDesignator') : getSetting('pmDesignator'); -} - - - -/* Misc Methods ----------------------------------------------------------------------------------*/ - - -each( - [ // other getters - 'getTime', - 'valueOf', - 'toDateString', - 'toTimeString', - 'toLocaleString', - 'toLocaleDateString', - 'toLocaleTimeString', - 'toJSON' - ], - function(methodName) { - proto[methodName] = function() { - return this[0][methodName](); - }; - } -); - - -proto.setTime = function(t) { - this[0].setTime(t); - return this; // for chaining -}; - - -proto.valid = methodize(valid); -function valid(xdate) { - return !isNaN(+xdate[0]); -} - - -proto.clone = function() { - return new XDate(this); -}; - - -proto.clearTime = function() { - return this.setHours(0, 0, 0, 0); // will return an XDate for chaining -}; - - -proto.toDate = function() { - return new Date(+this[0]); -}; - - - -/* Misc Class Methods ----------------------------------------------------------------------------------*/ - - -XDate.now = function() { - return +new Date(); -}; - - -XDate.today = function() { - return new XDate().clearTime(); -}; - - -XDate.UTC = UTC; - - -XDate.getDaysInMonth = getDaysInMonth; - - - -/* Internal Utilities ----------------------------------------------------------------------------------*/ - - -function _clone(xdate) { // returns the internal Date object that should be used - var d = new Date(+xdate[0]); - if (getUTCMode(xdate)) { - d.toString = toUTCString; - } - return d; -} - - -function _getField(d, useUTC, fieldIndex) { - return d['get' + (useUTC ? 'UTC' : '') + methodSubjects[fieldIndex]](); -} - - -function _setField(d, useUTC, fieldIndex, args) { - d['set' + (useUTC ? 'UTC' : '') + methodSubjects[fieldIndex]].apply(d, args); -} - - - -/* Date Math Utilities ----------------------------------------------------------------------------------*/ - - -function coerceToUTC(date) { - return new Date(UTC( - date.getFullYear(), - date.getMonth(), - date.getDate(), - date.getHours(), - date.getMinutes(), - date.getSeconds(), - date.getMilliseconds() - )); -} - - -function coerceToLocal(date) { - return new Date( - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate(), - date.getUTCHours(), - date.getUTCMinutes(), - date.getUTCSeconds(), - date.getUTCMilliseconds() - ); -} - - -function getDaysInMonth(year, month) { - return 32 - new Date(UTC(year, month, 32)).getUTCDate(); -} - - - -/* General Utilities ----------------------------------------------------------------------------------*/ - - -function methodize(f) { - return function() { - return f.apply(undefined, [this].concat(slice(arguments))); - }; -} - - -function curry(f) { - var firstArgs = slice(arguments, 1); - return function() { - return f.apply(undefined, firstArgs.concat(slice(arguments))); - }; -} - - -function slice(a, start, end) { - return Array.prototype.slice.call( - a, - start || 0, // start and end cannot be undefined for IE - end===undefined ? a.length : end - ); -} - - -function each(a, f) { - for (var i=0; i