Skip to content

Commit dee3879

Browse files
committed
Date: Make $.date() a constructor function. Move methods to prototype.
1 parent 0cd4989 commit dee3879

File tree

2 files changed

+173
-156
lines changed

2 files changed

+173
-156
lines changed

external/date.js

Lines changed: 169 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -20,168 +20,185 @@ var weekdays = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ],
2020
Globalize.locale( "en" );
2121

2222
$.date = function( date, globalFormat ) {
23-
//TODO: Need to refactor $.date to be a constructor, move the methods to a prototype.
23+
if ( !( this instanceof $.date ) ) {
24+
return new $.date( date, globalFormat );
25+
}
2426
if ( typeof date === "string" && date.length ) {
25-
date = Globalize.parseDate( date, globalFormat );
27+
this.dateObject = Globalize.parseDate( date, globalFormat );
2628
}
2729

28-
date = date || new Date();
30+
this.dateObject = this.dateObject || new Date();
31+
this.globalFormat = globalFormat;
32+
};
2933

30-
return {
31-
setFormat: function( format ) {
32-
if ( format ) {
33-
globalFormat = format;
34-
}
35-
return this;
36-
},
37-
//TODO: same as the underlying Date object's terminology, but still misleading.
38-
//TODO: We can use .setTime() instead of new Date and rename to setTimestamp.
39-
setTime: function( time ) {
40-
date = new Date( time );
41-
return this;
42-
},
43-
setDay: function( day ) {
44-
date = new Date( date.getFullYear(), date.getMonth(), day, date.getHours(), date.getMinutes(), date.getSeconds() );
45-
return this;
46-
},
47-
setMonth: function( month ) {
48-
// Overflow example: Month is October 31 (yeah Halloween) and month is changed to April with 30 days,
49-
// the new date will me May 1. We will honor the month the user wants to set and if and overflow
50-
// occurs, set to last day of month.
51-
var days = date.getDay(), year = date.getFullYear();
52-
if ( days > this.daysInMonth( year, month ) ) {
53-
// Overflow
54-
days = this.daysInMonth( year, month );
55-
}
56-
date = new Date( year, month, days, date.getHours(), date.getMinutes(), date.getSeconds() );
57-
return this;
58-
},
59-
setYear: function( year ) {
60-
var day = date.getDate(),
61-
month = date.getMonth();
62-
// Check if Leap, and February and day is 29th
63-
if ( this.isLeapYear( year ) && month == 1 && day == 29 ) {
64-
// set day to last day of February
65-
day = this.daysInMonth( year, month );
66-
}
67-
date = new Date( year, month, day, date.getHours(), date.getMinutes(), date.getSeconds() );
68-
return this;
69-
},
70-
setFullDate: function( year, month, day ) {
71-
date = new Date( year, month, day );
72-
return this;
73-
},
74-
adjust: function( period, offset ) {
75-
var day = period == "D" ? date.getDate() + offset : date.getDate(),
76-
month = period == "M" ? date.getMonth() + offset : date.getMonth(),
77-
year = period == "Y" ? date.getFullYear() + offset : date.getFullYear();
78-
// If not day, update the day to the new month and year
79-
if ( period != "D" ) {
80-
day = Math.max( 1, Math.min( day, this.daysInMonth( year, month ) ) );
81-
}
82-
date = new Date( year, month, day, date.getHours(), date.getMinutes(), date.getSeconds() );
83-
return this;
84-
},
85-
daysInMonth: function( year, month ) {
86-
year = year || date.getFullYear();
87-
month = month || date.getMonth();
88-
return 32 - new Date( year, month, 32 ).getDate();
89-
},
90-
monthName: function() {
91-
return Globalize.format( date, { pattern: "MMMM" } );
92-
},
93-
day: function() {
94-
return date.getDate();
95-
},
96-
month: function() {
97-
return date.getMonth();
98-
},
99-
year: function() {
100-
return date.getFullYear();
101-
},
102-
isLeapYear: function( year ) {
103-
year = year || date.getFullYear();
104-
return new Date( year, 1, 29 ).getMonth() == 1;
34+
$.date.prototype = {
35+
setFormat: function( format ) {
36+
if ( format ) {
37+
this.globalFormat = format;
38+
}
39+
return this;
40+
},
41+
//TODO: same as the underlying Date object's terminology, but still misleading.
42+
//TODO: We can use .setTime() instead of new Date and rename to setTimestamp.
43+
setTime: function( time ) {
44+
this.dateObject = new Date( time );
45+
return this;
46+
},
47+
setDay: function( day ) {
48+
var date = this.dateObject;
49+
this.dateObject = new Date( date.getFullYear(), date.getMonth(), day, date.getHours(),
50+
date.getMinutes(), date.getSeconds() );
51+
return this;
52+
},
53+
setMonth: function( month ) {
54+
// Overflow example: Month is October 31 (yeah Halloween) and month is changed to April with 30 days,
55+
// the new date will me May 1. We will honor the month the user wants to set and if and overflow
56+
// occurs, set to last day of month.
57+
var date = this.dateObject,
58+
days = date.getDay(), year = date.getFullYear();
59+
if ( days > this.daysInMonth( year, month ) ) {
10560

106-
},
107-
weekdays: function() {
108-
var result = [];
109-
for ( var dow = 0; dow < 7; dow++ ) {
110-
var day = ( dow + weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] ) % 7;
111-
result.push({
112-
shortname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/abbreviated", weekdays[ day ] ]),
113-
fullname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/wide", weekdays[ day ] ]),
114-
});
115-
}
116-
return result;
117-
},
118-
days: function() {
119-
var result = [],
120-
today = $.date(),
121-
firstDayOfMonth = new Date( this.year(), date.getMonth(), 1 ).getDay(),
122-
leadDays = ( firstDayOfMonth - weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] + 7 ) % 7,
123-
rows = Math.ceil( ( leadDays + this.daysInMonth() ) / 7 ),
124-
printDate = new Date( this.year(), date.getMonth(), 1 - leadDays );
125-
for ( var row = 0; row < rows; row++ ) {
126-
var week = result[ result.length ] = {
127-
number: Globalize.format( printDate, { pattern: "w" } ),
128-
days: []
61+
// Overflow
62+
days = this.daysInMonth( year, month );
63+
}
64+
this.dateObject = new Date( year, month, days, date.getHours(),
65+
date.getMinutes(), date.getSeconds() );
66+
return this;
67+
},
68+
setYear: function( year ) {
69+
var date = this.dateObject,
70+
day = date.getDate(),
71+
month = date.getMonth();
72+
73+
// Check if Leap, and February and day is 29th
74+
if ( this.isLeapYear( year ) && month == 1 && day == 29 ) {
75+
76+
// set day to last day of February
77+
day = this.daysInMonth( year, month );
78+
}
79+
this.dateObject = new Date( year, month, day, date.getHours(),
80+
date.getMinutes(), date.getSeconds() );
81+
return this;
82+
},
83+
setFullDate: function( year, month, day ) {
84+
this.dateObject = new Date( year, month, day );
85+
return this;
86+
},
87+
adjust: function( period, offset ) {
88+
var date = this.dateObject,
89+
day = period == "D" ? date.getDate() + offset : date.getDate(),
90+
month = period == "M" ? date.getMonth() + offset : date.getMonth(),
91+
year = period == "Y" ? date.getFullYear() + offset : date.getFullYear();
92+
93+
// If not day, update the day to the new month and year
94+
if ( period != "D" ) {
95+
day = Math.max( 1, Math.min( day, this.daysInMonth( year, month ) ) );
96+
}
97+
this.dateObject = new Date( year, month, day, date.getHours(),
98+
date.getMinutes(), date.getSeconds() );
99+
return this;
100+
},
101+
daysInMonth: function( year, month ) {
102+
var date = this.dateObject;
103+
year = year || date.getFullYear();
104+
month = month || date.getMonth();
105+
return 32 - new Date( year, month, 32 ).getDate();
106+
},
107+
monthName: function() {
108+
return Globalize.format( this.dateObject, { pattern: "MMMM" } );
109+
},
110+
day: function() {
111+
return this.dateObject.getDate();
112+
},
113+
month: function() {
114+
return this.dateObject.getMonth();
115+
},
116+
year: function() {
117+
return this.dateObject.getFullYear();
118+
},
119+
isLeapYear: function( year ) {
120+
year = year || this.dateObject.getFullYear();
121+
return new Date( year, 1, 29 ).getMonth() == 1;
122+
},
123+
weekdays: function() {
124+
var result = [];
125+
for ( var dow = 0; dow < 7; dow++ ) {
126+
var day = ( dow + weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] ) % 7;
127+
result.push({
128+
shortname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/abbreviated", weekdays[ day ] ]),
129+
fullname: Globalize.locale().main([ "dates/calendars/gregorian/days/format/wide", weekdays[ day ] ]),
130+
});
131+
}
132+
return result;
133+
},
134+
days: function() {
135+
var result = [],
136+
today = $.date(),
137+
date = this.dateObject,
138+
firstDayOfMonth = new Date( this.year(), date.getMonth(), 1 ).getDay(),
139+
leadDays = ( firstDayOfMonth - weekdaysRev[ Globalize.locale().supplemental.weekData.firstDay() ] + 7 ) % 7,
140+
rows = Math.ceil( ( leadDays + this.daysInMonth() ) / 7 ),
141+
printDate = new Date( this.year(), date.getMonth(), 1 - leadDays );
142+
for ( var row = 0; row < rows; row++ ) {
143+
var week = result[ result.length ] = {
144+
number: Globalize.format( printDate, { pattern: "w" } ),
145+
days: []
146+
};
147+
for ( var dayx = 0; dayx < 7; dayx++ ) {
148+
var day = week.days[ week.days.length ] = {
149+
lead: printDate.getMonth() != date.getMonth(),
150+
date: printDate.getDate(),
151+
timestamp: printDate.getTime(),
152+
current: this.selected && this.selected.equal( printDate ),
153+
today: today.equal( printDate )
129154
};
130-
for ( var dayx = 0; dayx < 7; dayx++ ) {
131-
var day = week.days[ week.days.length ] = {
132-
lead: printDate.getMonth() != date.getMonth(),
133-
date: printDate.getDate(),
134-
timestamp: printDate.getTime(),
135-
current: this.selected && this.selected.equal( printDate ),
136-
today: today.equal( printDate )
137-
};
138-
day.render = day.selectable = !day.lead;
139-
if ( this.eachDay ) {
140-
this.eachDay( day );
141-
}
142-
// TODO use adjust("D", 1)?
143-
printDate.setDate( printDate.getDate() + 1 );
155+
day.render = day.selectable = !day.lead;
156+
if ( this.eachDay ) {
157+
this.eachDay( day );
144158
}
159+
// TODO use adjust("D", 1)?
160+
printDate.setDate( printDate.getDate() + 1 );
145161
}
146-
return result;
147-
},
148-
// specialized for multi-month template, could be used in general
149-
months: function( add ) {
150-
var clone,
151-
result = [ this ];
162+
}
163+
return result;
164+
},
165+
// specialized for multi-month template, could be used in general
166+
months: function( add ) {
167+
var clone,
168+
result = [ this ];
152169

153-
for ( var i = 0; i < add; i++ ) {
154-
clone = this.clone();
155-
clone.adjust( "M", i + 1 );
156-
result.push( clone );
157-
}
158-
result[ 0 ].first = true;
159-
result[ result.length - 1 ].last = true;
160-
return result;
161-
},
162-
select: function() {
163-
this.selected = this.clone();
164-
return this;
165-
},
166-
clone: function() {
167-
return $.date( new Date(date.getFullYear(), date.getMonth(),
168-
date.getDate(), date.getHours(),
169-
date.getMinutes(), date.getSeconds()), globalFormat );
170-
},
171-
// TODO compare year, month, day each for better performance
172-
equal: function( other ) {
173-
function format( date ) {
174-
return Globalize.format( date, { pattern: "yyyyMMdd" } );
175-
}
176-
return format( date ) === format( other );
177-
},
178-
date: function() {
179-
return date;
180-
},
181-
format: function( format ) {
182-
return Globalize.format( date, format || globalFormat );
170+
for ( var i = 0; i < add; i++ ) {
171+
clone = this.clone();
172+
clone.adjust( "M", i + 1 );
173+
result.push( clone );
183174
}
184-
};
175+
result[ 0 ].first = true;
176+
result[ result.length - 1 ].last = true;
177+
return result;
178+
},
179+
select: function() {
180+
this.selected = this.clone();
181+
return this;
182+
},
183+
clone: function() {
184+
var date = this.dateObject;
185+
return new $.date( new Date( date.getFullYear(), date.getMonth(),
186+
date.getDate(), date.getHours(),
187+
date.getMinutes(), date.getSeconds()), this.globalFormat );
188+
},
189+
// TODO compare year, month, day each for better performance
190+
equal: function( other ) {
191+
function format( date ) {
192+
return Globalize.format( date, { pattern: "yyyyMMdd" } );
193+
}
194+
return format( this.dateObject ) === format( other );
195+
},
196+
date: function() {
197+
return this.dateObject;
198+
},
199+
format: function( format ) {
200+
return Globalize.format( this.dateObject, format || this.globalFormat );
201+
}
185202
};
186203

187204
}( jQuery ));

tests/unit/date/date_core.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module( "date: core" );
22

3-
test( "Check Date Setup", 2, function() {
4-
ok( true, "First Test Always Passes" );
5-
ok( $.date(), "Load JQuery Date" );
3+
test( "Instantiation", function() {
4+
expect( 2 );
5+
ok( new $.date() instanceof $.date, "constructor function" );
6+
ok( $.date() instanceof $.date, "instantiation without new" );
67
});
78

89
test( "Check Sets and Gets", 6, function() {
@@ -38,7 +39,6 @@ test( "Date Adjustments - Normal Use Cases", 10, function() {
3839
equal( date.adjust( "D", 1 ).year(), 2013, "Add 1 day to change year from 2012 to 2013" );
3940
equal( date.adjust( "D", -1 ).year(), 2012,
4041
"Subtract 1 day to change month from 2013 to 2012" );
41-
4242
});
4343

4444
test( "Date Adjustments - Month Overflow Edge Cases", 2, function() {

0 commit comments

Comments
 (0)