sugar-rails 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. data/lib/sugar/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/precompiled/development/array.js +50 -15
  3. data/vendor/assets/javascripts/precompiled/development/core.js +39 -13
  4. data/vendor/assets/javascripts/precompiled/development/date.js +137 -152
  5. data/vendor/assets/javascripts/precompiled/development/date_ranges.js +22 -10
  6. data/vendor/assets/javascripts/precompiled/development/es5.js +1 -1
  7. data/vendor/assets/javascripts/precompiled/development/function.js +7 -5
  8. data/vendor/assets/javascripts/precompiled/development/object.js +2 -2
  9. data/vendor/assets/javascripts/precompiled/minified/array.js +16 -16
  10. data/vendor/assets/javascripts/precompiled/minified/core.js +9 -8
  11. data/vendor/assets/javascripts/precompiled/minified/date.js +41 -39
  12. data/vendor/assets/javascripts/precompiled/minified/date_locales.js +9 -9
  13. data/vendor/assets/javascripts/precompiled/minified/date_ranges.js +3 -3
  14. data/vendor/assets/javascripts/precompiled/minified/es5.js +8 -7
  15. data/vendor/assets/javascripts/precompiled/minified/function.js +4 -4
  16. data/vendor/assets/javascripts/precompiled/minified/inflections.js +7 -7
  17. data/vendor/assets/javascripts/precompiled/minified/language.js +9 -9
  18. data/vendor/assets/javascripts/precompiled/minified/number.js +5 -5
  19. data/vendor/assets/javascripts/precompiled/minified/object.js +6 -6
  20. data/vendor/assets/javascripts/precompiled/minified/regexp.js +2 -2
  21. data/vendor/assets/javascripts/precompiled/minified/string.js +12 -12
  22. data/vendor/assets/javascripts/sugar-development.js +259 -199
  23. data/vendor/assets/javascripts/sugar-full.js +132 -128
  24. data/vendor/assets/javascripts/sugar.js +107 -103
  25. metadata +4 -4
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Sugar Library v1.3
2
+ * Sugar Library v1.3.1
3
3
  *
4
4
  * Freely distributable and licensed under the MIT-style license.
5
5
  * Copyright (c) 2012 Andrew Plummer
@@ -24,7 +24,7 @@
24
24
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
25
25
  var definePropertySupport = object.defineProperty && object.defineProperties;
26
26
 
27
- // Class initializers and isClass type helpers
27
+ // Class initializers and class helpers
28
28
 
29
29
  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');
30
30
 
@@ -38,12 +38,12 @@
38
38
 
39
39
  function buildClassCheck(type) {
40
40
  return function(obj) {
41
- return isClass(obj, type);
41
+ return className(obj) === '[object '+type+']';
42
42
  }
43
43
  }
44
44
 
45
- function isClass(obj, str) {
46
- return object.prototype.toString.call(obj) === '[object '+str+']';
45
+ function className(obj) {
46
+ return object.prototype.toString.call(obj);
47
47
  }
48
48
 
49
49
  function initializeClasses() {
@@ -149,7 +149,9 @@
149
149
 
150
150
  function isObject(obj) {
151
151
  // === on the constructor is not safe across iframes
152
- return !!obj && isClass(obj, 'Object') && string(obj.constructor) === string(object);
152
+ // 'hasOwnProperty' ensures that the object also inherits
153
+ // from Object, which is false for DOMElements in IE.
154
+ return !!obj && className(obj) === '[object Object]' && 'hasOwnProperty' in obj;
153
155
  }
154
156
 
155
157
  function hasOwnProperty(obj, key) {
@@ -263,16 +265,20 @@
263
265
  // Used by Array#unique and Object.equal
264
266
 
265
267
  function stringify(thing, stack) {
266
- var value, klass, isObject, isArray, arr, i, key, type = typeof thing;
268
+ var type = typeof thing,
269
+ thingIsObject,
270
+ thingIsArray,
271
+ klass, value,
272
+ arr, key, i;
267
273
 
268
274
  // Return quickly if string to save cycles
269
275
  if(type === 'string') return thing;
270
276
 
271
- klass = object.prototype.toString.call(thing)
272
- isObject = klass === '[object Object]';
273
- isArray = klass === '[object Array]';
277
+ klass = object.prototype.toString.call(thing)
278
+ thingIsObject = isObject(thing);
279
+ thingIsArray = klass === '[object Array]';
274
280
 
275
- if(thing != null && isObject || isArray) {
281
+ if(thing != null && thingIsObject || thingIsArray) {
276
282
  // This method for checking for cyclic structures was egregiously stolen from
277
283
  // the ingenious method by @kitcambridge from the Underscore script:
278
284
  // https://github.com/documentcloud/underscore/issues/240
@@ -291,20 +297,40 @@
291
297
  }
292
298
  stack.push(thing);
293
299
  value = string(thing.constructor);
294
- arr = isArray ? thing : object.keys(thing).sort();
300
+ arr = thingIsArray ? thing : object.keys(thing).sort();
295
301
  for(i = 0; i < arr.length; i++) {
296
- key = isArray ? i : arr[i];
302
+ key = thingIsArray ? i : arr[i];
297
303
  value += key + stringify(thing[key], stack);
298
304
  }
299
305
  stack.pop();
300
306
  } else if(1 / thing === -Infinity) {
301
307
  value = '-0';
302
308
  } else {
303
- value = string(thing && thing.valueOf());
309
+ value = string(thing && thing.valueOf ? thing.valueOf() : thing);
304
310
  }
305
311
  return type + klass + value;
306
312
  }
307
313
 
314
+ function isEqual(a, b) {
315
+ if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
316
+ return stringify(a) === stringify(b);
317
+ } else {
318
+ return a === b;
319
+ }
320
+ }
321
+
322
+ function objectIsMatchedByValue(obj) {
323
+ var klass = className(obj);
324
+ return klass === '[object Date]' ||
325
+ klass === '[object Array]' ||
326
+ klass === '[object String]' ||
327
+ klass === '[object Number]' ||
328
+ klass === '[object RegExp]' ||
329
+ klass === '[object Boolean]' ||
330
+ klass === '[object Arguments]' ||
331
+ isObject(obj);
332
+ }
333
+
308
334
 
309
335
  // Used by Array#at and String#at
310
336
 
@@ -454,7 +480,7 @@
454
480
  *
455
481
  ***/
456
482
  'isArray': function(obj) {
457
- return isClass(obj, 'Array');
483
+ return isArray(obj);
458
484
  }
459
485
 
460
486
  });
@@ -780,7 +806,6 @@
780
806
 
781
807
 
782
808
 
783
-
784
809
  /***
785
810
  * @package Array
786
811
  * @dependency core
@@ -807,9 +832,9 @@
807
832
  result = false;
808
833
  }
809
834
  });
810
- return object.keys(match).length > 0 && result;
835
+ return result;
811
836
  } else {
812
- return stringify(el) === stringify(match);
837
+ return isEqual(el, match);
813
838
  }
814
839
  }
815
840
 
@@ -877,12 +902,10 @@
877
902
  }
878
903
 
879
904
  function arrayUnique(arr, map) {
880
- var result = [], o = {}, stringified, transformed;
905
+ var result = [], o = {}, transformed;
881
906
  arrayEach(arr, function(el, i) {
882
907
  transformed = map ? transformArgument(el, map, arr, [el, i, arr]) : el;
883
- stringified = stringify(transformed);
884
- if(!arrayObjectExists(o, stringified, el)) {
885
- o[stringified] = transformed;
908
+ if(!checkForElementInHashAndSet(o, transformed)) {
886
909
  result.push(el);
887
910
  }
888
911
  })
@@ -892,15 +915,16 @@
892
915
  function arrayIntersect(arr1, arr2, subtract) {
893
916
  var result = [], o = {};
894
917
  arr2.each(function(el) {
895
- o[stringify(el)] = el;
918
+ checkForElementInHashAndSet(o, el);
896
919
  });
897
920
  arr1.each(function(el) {
898
- var stringified = stringify(el), exists = arrayObjectExists(o, stringified, el);
921
+ var stringified = stringify(el),
922
+ isReference = !objectIsMatchedByValue(el);
899
923
  // Add the result to the array if:
900
924
  // 1. We're subtracting intersections or it doesn't already exist in the result and
901
925
  // 2. It exists in the compared array and we're adding, or it doesn't exist and we're removing.
902
- if(exists != subtract) {
903
- delete o[stringified];
926
+ if(elementExistsInHash(o, stringified, el, isReference) != subtract) {
927
+ discardElementFromHash(o, stringified, el, isReference);
904
928
  result.push(el);
905
929
  }
906
930
  });
@@ -929,10 +953,44 @@
929
953
  return result;
930
954
  }
931
955
 
932
- function arrayObjectExists(hash, stringified, obj) {
933
- return stringified in hash && (typeof obj !== 'function' || obj === hash[stringified]);
956
+ function elementExistsInHash(hash, key, element, isReference) {
957
+ var exists = key in hash;
958
+ if(isReference) {
959
+ if(!hash[key]) {
960
+ hash[key] = [];
961
+ }
962
+ exists = hash[key].indexOf(element) !== -1;
963
+ }
964
+ return exists;
934
965
  }
935
966
 
967
+ function checkForElementInHashAndSet(hash, element) {
968
+ var stringified = stringify(element),
969
+ isReference = !objectIsMatchedByValue(element),
970
+ exists = elementExistsInHash(hash, stringified, element, isReference);
971
+ if(isReference) {
972
+ hash[stringified].push(element);
973
+ } else {
974
+ hash[stringified] = element;
975
+ }
976
+ return exists;
977
+ }
978
+
979
+ function discardElementFromHash(hash, key, element, isReference) {
980
+ var arr, i = 0;
981
+ if(isReference) {
982
+ arr = hash[key];
983
+ while(i < arr.length) {
984
+ if(arr[i] === element) {
985
+ arr.splice(i, 1);
986
+ } else {
987
+ i += 1;
988
+ }
989
+ }
990
+ } else {
991
+ delete hash[key];
992
+ }
993
+ }
936
994
 
937
995
  // Support methods
938
996
 
@@ -1121,8 +1179,11 @@
1121
1179
  'create': function() {
1122
1180
  var result = []
1123
1181
  multiArgs(arguments, function(a) {
1124
- if(a && a.callee) a = multiArgs(a);
1125
- result = result.concat(a);
1182
+ if(isObjectPrimitive(a)) {
1183
+ result = result.concat(array.prototype.slice.call(a));
1184
+ } else {
1185
+ result.push(a);
1186
+ }
1126
1187
  });
1127
1188
  return result;
1128
1189
  }
@@ -2018,19 +2079,19 @@
2018
2079
  {
2019
2080
  token: 'f{1,4}|ms|milliseconds',
2020
2081
  format: function(d) {
2021
- return d.getMilliseconds();
2082
+ return callDateGet(d, 'Milliseconds');
2022
2083
  }
2023
2084
  },
2024
2085
  {
2025
2086
  token: 'ss?|seconds',
2026
2087
  format: function(d, len) {
2027
- return d.getSeconds();
2088
+ return callDateGet(d, 'Seconds');
2028
2089
  }
2029
2090
  },
2030
2091
  {
2031
2092
  token: 'mm?|minutes',
2032
2093
  format: function(d, len) {
2033
- return d.getMinutes();
2094
+ return callDateGet(d, 'Minutes');
2034
2095
  }
2035
2096
  },
2036
2097
  {
@@ -2042,45 +2103,48 @@
2042
2103
  {
2043
2104
  token: 'HH?|24hr',
2044
2105
  format: function(d) {
2045
- return d.getHours();
2106
+ return callDateGet(d, 'Hours');
2046
2107
  }
2047
2108
  },
2048
2109
  {
2049
2110
  token: 'dd?|date|day',
2050
2111
  format: function(d) {
2051
- return d.getDate();
2112
+ return callDateGet(d, 'Date');
2052
2113
  }
2053
2114
  },
2054
2115
  {
2055
2116
  token: 'dow|weekday',
2056
2117
  word: true,
2057
2118
  format: function(d, loc, n, t) {
2058
- return loc['weekdays'][d.getDay() + (n - 1) * 7];
2119
+ var dow = callDateGet(d, 'Day');
2120
+ return loc['weekdays'][dow + (n - 1) * 7];
2059
2121
  }
2060
2122
  },
2061
2123
  {
2062
2124
  token: 'MM?',
2063
2125
  format: function(d) {
2064
- return d.getMonth() + 1;
2126
+ return callDateGet(d, 'Month') + 1;
2065
2127
  }
2066
2128
  },
2067
2129
  {
2068
2130
  token: 'mon|month',
2069
2131
  word: true,
2070
2132
  format: function(d, loc, n, len) {
2071
- return loc['months'][d.getMonth() + (n - 1) * 12];
2133
+ var month = callDateGet(d, 'Month');
2134
+ return loc['months'][month + (n - 1) * 12];
2072
2135
  }
2073
2136
  },
2074
2137
  {
2075
2138
  token: 'y{2,4}|year',
2076
2139
  format: function(d) {
2077
- return d.getFullYear();
2140
+ return callDateGet(d, 'FullYear');
2078
2141
  }
2079
2142
  },
2080
2143
  {
2081
2144
  token: '[Tt]{1,2}',
2082
2145
  format: function(d, loc, n, format) {
2083
- var str = loc['ampm'][floor(d.getHours() / 12)];
2146
+ var hours = callDateGet(d, 'Hours');
2147
+ var str = loc['ampm'][floor(hours / 12)];
2084
2148
  if(format.length === 1) str = str.slice(0,1);
2085
2149
  if(format.slice(0,1) === 'T') str = str.toUpperCase();
2086
2150
  return str;
@@ -2108,8 +2172,8 @@
2108
2172
  {
2109
2173
  token: 'ord',
2110
2174
  format: function(d) {
2111
- var d = d.getDate();
2112
- return d + getOrdinalizedSuffix(d);
2175
+ var date = callDateGet(d, 'Date');
2176
+ return date + getOrdinalizedSuffix(date);
2113
2177
  }
2114
2178
  }
2115
2179
  ];
@@ -2118,6 +2182,7 @@
2118
2182
  {
2119
2183
  unit: 'year',
2120
2184
  method: 'FullYear',
2185
+ ambiguous: true,
2121
2186
  multiplier: function(d) {
2122
2187
  var adjust = d ? (d.isLeapYear() ? 1 : 0) : 0.25;
2123
2188
  return (365 + adjust) * 24 * 60 * 60 * 1000;
@@ -2247,6 +2312,10 @@
2247
2312
  return code === 'en' || code === 'en-US' ? true : this['variant'];
2248
2313
  },
2249
2314
 
2315
+ matchAM: function(str) {
2316
+ return str === this['ampm'][0];
2317
+ },
2318
+
2250
2319
  matchPM: function(str) {
2251
2320
  return str === this['ampm'][1];
2252
2321
  },
@@ -2341,7 +2410,7 @@
2341
2410
  }
2342
2411
 
2343
2412
  function setLocalization(localeCode, set) {
2344
- var loc;
2413
+ var loc, canAbbreviate;
2345
2414
 
2346
2415
  function initializeField(name) {
2347
2416
  var val = loc[name];
@@ -2365,16 +2434,15 @@
2365
2434
 
2366
2435
  function setArray(name, abbreviate, multiple) {
2367
2436
  var arr = [];
2368
- if(!loc[name]) return;
2369
- loc[name].forEach(function(el, i) {
2370
- eachAlternate(el, function(str, j) {
2371
- arr[j * multiple + i] = str.toLowerCase();
2437
+ loc[name].forEach(function(full, i) {
2438
+ if(abbreviate) {
2439
+ full += '+' + full.slice(0,3);
2440
+ }
2441
+ eachAlternate(full, function(day, j) {
2442
+ arr[j * multiple + i] = day.toLowerCase();
2372
2443
  });
2373
2444
  });
2374
- if(abbreviate) arr = arr.concat(loc[name].map(function(str) {
2375
- return str.slice(0,3).toLowerCase();
2376
- }));
2377
- return loc[name] = arr;
2445
+ loc[name] = arr;
2378
2446
  }
2379
2447
 
2380
2448
  function getDigit(start, stop, allowNumbers) {
@@ -2410,8 +2478,10 @@
2410
2478
  initializeField('modifiers');
2411
2479
  'months,weekdays,units,numbers,articles,optionals,timeMarker,ampm,timeSuffixes,dateParse,timeParse'.split(',').forEach(initializeField);
2412
2480
 
2413
- setArray('months', true, 12);
2414
- setArray('weekdays', true, 7);
2481
+ canAbbreviate = !loc['monthSuffix'];
2482
+
2483
+ setArray('months', canAbbreviate, 12);
2484
+ setArray('weekdays', canAbbreviate, 7);
2415
2485
  setArray('units', false, 8);
2416
2486
  setArray('numbers', false, 10);
2417
2487
 
@@ -2497,10 +2567,12 @@
2497
2567
  function getDateParamsFromString(str, num) {
2498
2568
  var params = {};
2499
2569
  match = str.match(/^(\d+)?\s?(\w+?)s?$/i);
2500
- if(isUndefined(num)) {
2501
- num = parseInt(match[1]) || 1;
2570
+ if(match) {
2571
+ if(isUndefined(num)) {
2572
+ num = parseInt(match[1]) || 1;
2573
+ }
2574
+ params[match[2].toLowerCase()] = num;
2502
2575
  }
2503
- params[match[2].toLowerCase()] = num;
2504
2576
  return params;
2505
2577
  }
2506
2578
 
@@ -2546,14 +2618,17 @@
2546
2618
  });
2547
2619
  }
2548
2620
 
2549
- function getExtendedDate(f, localeCode, prefer) {
2621
+ function getExtendedDate(f, localeCode, prefer, forceUTC) {
2550
2622
  var d = new date(), relative = false, baseLocalization, loc, format, set, unit, weekday, num, tmp, after;
2623
+
2624
+ d.utc(forceUTC);
2625
+
2551
2626
  if(isDate(f)) {
2552
2627
  d = f.clone();
2553
2628
  } else if(isNumber(f)) {
2554
2629
  d = new date(f);
2555
2630
  } else if(isObject(f)) {
2556
- d = new date().set(f, true);
2631
+ d.set(f, true);
2557
2632
  set = f;
2558
2633
  } else if(isString(f)) {
2559
2634
 
@@ -2571,6 +2646,11 @@
2571
2646
  format = dif;
2572
2647
  loc = format.locale;
2573
2648
  set = getFormatMatch(match, format.to, loc);
2649
+
2650
+ if(set['utc']) {
2651
+ d.utc();
2652
+ }
2653
+
2574
2654
  loc.cachedFormat = format;
2575
2655
 
2576
2656
  if(set.timestamp) {
@@ -2619,7 +2699,8 @@
2619
2699
  // to be set after the actual set because it requires overriding the "prefer" argument which
2620
2700
  // could unintentionally send the year into the future, past, etc.
2621
2701
  after = function() {
2622
- updateDate(d, { 'weekday': weekday + (7 * (set['num'] - 1)) }, false, false, false, 1);
2702
+ var w = d.getWeekday();
2703
+ d.setWeekday((7 * (set['num'] - 1)) + (w > weekday ? weekday + 7 : weekday));
2623
2704
  }
2624
2705
  set['day'] = 1;
2625
2706
  } else {
@@ -2634,11 +2715,13 @@
2634
2715
  // If the time is 1pm-11pm advance the time by 12 hours.
2635
2716
  if(loc.matchPM(set['ampm']) && set['hour'] < 12) {
2636
2717
  set['hour'] += 12;
2718
+ } else if(loc.matchAM(set['ampm']) && set['hour'] === 12) {
2719
+ set['hour'] = 0;
2637
2720
  }
2638
2721
 
2639
2722
  // Adjust for timezone offset
2640
2723
  if('offset_hours' in set || 'offset_minutes' in set) {
2641
- set['utc'] = true;
2724
+ d.utc();
2642
2725
  set['offset_minutes'] = set['offset_minutes'] || 0;
2643
2726
  set['offset_minutes'] += set['offset_hours'] * 60;
2644
2727
  if(set['offset_sign'] === '-') {
@@ -2707,12 +2790,12 @@
2707
2790
  } else if(relative) {
2708
2791
  d.advance(set);
2709
2792
  } else {
2710
- if(set['utc']) {
2793
+ if(d._utc) {
2711
2794
  // UTC times can traverse into other days or even months,
2712
2795
  // so preemtively reset the time here to prevent this.
2713
2796
  d.reset();
2714
2797
  }
2715
- updateDate(d, set, true, set['utc'], false, prefer);
2798
+ updateDate(d, set, true, false, prefer);
2716
2799
  }
2717
2800
 
2718
2801
  // If there is an "edge" it needs to be set after the
@@ -2744,17 +2827,18 @@
2744
2827
 
2745
2828
  // If the year is two digits, add the most appropriate century prefix.
2746
2829
  function getYearFromAbbreviation(year) {
2747
- return round(new date().getFullYear() / 100) * 100 - round(year / 100) * 100 + year;
2830
+ return round(callDateGet(new date(), 'FullYear') / 100) * 100 - round(year / 100) * 100 + year;
2748
2831
  }
2749
2832
 
2750
- function getShortHour(d, utc) {
2751
- var hours = callDateMethod(d, 'get', utc, 'Hours');
2833
+ function getShortHour(d) {
2834
+ var hours = callDateGet(d, 'Hours');
2752
2835
  return hours === 0 ? 12 : hours - (floor(hours / 13) * 12);
2753
2836
  }
2754
2837
 
2755
2838
  // weeksSince won't work here as the result needs to be floored, not rounded.
2756
2839
  function getWeekNumber(date) {
2757
- var dow = date.getDay() || 7;
2840
+ date = date.clone();
2841
+ var dow = callDateGet(date, 'Day') || 7;
2758
2842
  date.addDays(4 - dow).reset();
2759
2843
  return 1 + floor(date.daysSince(date.clone().beginningOfYear()) / 7);
2760
2844
  }
@@ -2815,8 +2899,8 @@
2815
2899
 
2816
2900
  // Date comparison helpers
2817
2901
 
2818
- function compareDate(d, find, buffer) {
2819
- var p = getExtendedDate(find), accuracy = 0, loBuffer = 0, hiBuffer = 0, override, capitalized;
2902
+ function compareDate(d, find, buffer, forceUTC) {
2903
+ var p = getExtendedDate(find, null, null, forceUTC), accuracy = 0, loBuffer = 0, hiBuffer = 0, override, capitalized;
2820
2904
  if(buffer > 0) {
2821
2905
  loBuffer = hiBuffer = buffer;
2822
2906
  override = true;
@@ -2845,12 +2929,11 @@
2845
2929
  var t = d.getTime();
2846
2930
  var min = p.date.getTime();
2847
2931
  var max = max || (min + accuracy);
2848
- // Offset any shift that may occur as a result of DST traversal.
2849
2932
  return t >= (min - loBuffer) && t <= (max + hiBuffer);
2850
2933
  }
2851
2934
 
2852
- function updateDate(d, params, reset, utc, advance, prefer) {
2853
- var weekday;
2935
+ function updateDate(d, params, reset, advance, prefer) {
2936
+ var weekday, specificityIndex;
2854
2937
 
2855
2938
  function getParam(key) {
2856
2939
  return isDefined(params[key]) ? params[key] : params[key + 's'];
@@ -2860,8 +2943,9 @@
2860
2943
  return isDefined(getParam(key));
2861
2944
  }
2862
2945
 
2863
- function canDisambiguate(u, higherUnit) {
2864
- return prefer && u.ambiguous && !paramExists(higherUnit.unit);
2946
+ function canDisambiguate() {
2947
+ var now = new date;
2948
+ return (prefer === -1 && d > now) || (prefer === 1 && d < now);
2865
2949
  }
2866
2950
 
2867
2951
  if(isNumber(params) && advance) {
@@ -2885,10 +2969,11 @@
2885
2969
  var isDay = u.unit === 'day';
2886
2970
  if(paramExists(u.unit) || (isDay && paramExists('weekday'))) {
2887
2971
  params.specificity = u.unit;
2972
+ specificityIndex = +i;
2888
2973
  return false;
2889
2974
  } else if(reset && u.unit !== 'week' && (!isDay || !paramExists('week'))) {
2890
2975
  // Days are relative to months, not weeks, so don't reset if a week exists.
2891
- callDateMethod(d, 'set', utc, u.method, (isDay ? 1 : 0));
2976
+ callDateSet(d, u.method, (isDay ? 1 : 0));
2892
2977
  }
2893
2978
  });
2894
2979
 
@@ -2897,23 +2982,12 @@
2897
2982
  var unit = u.unit, method = u.method, higherUnit = DateUnits[i - 1], value;
2898
2983
  value = getParam(unit)
2899
2984
  if(isUndefined(value)) return;
2900
- if(canDisambiguate(u, higherUnit)) {
2901
- // Formats like "June" have an ambiguous year. If no preference is stated, this
2902
- // is fine as "June of this year", however in a future context, this would mean
2903
- // "the next June", which may be either this year or next year. If we have an
2904
- // ambiguity *and* a preference for resolving it, then advance or rewind the
2905
- // higher order as necessary. Note that weekdays are handled differently below.
2906
- var current = callDateMethod(new date, 'get', utc, u.method);
2907
- if(current >= value === (prefer === 1)) {
2908
- d[higherUnit.addMethod](prefer);
2909
- }
2910
- }
2911
2985
  if(advance) {
2912
2986
  if(unit === 'week') {
2913
2987
  value = (params['day'] || 0) + (value * 7);
2914
2988
  method = 'Date';
2915
2989
  }
2916
- value = (value * advance) + callDateMethod(d, 'get', false, method);
2990
+ value = (value * advance) + callDateGet(d, method);
2917
2991
  } else if(unit === 'month' && paramExists('day')) {
2918
2992
  // When setting the month, there is a chance that we will traverse into a new month.
2919
2993
  // This happens in DST shifts, for example June 1st DST jumping to January 1st
@@ -2929,9 +3003,9 @@
2929
3003
  // TL;DR This method avoids the edges of a month IF not advancing and the date is going
2930
3004
  // to be set anyway, while checkMonthTraversal resets the date to the last day if advancing.
2931
3005
  //
2932
- d.setDate(15);
3006
+ callDateSet(d, 'Date', 15);
2933
3007
  }
2934
- callDateMethod(d, 'set', utc, method, value);
3008
+ callDateSet(d, method, value);
2935
3009
  if(advance && unit === 'month') {
2936
3010
  checkMonthTraversal(d, value);
2937
3011
  }
@@ -2941,24 +3015,27 @@
2941
3015
  // to reflect the updated date so that resetting works properly.
2942
3016
  if(!advance && !paramExists('day') && paramExists('weekday')) {
2943
3017
  var weekday = getParam('weekday'), isAhead, futurePreferred;
2944
- if(isDefined(prefer)) {
2945
- // If there is a preference as to whether this weekday is in the future,
2946
- // then add an offset as needed. NOTE: Was previously doing something much
2947
- // more one-liner-hipster here, but it made Opera choke (order of operations
2948
- // bug??) ... better to be more explicit here anyway.
2949
- isAhead = callDateMethod(d, 'get', utc, 'Day') - (weekday % 7) >= 0;
2950
- futurePreferred = prefer === 1;
2951
- if(isAhead === futurePreferred) {
2952
- weekday += prefer * 7;
2953
- }
2954
- }
2955
- callDateMethod(d, 'set', utc, 'Weekday', weekday)
3018
+ d.setWeekday(weekday);
3019
+ }
3020
+
3021
+ if(canDisambiguate()) {
3022
+ iterateOverObject(DateUnitsReversed.slice(specificityIndex + 1), function(i,u) {
3023
+ var ambiguous = u.ambiguous || (u.unit === 'week' && paramExists('weekday'));
3024
+ if(ambiguous && !paramExists(u.unit)) {
3025
+ d[u.addMethod](prefer);
3026
+ return false;
3027
+ }
3028
+ });
2956
3029
  }
2957
3030
  return d;
2958
3031
  }
2959
3032
 
2960
- function callDateMethod(d, prefix, utc, method, value) {
2961
- return d[prefix + (utc ? 'UTC' : '') + method](value);
3033
+ function callDateGet(d, method) {
3034
+ return d['get' + (d._utc ? 'UTC' : '') + method]();
3035
+ }
3036
+
3037
+ function callDateSet(d, method, value) {
3038
+ return d['set' + (d._utc ? 'UTC' : '') + method](value);
2962
3039
  }
2963
3040
 
2964
3041
  // The ISO format allows times strung together without a demarcating ":", so make sure
@@ -2993,20 +3070,22 @@
2993
3070
 
2994
3071
  function checkMonthTraversal(date, targetMonth) {
2995
3072
  if(targetMonth < 0) targetMonth += 12;
2996
- if(targetMonth % 12 != date.getMonth()) {
2997
- date.setDate(0);
3073
+ if(targetMonth % 12 != callDateGet(date, 'Month')) {
3074
+ callDateSet(date, 'Date', 0);
2998
3075
  }
2999
3076
  }
3000
3077
 
3001
3078
  function createDate(args, prefer) {
3002
- var f;
3079
+ var f, localeCode, forceUTC;
3003
3080
  if(isNumber(args[1])) {
3004
3081
  // If the second argument is a number, then we have an enumerated constructor type as in "new Date(2003, 2, 12);"
3005
3082
  f = collectDateArguments(args)[0];
3006
3083
  } else {
3007
- f = args[0];
3084
+ f = args[0];
3085
+ localeCode = args[1];
3086
+ forceUTC = args[2];
3008
3087
  }
3009
- return getExtendedDate(f, args[1], prefer).date;
3088
+ return getExtendedDate(f, localeCode, prefer, forceUTC).date;
3010
3089
  }
3011
3090
 
3012
3091
  function buildDateUnits() {
@@ -3243,9 +3322,9 @@
3243
3322
  methods['beginningOf' + caps] = function() {
3244
3323
  var set = {};
3245
3324
  switch(unit) {
3246
- case 'year': set['year'] = this.getFullYear(); break;
3247
- case 'month': set['month'] = this.getMonth(); break;
3248
- case 'day': set['day'] = this.getDate(); break;
3325
+ case 'year': set['year'] = callDateGet(this, 'FullYear'); break;
3326
+ case 'month': set['month'] = callDateGet(this, 'Month'); break;
3327
+ case 'day': set['day'] = callDateGet(this, 'Date'); break;
3249
3328
  case 'week': set['weekday'] = 0; break;
3250
3329
  }
3251
3330
  return this.set(set, true);
@@ -3358,8 +3437,8 @@
3358
3437
  var weekdays = English['weekdays'].slice(0,7);
3359
3438
  var months = English['months'].slice(0,12);
3360
3439
  extendSimilar(date, true, false, special.concat(weekdays).concat(months), function(methods, name) {
3361
- methods['is'+ simpleCapitalize(name)] = function() {
3362
- return this.is(name);
3440
+ methods['is'+ simpleCapitalize(name)] = function(utc) {
3441
+ return this.is(name, 0, utc);
3363
3442
  };
3364
3443
  });
3365
3444
  }
@@ -3387,10 +3466,10 @@
3387
3466
  date.extend({
3388
3467
 
3389
3468
  /***
3390
- * @method Date.create(<d>, [locale] = currentLocale)
3469
+ * @method Date.create(<d>, [locale] = currentLocale, [utc] = false)
3391
3470
  * @returns Date
3392
3471
  * @short Alternate Date constructor which understands many different text formats, a timestamp, or another date.
3393
- * @extra If no argument is given, date is assumed to be now. %Date.create% additionally can accept enumerated parameters as with the standard date constructor. [locale] can be passed to specify the locale that the date is in. When unspecified, the current locale (default is English) is assumed. For more information, see @date_format.
3472
+ * @extra If no argument is given, date is assumed to be now. %Date.create% additionally can accept enumerated parameters as with the standard date constructor. [locale] can be passed to specify the locale that the date is in. When unspecified, the current locale (default is English) is assumed. [utc] indicates a utc-based date. For more information, see @date_format.
3394
3473
  * @example
3395
3474
  *
3396
3475
  * Date.create('July') -> July of this year
@@ -3409,7 +3488,7 @@
3409
3488
  },
3410
3489
 
3411
3490
  /***
3412
- * @method Date.past(<d>, [locale] = currentLocale)
3491
+ * @method Date.past(<d>, [locale] = currentLocale, [utc] = false)
3413
3492
  * @returns Date
3414
3493
  * @short Alternate form of %Date.create% with any ambiguity assumed to be the past.
3415
3494
  * @extra For example %"Sunday"% can be either "the Sunday coming up" or "the Sunday last" depending on context. Note that dates explicitly in the future ("next Sunday") will remain in the future. This method simply provides a hint when ambiguity exists.
@@ -3424,7 +3503,7 @@
3424
3503
  },
3425
3504
 
3426
3505
  /***
3427
- * @method Date.future(<d>, [locale] = currentLocale)
3506
+ * @method Date.future(<d>, [locale] = currentLocale, [utc] = false)
3428
3507
  * @returns Date
3429
3508
  * @short Alternate form of %Date.create% with any ambiguity assumed to be the future.
3430
3509
  * @extra For example %"Sunday"% can be either "the Sunday coming up" or "the Sunday last" depending on context. Note that dates explicitly in the past ("last Sunday") will remain in the past. This method simply provides a hint when ambiguity exists.
@@ -3497,10 +3576,7 @@
3497
3576
  * @method set(<set>, [reset] = false)
3498
3577
  * @returns Date
3499
3578
  * @short Sets the date object.
3500
- * @extra This method can accept multiple formats including a single number as a timestamp, an object, or enumerated parameters (as with the Date constructor). If [reset] is %true%, any units more specific than those passed will be reset. %setUTC% will set the date according to universal time.
3501
- *
3502
- * @set
3503
- * setUTC
3579
+ * @extra This method can accept multiple formats including a single number as a timestamp, an object, or enumerated parameters (as with the Date constructor). If [reset] is %true%, any units more specific than those passed will be reset.
3504
3580
  *
3505
3581
  * @example
3506
3582
  *
@@ -3515,19 +3591,10 @@
3515
3591
  return updateDate(this, args[0], args[1])
3516
3592
  },
3517
3593
 
3518
- 'setUTC': function() {
3519
- var args = collectDateArguments(arguments);
3520
- return updateDate(this, args[0], args[1], true)
3521
- },
3522
-
3523
3594
  /***
3524
3595
  * @method setWeekday()
3525
3596
  * @returns Nothing
3526
3597
  * @short Sets the weekday of the date.
3527
- * @extra %setUTCWeekday% sets according to universal time.
3528
- *
3529
- * @set
3530
- * setUTCWeekday
3531
3598
  *
3532
3599
  * @example
3533
3600
  *
@@ -3537,22 +3604,13 @@
3537
3604
  ***/
3538
3605
  'setWeekday': function(dow) {
3539
3606
  if(isUndefined(dow)) return;
3540
- this.setDate(this.getDate() + dow - this.getDay());
3541
- },
3542
-
3543
- 'setUTCWeekday': function(dow) {
3544
- if(isUndefined(dow)) return;
3545
- this.setDate(this.getUTCDate() + dow - this.getDay());
3607
+ return callDateSet(this, 'Date', callDateGet(this, 'Date') + dow - callDateGet(this, 'Day'));
3546
3608
  },
3547
3609
 
3548
3610
  /***
3549
3611
  * @method setWeek()
3550
3612
  * @returns Nothing
3551
3613
  * @short Sets the week (of the year).
3552
- * @extra %setUTCWeek% sets according to universal time.
3553
- *
3554
- * @set
3555
- * setUTCWeek
3556
3614
  *
3557
3615
  * @example
3558
3616
  *
@@ -3561,41 +3619,27 @@
3561
3619
  ***/
3562
3620
  'setWeek': function(week) {
3563
3621
  if(isUndefined(week)) return;
3564
- var date = this.getDate();
3565
- this.setMonth(0);
3566
- this.setDate((week * 7) + 1);
3567
- },
3568
-
3569
- 'setUTCWeek': function(week) {
3570
- if(isUndefined(week)) return;
3571
- var date = this.getUTCDate();
3572
- this.setMonth(0);
3573
- this.setUTCDate((week * 7) + 1);
3622
+ var date = callDateGet(this, 'Date');
3623
+ callDateSet(this, 'Month', 0);
3624
+ callDateSet(this, 'Date', (week * 7) + 1);
3625
+ return this.getTime();
3574
3626
  },
3575
3627
 
3576
3628
  /***
3577
3629
  * @method getWeek()
3578
3630
  * @returns Number
3579
3631
  * @short Gets the date's week (of the year).
3580
- * @extra %getUTCWeek% gets the week according to universal time.
3581
- *
3582
- * @set
3583
- * getUTCWeek
3632
+ * @extra If %utc% is set on the date, the week will be according to UTC time.
3584
3633
  *
3585
3634
  * @example
3586
3635
  *
3587
3636
  * new Date().getWeek() -> today's week of the year
3588
- * new Date().getUTCWeek() -> today's week of the year
3589
3637
  *
3590
3638
  ***/
3591
3639
  'getWeek': function() {
3592
3640
  return getWeekNumber(this);
3593
3641
  },
3594
3642
 
3595
- 'getUTCWeek': function() {
3596
- return getWeekNumber(this.toUTC());
3597
- },
3598
-
3599
3643
  /***
3600
3644
  * @method getUTCOffset([iso])
3601
3645
  * @returns String
@@ -3607,27 +3651,26 @@
3607
3651
  *
3608
3652
  ***/
3609
3653
  'getUTCOffset': function(iso) {
3610
- var offset = this.utc ? 0 : this.getTimezoneOffset();
3654
+ var offset = this._utc ? 0 : this.getTimezoneOffset();
3611
3655
  var colon = iso === true ? ':' : '';
3612
3656
  if(!offset && iso) return 'Z';
3613
3657
  return padNumber(round(-offset / 60), 2, true) + colon + padNumber(offset % 60, 2);
3614
3658
  },
3615
3659
 
3616
3660
  /***
3617
- * @method toUTC()
3661
+ * @method utc([on] = true)
3618
3662
  * @returns Date
3619
- * @short Converts the date to UTC time, effectively subtracting the timezone offset.
3620
- * @extra Note here that the method %getTimezoneOffset% will still show an offset even after this method is called, as this method effectively just rewinds the date. %format% however, will correctly set the %{tz}% (timezone) token as UTC once this method has been called on the date, and %isUTC% will return %true%. Once a date is set to UTC the only way to unset is the %clone% method.
3663
+ * @short Sets the internal utc flag for the date. When on, UTC-based methods will be called internally.
3664
+ * @extra For more see @date_format.
3621
3665
  * @example
3622
3666
  *
3623
- * new Date().toUTC() -> current time in UTC
3667
+ * new Date().utc(true)
3668
+ * new Date().utc(false)
3624
3669
  *
3625
3670
  ***/
3626
- 'toUTC': function() {
3627
- if(this.utc) return this;
3628
- var d = this.clone().addMinutes(this.getTimezoneOffset());
3629
- d.utc = true;
3630
- return d;
3671
+ 'utc': function(set) {
3672
+ this._utc = set === true || arguments.length === 0;
3673
+ return this;
3631
3674
  },
3632
3675
 
3633
3676
  /***
@@ -3642,7 +3685,7 @@
3642
3685
  *
3643
3686
  ***/
3644
3687
  'isUTC': function() {
3645
- return this.utc || this.getTimezoneOffset() === 0;
3688
+ return !!this._utc || this.getTimezoneOffset() === 0;
3646
3689
  },
3647
3690
 
3648
3691
  /***
@@ -3660,7 +3703,7 @@
3660
3703
  ***/
3661
3704
  'advance': function() {
3662
3705
  var args = collectDateArguments(arguments, true);
3663
- return updateDate(this, args[0], args[1], false, 1);
3706
+ return updateDate(this, args[0], args[1], 1);
3664
3707
  },
3665
3708
 
3666
3709
  /***
@@ -3677,7 +3720,7 @@
3677
3720
  ***/
3678
3721
  'rewind': function() {
3679
3722
  var args = collectDateArguments(arguments, true);
3680
- return updateDate(this, args[0], args[1], false, -1);
3723
+ return updateDate(this, args[0], args[1], -1);
3681
3724
  },
3682
3725
 
3683
3726
  /***
@@ -3705,7 +3748,7 @@
3705
3748
  * new Date().isAfter('yesterday') -> true
3706
3749
  *
3707
3750
  ***/
3708
- 'isAfter': function(d, margin) {
3751
+ 'isAfter': function(d, margin, utc) {
3709
3752
  return this.getTime() > date.create(d).getTime() - (margin || 0);
3710
3753
  },
3711
3754
 
@@ -3755,7 +3798,7 @@
3755
3798
  *
3756
3799
  ***/
3757
3800
  'isLeapYear': function() {
3758
- var year = this.getFullYear();
3801
+ var year = callDateGet(this, 'FullYear');
3759
3802
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
3760
3803
  },
3761
3804
 
@@ -3770,7 +3813,7 @@
3770
3813
  *
3771
3814
  ***/
3772
3815
  'daysInMonth': function() {
3773
- return 32 - new date(this.getFullYear(), this.getMonth(), 32).getDate();
3816
+ return 32 - callDateGet(new date(callDateGet(this, 'FullYear'), callDateGet(this, 'Month'), 32), 'Date');
3774
3817
  },
3775
3818
 
3776
3819
  /***
@@ -3840,21 +3883,22 @@
3840
3883
  * Date.create().is(new Date(1776, 6, 4)) -> false
3841
3884
  *
3842
3885
  ***/
3843
- 'is': function(d, margin) {
3844
- var tmp;
3886
+ 'is': function(d, margin, utc) {
3887
+ var tmp, comp;
3845
3888
  if(!this.isValid()) return;
3846
3889
  if(isString(d)) {
3847
3890
  d = d.trim().toLowerCase();
3891
+ comp = this.clone().utc(utc);
3848
3892
  switch(true) {
3849
3893
  case d === 'future': return this.getTime() > new date().getTime();
3850
3894
  case d === 'past': return this.getTime() < new date().getTime();
3851
- case d === 'weekday': return this.getDay() > 0 && this.getDay() < 6;
3852
- case d === 'weekend': return this.getDay() === 0 || this.getDay() === 6;
3853
- case (tmp = English['weekdays'].indexOf(d) % 7) > -1: return this.getDay() === tmp;
3854
- case (tmp = English['months'].indexOf(d) % 12) > -1: return this.getMonth() === tmp;
3895
+ case d === 'weekday': return callDateGet(comp, 'Day') > 0 && callDateGet(comp, 'Day') < 6;
3896
+ case d === 'weekend': return callDateGet(comp, 'Day') === 0 || callDateGet(comp, 'Day') === 6;
3897
+ case (tmp = English['weekdays'].indexOf(d) % 7) > -1: return callDateGet(comp, 'Day') === tmp;
3898
+ case (tmp = English['months'].indexOf(d) % 12) > -1: return callDateGet(comp, 'Month') === tmp;
3855
3899
  }
3856
3900
  }
3857
- return compareDate(this, d, margin);
3901
+ return compareDate(this, d, margin, utc);
3858
3902
  },
3859
3903
 
3860
3904
  /***
@@ -3888,7 +3932,9 @@
3888
3932
  *
3889
3933
  ***/
3890
3934
  'clone': function() {
3891
- return new date(this.getTime());
3935
+ var d = new date(this.getTime());
3936
+ d._utc = this._utc;
3937
+ return d;
3892
3938
  }
3893
3939
 
3894
3940
  });
@@ -4257,17 +4303,29 @@
4257
4303
  *
4258
4304
  ***/
4259
4305
  'every': function(increment, fn) {
4260
- var current = this.start.clone(), result = [], index = 0, params;
4306
+ var current = this.start.clone(), result = [], index = 0, params, isDay;
4261
4307
  if(isString(increment)) {
4262
4308
  current.advance(getDateParamsFromString(increment, 0), true);
4263
4309
  params = getDateParamsFromString(increment);
4310
+ isDay = increment.toLowerCase() === 'day';
4264
4311
  } else {
4265
4312
  params = { 'milliseconds': increment };
4266
4313
  }
4267
4314
  while(current <= this.end) {
4268
4315
  result.push(current);
4269
4316
  if(fn) fn(current, index);
4270
- current = current.clone().advance(params, true);
4317
+ if(isDay && callDateGet(current, 'Hours') === 23) {
4318
+ // When DST traversal happens at 00:00 hours, the time is effectively
4319
+ // pushed back to 23:00, meaning 1) 00:00 for that day does not exist,
4320
+ // and 2) there is no difference between 23:00 and 00:00, as you are
4321
+ // "jumping" around in time. Hours here will be reset before the date
4322
+ // is advanced and the date will never in fact advance, so set the hours
4323
+ // directly ahead to the next day to avoid this problem.
4324
+ current = current.clone();
4325
+ callDateSet(current, 'Hours', 48);
4326
+ } else {
4327
+ current = current.clone().advance(params, true);
4328
+ }
4271
4329
  index++;
4272
4330
  }
4273
4331
  return result;
@@ -4313,14 +4371,14 @@
4313
4371
  * @short Increments through the date range for each [unit], calling [fn] if it is passed. Returns an array of each increment visited.
4314
4372
  *
4315
4373
  * @set
4316
- * eachMillisecond()
4317
- * eachSecond()
4318
- * eachMinute()
4319
- * eachHour()
4320
- * eachDay()
4321
- * eachWeek()
4322
- * eachMonth()
4323
- * eachYear()
4374
+ * eachMillisecond
4375
+ * eachSecond
4376
+ * eachMinute
4377
+ * eachHour
4378
+ * eachDay
4379
+ * eachWeek
4380
+ * eachMonth
4381
+ * eachYear
4324
4382
  *
4325
4383
  * @example
4326
4384
  *
@@ -4361,13 +4419,14 @@
4361
4419
  ***/
4362
4420
 
4363
4421
  function setDelay(fn, ms, after, scope, args) {
4422
+ var index;
4364
4423
  if(!fn.timers) fn.timers = [];
4365
4424
  if(!isNumber(ms)) ms = 0;
4366
4425
  fn.timers.push(setTimeout(function(){
4367
4426
  fn.timers.splice(index, 1);
4368
4427
  after.apply(scope, args || []);
4369
4428
  }, ms));
4370
- var index = fn.timers.length;
4429
+ index = fn.timers.length;
4371
4430
  }
4372
4431
 
4373
4432
  extend(Function, true, false, {
@@ -4468,10 +4527,11 @@
4468
4527
  ***/
4469
4528
  'debounce': function(ms) {
4470
4529
  var fn = this;
4471
- return function() {
4472
- fn.cancel();
4473
- setDelay(fn, ms, fn, this, arguments);
4474
- }
4530
+ function debounced() {
4531
+ debounced.cancel();
4532
+ setDelay(debounced, ms, fn, this, arguments);
4533
+ };
4534
+ return debounced;
4475
4535
  },
4476
4536
 
4477
4537
  /***
@@ -5068,7 +5128,7 @@
5068
5128
  var method = 'is' + name;
5069
5129
  ObjectTypeMethods.push(method);
5070
5130
  methods[method] = function(obj) {
5071
- return isClass(obj, name);
5131
+ return className(obj) === '[object '+name+']';
5072
5132
  }
5073
5133
  });
5074
5134
  }
@@ -5163,7 +5223,7 @@
5163
5223
  *
5164
5224
  ***/
5165
5225
  'equal': function(a, b) {
5166
- return stringify(a) === stringify(b);
5226
+ return isEqual(a, b);
5167
5227
  },
5168
5228
 
5169
5229
  /***