usefull_filter 0.0.4 → 1.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -3
- data/README.rdoc +6 -1
- data/app/helpers/usefull_filter_helper.rb +34 -6
- data/lib/generators/usefull_filter/install/install_generator.rb +3 -3
- data/lib/generators/usefull_filter/install/templates/config/locales/usefull_filter.it.yml +29 -0
- data/lib/generators/usefull_filter/install/templates/public/javascripts/usefull_filter_date_select.js +2420 -0
- data/lib/generators/usefull_filter/install/templates/public/stylesheets/usefull_filter.css +67 -0
- data/lib/generators/usefull_filter/install/templates/public/stylesheets/usefull_filter_date_select.css +247 -0
- data/lib/usefull_filter/filter_form_builder.rb +60 -35
- data/lib/usefull_filter/version.rb +1 -1
- metadata +22 -43
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA512:
|
3
|
+
data.tar.gz: 472b4bc87a817818a0b0154c20d3cac9ef84202c23b4a17f0d531fe64eb8079f2d6cb26cfa6155adcfbbc6a76a8e718566363a2f72135d5d0def4381e08957f2
|
4
|
+
metadata.gz: 9c7a67d87fd54c5ad1e7fa6acd9e4247dc0d69679f2222afa1878a0375c206efc9371969c835e597e90e21493d657df9bb59acff8c765820c99214054c4ce2b8
|
5
|
+
SHA1:
|
6
|
+
data.tar.gz: 032e5f180a6dadee2775a07bbf8549b05d59373d
|
7
|
+
metadata.gz: 60224ac3910252312735d255fd5dcc683cd90d17
|
data/CHANGELOG.md
CHANGED
data/README.rdoc
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#[documents_controller]
|
5
5
|
# Vedi TableHelper
|
6
6
|
#
|
7
|
+
#
|
7
8
|
#[index.html.erb]
|
8
9
|
# <%=filter_for_new @search, :url => magazzino_documents_path do |f| %>
|
9
10
|
# <%= f.text_field :data, :size => 10, :filters => ["equals", "less_than_or_equal_to", "greater_than_or_equal_to"] %>
|
@@ -12,7 +13,7 @@
|
|
12
13
|
# <%= f.text_field :BollaXENrDoC, filters_except => ["equals", "does_not_equal"] %>
|
13
14
|
# <%= f.text_field :DoCSit %>
|
14
15
|
# <%= f.submit %>
|
15
|
-
# <% end %>
|
16
|
+
# <% end %> f
|
16
17
|
module UsefullFilterHelper
|
17
18
|
#Contatta l'url passato ripassando i filtri attivi in @search
|
18
19
|
def filter_button_tag(name, url, method = :get)
|
@@ -34,8 +35,28 @@ module UsefullFilterHelper
|
|
34
35
|
filter_for(obj, *args, &proc)
|
35
36
|
end
|
36
37
|
|
38
|
+
# Parsa il params per accomodare il tipo di dato dei valori
|
39
|
+
def parse_params(param)
|
40
|
+
param.keys.each do |k|
|
41
|
+
param[k]=param[k].split(' ') if '_in' == /_in$/.match(k).to_s
|
42
|
+
end unless param.blank?
|
43
|
+
#mylog("parse_params: #{param.inspect}")
|
44
|
+
param
|
45
|
+
end
|
46
|
+
|
47
|
+
# Parsa il params per accomodare il tipo di dato dei valori
|
48
|
+
def parse_params_rev(param)
|
49
|
+
param.keys.each do |k|
|
50
|
+
param[k]=param[k].join(' ') if '_in' == /_in$/.match(k).to_s
|
51
|
+
end
|
52
|
+
mylog("parse_params_rev: #{param.inspect}")
|
53
|
+
param
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
37
58
|
#Cerca una serie di filtri utilizzando MetaSearch di cui fa il wrapper
|
38
|
-
#obj è una istanza
|
59
|
+
#obj è una istanza metasearch
|
39
60
|
def filter_for(obj, *args, &proc)
|
40
61
|
unless obj.blank?
|
41
62
|
options = args.extract_options!
|
@@ -52,18 +73,25 @@ module UsefullFilterHelper
|
|
52
73
|
filter_title = I18n.t("filter_title", :scope => "meta_search.buttons")
|
53
74
|
|
54
75
|
#Estraggo le options che mi interessano, perchè una volta passate al builder
|
55
|
-
#per
|
76
|
+
#per qualche arcano motivo vengono alterate....
|
56
77
|
classe = options[:html_1].delete(:class)
|
57
78
|
url = options[:url]
|
58
|
-
#
|
79
|
+
# mylog("FilterHelper#filter_for_new: args=#{args.inspect}")
|
80
|
+
# mylog("FilterHelper#filter_for_new: options=#{options.inspect}")
|
81
|
+
# mylog("FilterHelper#filter_for_new: obj=#{obj.inspect}")
|
59
82
|
content_tag(:div,
|
83
|
+
javascript_include_tag("usefull_filter_date_select") +
|
84
|
+
javascript_include_tag("usefull_helpers_toggle_area")+
|
85
|
+
stylesheet_link_tag("usefull_filter") +
|
86
|
+
stylesheet_link_tag("usefull_filter_date_select") +
|
60
87
|
content_tag(:h3, filter_title) +
|
88
|
+
toggle_area("all_filters") +
|
61
89
|
content_tag(:ul,
|
62
90
|
form_for(obj, *(args << options), &proc) +
|
63
91
|
form_tag(url_for(url), :method => :get) do
|
64
92
|
obj.search_attributes.each_key {|k| concat hidden_field_tag("search[#{k}]") }
|
65
|
-
concat submit_tag(remove_filter_label, :class => "
|
66
|
-
end ),
|
93
|
+
concat submit_tag(remove_filter_label, :class => "remove_filter_btn")
|
94
|
+
end, :class=> "all_filters", :style => "display: none;" ),
|
67
95
|
:class => classe)
|
68
96
|
end
|
69
97
|
end
|
@@ -4,9 +4,9 @@ module UsefullFilter
|
|
4
4
|
desc "Install generator for UsefullFilter gem"
|
5
5
|
source_root File.expand_path("../templates", __FILE__)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
def copy_config
|
8
|
+
directory "."
|
9
|
+
end
|
10
10
|
|
11
11
|
#def copy_public
|
12
12
|
# directory "public"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
it:
|
2
|
+
meta_search:
|
3
|
+
predicates:
|
4
|
+
equals: "%{attribute} ="
|
5
|
+
does_not_equal: "%{attribute} !="
|
6
|
+
contains: "%{attribute} contiene"
|
7
|
+
does_not_contain: "%{attribute} non contiene"
|
8
|
+
starts_with: "%{attribute} inizia con"
|
9
|
+
does_not_start_with: "%{attribute} non inizia con"
|
10
|
+
ends_with: "%{attribute} finisce con"
|
11
|
+
does_not_end_with: "%{attribute} non finisce con"
|
12
|
+
greater_than: "%{attribute} >"
|
13
|
+
less_than: "%{attribute} <"
|
14
|
+
greater_than_or_equal_to: "%{attribute} >="
|
15
|
+
less_than_or_equal_to: "%{attribute} <="
|
16
|
+
in: "%{attribute} è uno di"
|
17
|
+
not_in: "%{attribute} non è uno di"
|
18
|
+
is_true: "%{attribute} è vero"
|
19
|
+
is_false: "%{attribute} è falso"
|
20
|
+
is_present: "%{attribute} è presente"
|
21
|
+
is_blank: "%{attribute} è bianco"
|
22
|
+
is_null: "%{attribute} è nullo"
|
23
|
+
is_not_null: "%{attribute} non è nullo"
|
24
|
+
between: "%{attribute} compreso tra"
|
25
|
+
buttons:
|
26
|
+
applay_filter: "Filtra"
|
27
|
+
remove_filter: "Rimuovi Filtri"
|
28
|
+
filter_title: "Filtri"
|
29
|
+
|
@@ -0,0 +1,2420 @@
|
|
1
|
+
/********************************************************************
|
2
|
+
* Kalendae, a framework agnostic javascript date picker *
|
3
|
+
* Copyright(c) 2013 Jarvis Badgley (chipersoft@gmail.com) *
|
4
|
+
* http://github.com/ChiperSoft/Kalendae *
|
5
|
+
* Version 0.4.2 *
|
6
|
+
********************************************************************/
|
7
|
+
|
8
|
+
(function (undefined) {
|
9
|
+
|
10
|
+
var today, moment;
|
11
|
+
|
12
|
+
var Kalendae = function (targetElement, options) {
|
13
|
+
if (typeof document.addEventListener !== 'function' && !util.isIE8()) return;
|
14
|
+
|
15
|
+
//if the first argument isn't an element and isn't a string, assume that it is the options object
|
16
|
+
var is_element = false;
|
17
|
+
try {
|
18
|
+
is_element = targetElement instanceof Element;
|
19
|
+
}
|
20
|
+
catch (err) {
|
21
|
+
is_element = !!targetElement && is_element.nodeType === 1;
|
22
|
+
}
|
23
|
+
if (!(is_element || typeof(targetElement) === 'string')) options = targetElement;
|
24
|
+
|
25
|
+
var self = this,
|
26
|
+
classes = self.classes,
|
27
|
+
opts = self.settings = util.merge(self.defaults, {attachTo:targetElement}, options || {}),
|
28
|
+
$container = self.container = util.make('div', {'class':classes.container}),
|
29
|
+
calendars = self.calendars = [],
|
30
|
+
startDay = moment().day(opts.weekStart),
|
31
|
+
vsd,
|
32
|
+
columnHeaders = [],
|
33
|
+
$cal,
|
34
|
+
$title,
|
35
|
+
$caption,
|
36
|
+
$header,
|
37
|
+
$days, dayNodes = [],
|
38
|
+
$span,
|
39
|
+
i = 0,
|
40
|
+
j = opts.months;
|
41
|
+
|
42
|
+
if (util.isIE8()) util.addClassName($container, 'ie8');
|
43
|
+
|
44
|
+
//generate the column headers (Su, Mo, Tu, etc)
|
45
|
+
i = 7;
|
46
|
+
while (i--) {
|
47
|
+
columnHeaders.push( startDay.format(opts.columnHeaderFormat) );
|
48
|
+
startDay.add('days',1);
|
49
|
+
}
|
50
|
+
|
51
|
+
//setup publish/subscribe and apply any subscriptions passed in settings
|
52
|
+
MinPubSub(self);
|
53
|
+
if (typeof opts.subscribe === 'object') {
|
54
|
+
for (i in opts.subscribe) if (opts.subscribe.hasOwnProperty(i)) {
|
55
|
+
self.subscribe(i, opts.subscribe[i]);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
//process default selected dates
|
60
|
+
self._sel = [];
|
61
|
+
if (!!opts.selected) self.setSelected(opts.selected, false);
|
62
|
+
|
63
|
+
//set the view month
|
64
|
+
if (!!opts.viewStartDate) {
|
65
|
+
vsd = moment(opts.viewStartDate, opts.format);
|
66
|
+
} else if (self._sel.length > 0) {
|
67
|
+
vsd = moment(self._sel[0]);
|
68
|
+
} else {
|
69
|
+
vsd = moment();
|
70
|
+
}
|
71
|
+
self.viewStartDate = vsd.date(1);
|
72
|
+
|
73
|
+
var viewDelta = ({
|
74
|
+
'past' : opts.months-1,
|
75
|
+
'today-past' : opts.months-1,
|
76
|
+
'any' : opts.months>2?Math.floor(opts.months/2):0,
|
77
|
+
'today-future' : 0,
|
78
|
+
'future' : 0
|
79
|
+
})[this.settings.direction];
|
80
|
+
|
81
|
+
|
82
|
+
if (viewDelta && moment().month()==moment(self.viewStartDate).month()){
|
83
|
+
self.viewStartDate = moment(self.viewStartDate).subtract({M:viewDelta}).date(1);
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
if (typeof opts.blackout === 'function') {
|
88
|
+
self.blackout = opts.blackout;
|
89
|
+
} else if (!!opts.blackout) {
|
90
|
+
var bdates = parseDates(opts.blackout, opts.parseSplitDelimiter, opts.format);
|
91
|
+
self.blackout = function (input) {
|
92
|
+
input = moment(input).yearDay();
|
93
|
+
if (input < 1 || !self._sel) return false;
|
94
|
+
var i = bdates.length;
|
95
|
+
while (i--) if (bdates[i].yearDay() === input) return true;
|
96
|
+
return false;
|
97
|
+
};
|
98
|
+
} else {
|
99
|
+
self.blackout = function () {return false;};
|
100
|
+
}
|
101
|
+
|
102
|
+
|
103
|
+
self.direction = self.directions[opts.direction] ? self.directions[opts.direction] : self.directions['any'];
|
104
|
+
|
105
|
+
|
106
|
+
//for the total months setting, generate N calendar views and add them to the container
|
107
|
+
j = Math.max(opts.months,1);
|
108
|
+
while (j--) {
|
109
|
+
$cal = util.make('div', {'class':classes.calendar}, $container);
|
110
|
+
|
111
|
+
$cal.setAttribute('data-cal-index', j);
|
112
|
+
if (opts.months > 1) {
|
113
|
+
if (j == Math.max(opts.months-1,1)) util.addClassName($cal, classes.monthFirst);
|
114
|
+
else if (j === 0) util.addClassName($cal, classes.monthLast);
|
115
|
+
else util.addClassName($cal, classes.monthMiddle);
|
116
|
+
}
|
117
|
+
|
118
|
+
//title bar
|
119
|
+
$title = util.make('div', {'class':classes.title}, $cal);
|
120
|
+
if(!opts.useYearNav){
|
121
|
+
util.addClassName($title, classes.disableYearNav);
|
122
|
+
}
|
123
|
+
util.make('a', {'class':classes.previousYear}, $title); //previous button
|
124
|
+
util.make('a', {'class':classes.previousMonth}, $title); //previous button
|
125
|
+
util.make('a', {'class':classes.nextYear}, $title); //next button
|
126
|
+
util.make('a', {'class':classes.nextMonth}, $title); //next button
|
127
|
+
$caption = util.make('span', {'class':classes.caption}, $title); //title caption
|
128
|
+
|
129
|
+
//column headers
|
130
|
+
$header = util.make('div', {'class':classes.header}, $cal);
|
131
|
+
i = 0;
|
132
|
+
do {
|
133
|
+
$span = util.make('span', {}, $header);
|
134
|
+
$span.innerHTML = columnHeaders[i];
|
135
|
+
} while (++i < 7);
|
136
|
+
|
137
|
+
//individual day cells
|
138
|
+
$days = util.make('div', {'class':classes.days}, $cal);
|
139
|
+
i = 0;
|
140
|
+
dayNodes = [];
|
141
|
+
while (i++ < 42) {
|
142
|
+
dayNodes.push(util.make('span', {}, $days));
|
143
|
+
}
|
144
|
+
|
145
|
+
//store each calendar view for easy redrawing
|
146
|
+
calendars.push({
|
147
|
+
caption:$caption,
|
148
|
+
days:dayNodes
|
149
|
+
});
|
150
|
+
|
151
|
+
if (j) util.make('div', {'class':classes.monthSeparator}, $container);
|
152
|
+
}
|
153
|
+
|
154
|
+
self.draw();
|
155
|
+
|
156
|
+
util.addEvent($container, 'mousedown', function (event, target) {
|
157
|
+
var clickedDate;
|
158
|
+
if (util.hasClassName(target, classes.nextMonth)) {
|
159
|
+
//NEXT MONTH BUTTON
|
160
|
+
if (!self.disableNext && self.publish('view-changed', self, ['next-month']) !== false) {
|
161
|
+
self.viewStartDate.add('months',1);
|
162
|
+
self.draw();
|
163
|
+
}
|
164
|
+
return false;
|
165
|
+
|
166
|
+
} else if (util.hasClassName(target, classes.previousMonth)) {
|
167
|
+
//PREVIOUS MONTH BUTTON
|
168
|
+
if (!self.disablePreviousMonth && self.publish('view-changed', self, ['previous-month']) !== false) {
|
169
|
+
self.viewStartDate.subtract('months',1);
|
170
|
+
self.draw();
|
171
|
+
}
|
172
|
+
return false;
|
173
|
+
|
174
|
+
} else if (util.hasClassName(target, classes.nextYear)) {
|
175
|
+
//NEXT MONTH BUTTON
|
176
|
+
if (!self.disableNext && self.publish('view-changed', self, ['next-year']) !== false) {
|
177
|
+
self.viewStartDate.add('years',1);
|
178
|
+
self.draw();
|
179
|
+
}
|
180
|
+
return false;
|
181
|
+
|
182
|
+
} else if (util.hasClassName(target, classes.previousYear)) {
|
183
|
+
//PREVIOUS MONTH BUTTON
|
184
|
+
if (!self.disablePreviousMonth && self.publish('view-changed', self, ['previous-year']) !== false) {
|
185
|
+
self.viewStartDate.subtract('years',1);
|
186
|
+
self.draw();
|
187
|
+
}
|
188
|
+
return false;
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
} else if (util.hasClassName(target.parentNode, classes.days) && util.hasClassName(target, classes.dayActive) && (clickedDate = target.getAttribute('data-date'))) {
|
193
|
+
//DAY CLICK
|
194
|
+
clickedDate = moment(clickedDate, opts.dayAttributeFormat).hours(12);
|
195
|
+
if (self.publish('date-clicked', self, [clickedDate]) !== false) {
|
196
|
+
|
197
|
+
switch (opts.mode) {
|
198
|
+
case 'multiple':
|
199
|
+
if (!self.addSelected(clickedDate)) self.removeSelected(clickedDate);
|
200
|
+
break;
|
201
|
+
case 'range':
|
202
|
+
self.addSelected(clickedDate);
|
203
|
+
break;
|
204
|
+
case 'single':
|
205
|
+
/* falls through */
|
206
|
+
default:
|
207
|
+
self.addSelected(clickedDate);
|
208
|
+
break;
|
209
|
+
}
|
210
|
+
|
211
|
+
}
|
212
|
+
return false;
|
213
|
+
|
214
|
+
}
|
215
|
+
return false;
|
216
|
+
});
|
217
|
+
|
218
|
+
|
219
|
+
if (!!(opts.attachTo = util.$(opts.attachTo))) {
|
220
|
+
opts.attachTo.appendChild($container);
|
221
|
+
}
|
222
|
+
|
223
|
+
};
|
224
|
+
|
225
|
+
Kalendae.prototype = {
|
226
|
+
defaults : {
|
227
|
+
attachTo :null, /* the element to attach the root container to. can be string or DOMElement */
|
228
|
+
months :1, /* total number of months to display side by side */
|
229
|
+
weekStart :0, /* day to use for the start of the week. 0 is Sunday */
|
230
|
+
direction :'any', /* past, today-past, any, today-future, future */
|
231
|
+
directionScrolling :true, /* if a direction other than any is defined, prevent scrolling out of range */
|
232
|
+
viewStartDate :null, /* date in the month to display. When multiple months, this is the left most */
|
233
|
+
blackout :null, /* array of dates, or function to be passed a date */
|
234
|
+
selected :null, /* dates already selected. can be string, date, or array of strings or dates. */
|
235
|
+
mode :'single', /* single, multiple, range */
|
236
|
+
dayOutOfMonthClickable:false,
|
237
|
+
format :null, /* string used for parsing dates. */
|
238
|
+
subscribe :null, /* object containing events to subscribe to */
|
239
|
+
|
240
|
+
columnHeaderFormat :'dd', /* number of characters to show in the column headers */
|
241
|
+
titleFormat :'MMMM, YYYY', /* format mask for month titles. See momentjs.com for rules */
|
242
|
+
dayNumberFormat :'D', /* format mask for individual days */
|
243
|
+
dayAttributeFormat :'YYYY-MM-DD', /* format mask for the data-date attribute set on every span */
|
244
|
+
parseSplitDelimiter : /,\s*|\s+-\s+/, /* regex to use for splitting multiple dates from a passed string */
|
245
|
+
rangeDelimiter :' - ', /* string to use between dates when outputting in range mode */
|
246
|
+
multipleDelimiter :', ', /* string to use between dates when outputting in multiple mode */
|
247
|
+
useYearNav :true,
|
248
|
+
|
249
|
+
dateClassMap :{}
|
250
|
+
},
|
251
|
+
classes : {
|
252
|
+
container :'kalendae',
|
253
|
+
calendar :'k-calendar',
|
254
|
+
monthFirst :'k-first-month',
|
255
|
+
monthMiddle :'k-middle-month',
|
256
|
+
monthLast :'k-last-month',
|
257
|
+
title :'k-title',
|
258
|
+
previousMonth :'k-btn-previous-month',
|
259
|
+
nextMonth :'k-btn-next-month',
|
260
|
+
previousYear :'k-btn-previous-year',
|
261
|
+
nextYear :'k-btn-next-year',
|
262
|
+
caption :'k-caption',
|
263
|
+
header :'k-header',
|
264
|
+
days :'k-days',
|
265
|
+
dayOutOfMonth :'k-out-of-month',
|
266
|
+
dayInMonth :'k-in-month',
|
267
|
+
dayActive :'k-active',
|
268
|
+
daySelected :'k-selected',
|
269
|
+
dayInRange :'k-range',
|
270
|
+
dayToday :'k-today',
|
271
|
+
monthSeparator :'k-separator',
|
272
|
+
disablePreviousMonth :'k-disable-previous-month-btn',
|
273
|
+
disableNextMonth :'k-disable-next-month-btn',
|
274
|
+
disablePreviousYear :'k-disable-previous-year-btn',
|
275
|
+
disableNextYear :'k-disable-next-year-btn',
|
276
|
+
disableYearNav :'k-disable-year-nav'
|
277
|
+
},
|
278
|
+
|
279
|
+
disablePreviousMonth: false,
|
280
|
+
disableNextMonth: false,
|
281
|
+
disablePreviousYear: false,
|
282
|
+
disableNextYear: false,
|
283
|
+
|
284
|
+
directions: {
|
285
|
+
'past' :function (date) {return moment(date).yearDay() >= today.yearDay();},
|
286
|
+
'today-past' :function (date) {return moment(date).yearDay() > today.yearDay();},
|
287
|
+
'any' :function (date) {return false;},
|
288
|
+
'today-future' :function (date) {return moment(date).yearDay() < today.yearDay();},
|
289
|
+
'future' :function (date) {return moment(date).yearDay() <= today.yearDay();}
|
290
|
+
},
|
291
|
+
|
292
|
+
getSelectedAsDates : function () {
|
293
|
+
var out = [];
|
294
|
+
var i=0, c = this._sel.length;
|
295
|
+
for (;i<c;i++) {
|
296
|
+
out.push(this._sel[i].toDate());
|
297
|
+
}
|
298
|
+
return out;
|
299
|
+
},
|
300
|
+
|
301
|
+
getSelectedAsText : function (format) {
|
302
|
+
var out = [];
|
303
|
+
var i=0, c = this._sel.length;
|
304
|
+
for (;i<c;i++) {
|
305
|
+
out.push(this._sel[i].format(format || this.settings.format || 'YYYY-MM-DD'));
|
306
|
+
}
|
307
|
+
return out;
|
308
|
+
},
|
309
|
+
|
310
|
+
getSelectedRaw : function () {
|
311
|
+
var out = [];
|
312
|
+
var i=0, c = this._sel.length;
|
313
|
+
for (;i<c;i++) {
|
314
|
+
out.push(moment(this._sel[i]));
|
315
|
+
}
|
316
|
+
return out;
|
317
|
+
},
|
318
|
+
|
319
|
+
getSelected : function (format) {
|
320
|
+
var sel = this.getSelectedAsText(format);
|
321
|
+
switch (this.settings.mode) {
|
322
|
+
case 'range':
|
323
|
+
sel.splice(2); //shouldn't be more than two, but lets just make sure.
|
324
|
+
return sel.join(this.settings.rangeDelimiter);
|
325
|
+
|
326
|
+
case 'multiple':
|
327
|
+
return sel.join(this.settings.multipleDelimiter);
|
328
|
+
|
329
|
+
case 'single':
|
330
|
+
/* falls through */
|
331
|
+
default:
|
332
|
+
return (sel[0] || null);
|
333
|
+
}
|
334
|
+
},
|
335
|
+
|
336
|
+
isSelected : function (input) {
|
337
|
+
input = moment(input).yearDay();
|
338
|
+
if (input < 1 || !this._sel || this._sel.length < 1) return false;
|
339
|
+
|
340
|
+
switch (this.settings.mode) {
|
341
|
+
case 'range':
|
342
|
+
var a = this._sel[0] ? this._sel[0].yearDay() : 0,
|
343
|
+
b = this._sel[1] ? this._sel[1].yearDay() : 0;
|
344
|
+
|
345
|
+
if (a === input || b === input) return 1;
|
346
|
+
if (!a || !b) return 0;
|
347
|
+
|
348
|
+
if ((input > a && input < b) || (a<b && input < a && input > b)) return -1;
|
349
|
+
return false;
|
350
|
+
|
351
|
+
case 'multiple':
|
352
|
+
var i = this._sel.length;
|
353
|
+
while (i--) {
|
354
|
+
if (this._sel[i].yearDay() === input) {
|
355
|
+
return true;
|
356
|
+
}
|
357
|
+
}
|
358
|
+
return false;
|
359
|
+
|
360
|
+
|
361
|
+
case 'single':
|
362
|
+
/* falls through */
|
363
|
+
default:
|
364
|
+
return (this._sel[0] && (this._sel[0].yearDay() === input));
|
365
|
+
}
|
366
|
+
|
367
|
+
return false;
|
368
|
+
},
|
369
|
+
|
370
|
+
setSelected : function (input, draw) {
|
371
|
+
var i,
|
372
|
+
new_dates = parseDates(input, this.settings.parseSplitDelimiter, this.settings.format),
|
373
|
+
old_dates = parseDates(this.getSelected(), this.settings.parseSplitDelimiter, this.settings.format);
|
374
|
+
|
375
|
+
i = old_dates.length;
|
376
|
+
while(i--) { this.removeSelected(old_dates[i], false); }
|
377
|
+
|
378
|
+
i = new_dates.length;
|
379
|
+
while(i--) { this.addSelected(new_dates[i], false); }
|
380
|
+
|
381
|
+
if (draw !== false) this.draw();
|
382
|
+
},
|
383
|
+
|
384
|
+
addSelected : function (date, draw) {
|
385
|
+
date = moment(date, this.settings.format).hours(12);
|
386
|
+
|
387
|
+
if(this.settings.dayOutOfMonthClickable && this.settings.mode !== 'range'){ this.makeSelectedDateVisible(date); }
|
388
|
+
|
389
|
+
switch (this.settings.mode) {
|
390
|
+
case 'multiple':
|
391
|
+
if (!this.isSelected(date)) this._sel.push(date);
|
392
|
+
else return false;
|
393
|
+
break;
|
394
|
+
case 'range':
|
395
|
+
|
396
|
+
if (this._sel.length !== 1) this._sel = [date];
|
397
|
+
else {
|
398
|
+
if (date.yearDay() > this._sel[0].yearDay()) this._sel[1] = date;
|
399
|
+
else this._sel = [date, this._sel[0]];
|
400
|
+
}
|
401
|
+
break;
|
402
|
+
case 'single':
|
403
|
+
/* falls through */
|
404
|
+
default:
|
405
|
+
this._sel = [date];
|
406
|
+
break;
|
407
|
+
}
|
408
|
+
this._sel.sort(function (a,b) {return a.yearDay() - b.yearDay();});
|
409
|
+
this.publish('change', this, [date]);
|
410
|
+
if (draw !== false) this.draw();
|
411
|
+
return true;
|
412
|
+
},
|
413
|
+
|
414
|
+
makeSelectedDateVisible: function (date) {
|
415
|
+
outOfViewMonth = moment(date).date('1').diff(this.viewStartDate,'months');
|
416
|
+
|
417
|
+
if(outOfViewMonth < 0){
|
418
|
+
this.viewStartDate.subtract('months',1);
|
419
|
+
}
|
420
|
+
else if(outOfViewMonth > 0 && outOfViewMonth >= this.settings.months){
|
421
|
+
this.viewStartDate.add('months',1);
|
422
|
+
}
|
423
|
+
},
|
424
|
+
|
425
|
+
removeSelected : function (date, draw) {
|
426
|
+
date = moment(date, this.settings.format).hours(12);
|
427
|
+
var i = this._sel.length;
|
428
|
+
while (i--) {
|
429
|
+
if (this._sel[i].yearDay() === date.yearDay()) {
|
430
|
+
this._sel.splice(i,1);
|
431
|
+
this.publish('change', this, [date]);
|
432
|
+
if (draw !== false) this.draw();
|
433
|
+
return true;
|
434
|
+
}
|
435
|
+
}
|
436
|
+
return false;
|
437
|
+
},
|
438
|
+
|
439
|
+
draw : function draw() {
|
440
|
+
// return;
|
441
|
+
var month = moment(this.viewStartDate).hours(12), //force middle of the day to avoid any weird date shifts
|
442
|
+
day,
|
443
|
+
classes = this.classes,
|
444
|
+
cal,
|
445
|
+
$span,
|
446
|
+
klass,
|
447
|
+
i=0, c,
|
448
|
+
j=0, k,
|
449
|
+
s,
|
450
|
+
dateString,
|
451
|
+
opts = this.settings,
|
452
|
+
diff;
|
453
|
+
|
454
|
+
c = this.calendars.length;
|
455
|
+
|
456
|
+
do {
|
457
|
+
day = moment(month).date(1);
|
458
|
+
day.day( day.day() < this.settings.weekStart ? this.settings.weekStart-7 : this.settings.weekStart);
|
459
|
+
//if the first day of the month is less than our week start, back up a week
|
460
|
+
|
461
|
+
cal = this.calendars[i];
|
462
|
+
cal.caption.innerHTML = month.format(this.settings.titleFormat);
|
463
|
+
j = 0;
|
464
|
+
do {
|
465
|
+
$span = cal.days[j];
|
466
|
+
|
467
|
+
klass = [];
|
468
|
+
|
469
|
+
s = this.isSelected(day);
|
470
|
+
|
471
|
+
if (s) klass.push(({'-1':classes.dayInRange,'1':classes.daySelected, 'true':classes.daySelected})[s]);
|
472
|
+
|
473
|
+
if (day.month() != month.month()) klass.push(classes.dayOutOfMonth);
|
474
|
+
else klass.push(classes.dayInMonth);
|
475
|
+
|
476
|
+
if (!(this.blackout(day) || this.direction(day) || (day.month() != month.month() && opts.dayOutOfMonthClickable === false)) || s>0) klass.push(classes.dayActive);
|
477
|
+
|
478
|
+
if (day.yearDay() === today.yearDay()) klass.push(classes.dayToday);
|
479
|
+
|
480
|
+
dateString = day.format(this.settings.dayAttributeFormat);
|
481
|
+
if (opts.dateClassMap[dateString]) klass.push(opts.dateClassMap[dateString]);
|
482
|
+
|
483
|
+
$span.innerHTML = day.format(opts.dayNumberFormat);
|
484
|
+
$span.className = klass.join(' ');
|
485
|
+
$span.setAttribute('data-date', dateString);
|
486
|
+
|
487
|
+
|
488
|
+
day.add('days',1);
|
489
|
+
} while (++j < 42);
|
490
|
+
month.add('months',1);
|
491
|
+
} while (++i < c);
|
492
|
+
|
493
|
+
if (opts.directionScrolling) {
|
494
|
+
if (opts.direction==='today-past' || opts.direction==='past') {
|
495
|
+
diff = month.add({m:1}).diff(moment(), 'months', true);
|
496
|
+
if (diff <= 0) {
|
497
|
+
this.disableNextMonth = false;
|
498
|
+
util.removeClassName(this.container, classes.disableNextMonth);
|
499
|
+
} else {
|
500
|
+
this.disableNextMonth = true;
|
501
|
+
util.addClassName(this.container, classes.disableNextMonth);
|
502
|
+
}
|
503
|
+
|
504
|
+
} else if (opts.direction==='today-future' || opts.direction==='future') {
|
505
|
+
diff = month.subtract({m:1}).diff(moment(), 'months', true);
|
506
|
+
if (diff > opts.months) {
|
507
|
+
this.disablePreviousMonth = false;
|
508
|
+
util.removeClassName(this.container, classes.disablePreviousMonth);
|
509
|
+
} else {
|
510
|
+
this.disablePreviousMonth = true;
|
511
|
+
util.addClassName(this.container, classes.disablePreviousMonth);
|
512
|
+
}
|
513
|
+
|
514
|
+
}
|
515
|
+
|
516
|
+
|
517
|
+
if (opts.direction==='today-past' || opts.direction==='past') {
|
518
|
+
diff = month.add({m:12}).diff(moment(), 'months', true);
|
519
|
+
if (diff <= -11) {
|
520
|
+
this.disableNextYear = false;
|
521
|
+
util.removeClassName(this.container, classes.disableNextYear);
|
522
|
+
} else {
|
523
|
+
this.disableNextYear = true;
|
524
|
+
util.addClassName(this.container, classes.disableNextYear);
|
525
|
+
}
|
526
|
+
|
527
|
+
} else if (opts.direction==='today-future' || opts.direction==='future') {
|
528
|
+
diff = month.subtract({m:12}).diff(moment(), 'months', true);
|
529
|
+
if (diff > (11 + opts.months)) {
|
530
|
+
this.disablePreviousYear = false;
|
531
|
+
util.removeClassName(this.container, classes.disablePreviousYear);
|
532
|
+
} else {
|
533
|
+
this.disablePreviousYear = true;
|
534
|
+
util.addClassName(this.container, classes.disablePreviousYear);
|
535
|
+
}
|
536
|
+
|
537
|
+
}
|
538
|
+
|
539
|
+
}
|
540
|
+
}
|
541
|
+
};
|
542
|
+
|
543
|
+
var parseDates = function (input, delimiter, format) {
|
544
|
+
var output = [];
|
545
|
+
|
546
|
+
if (typeof input === 'string') {
|
547
|
+
input = input.split(delimiter);
|
548
|
+
} else if (!util.isArray(input)) {
|
549
|
+
input = [input];
|
550
|
+
}
|
551
|
+
|
552
|
+
var c = input.length,
|
553
|
+
i = 0;
|
554
|
+
|
555
|
+
do {
|
556
|
+
if (input[i]) output.push( moment(input[i], format).hours(12) );
|
557
|
+
} while (++i < c);
|
558
|
+
|
559
|
+
return output;
|
560
|
+
};
|
561
|
+
|
562
|
+
|
563
|
+
|
564
|
+
window.Kalendae = Kalendae;
|
565
|
+
|
566
|
+
var util = Kalendae.util = {
|
567
|
+
|
568
|
+
isIE8: function() {
|
569
|
+
return !!( (/msie 8./i).test(navigator.appVersion) && !(/opera/i).test(navigator.userAgent) && window.ActiveXObject && XDomainRequest && !window.msPerformance );
|
570
|
+
},
|
571
|
+
|
572
|
+
// ELEMENT FUNCTIONS
|
573
|
+
|
574
|
+
$: function (elem) {
|
575
|
+
return (typeof elem == 'string') ? document.getElementById(elem) : elem;
|
576
|
+
},
|
577
|
+
|
578
|
+
$$: function (selector) {
|
579
|
+
return document.querySelectorAll(selector);
|
580
|
+
},
|
581
|
+
|
582
|
+
make: function (tagName, attributes, attach) {
|
583
|
+
var k, e = document.createElement(tagName);
|
584
|
+
if (!!attributes) for (k in attributes) if (attributes.hasOwnProperty(k)) e.setAttribute(k, attributes[k]);
|
585
|
+
if (!!attach) attach.appendChild(e);
|
586
|
+
return e;
|
587
|
+
},
|
588
|
+
|
589
|
+
// Returns true if the DOM element is visible, false if it's hidden.
|
590
|
+
// Checks if display is anything other than none.
|
591
|
+
isVisible: function (elem) {
|
592
|
+
// shamelessly copied from jQuery
|
593
|
+
return elem.offsetWidth > 0 || elem.offsetHeight > 0;
|
594
|
+
},
|
595
|
+
|
596
|
+
getStyle: function (elem, styleProp) {
|
597
|
+
var y;
|
598
|
+
if (elem.currentStyle) {
|
599
|
+
y = elem.currentStyle[styleProp];
|
600
|
+
} else if (window.getComputedStyle) {
|
601
|
+
y = window.getComputedStyle(elem, null)[styleProp];
|
602
|
+
}
|
603
|
+
return y;
|
604
|
+
},
|
605
|
+
|
606
|
+
domReady:function (f){/in/.test(document.readyState) ? setTimeout(function() {util.domReady(f);},9) : f()},
|
607
|
+
|
608
|
+
// Adds a listener callback to a DOM element which is fired on a specified
|
609
|
+
// event. Callback is sent the event object and the element that triggered the event
|
610
|
+
addEvent: function (elem, eventName, callback) {
|
611
|
+
var listener = function (event) {
|
612
|
+
event = event || window.event;
|
613
|
+
var target = event.target || event.srcElement;
|
614
|
+
var block = callback.apply(elem, [event, target]);
|
615
|
+
if (block === false) {
|
616
|
+
if (!!event.preventDefault) event.preventDefault();
|
617
|
+
else {
|
618
|
+
event.returnValue = false;
|
619
|
+
event.cancelBubble = true;
|
620
|
+
}
|
621
|
+
}
|
622
|
+
return block;
|
623
|
+
};
|
624
|
+
if (elem.attachEvent) { // IE only. The "on" is mandatory.
|
625
|
+
elem.attachEvent("on" + eventName, listener);
|
626
|
+
} else { // Other browsers.
|
627
|
+
elem.addEventListener(eventName, listener, false);
|
628
|
+
}
|
629
|
+
return listener;
|
630
|
+
},
|
631
|
+
|
632
|
+
// Removes a listener callback from a DOM element which is fired on a specified
|
633
|
+
// event.
|
634
|
+
removeEvent: function (elem, event, listener) {
|
635
|
+
if (elem.detachEvent) { // IE only. The "on" is mandatory.
|
636
|
+
elem.detachEvent("on" + event, listener);
|
637
|
+
} else { // Other browsers.
|
638
|
+
elem.removeEventListener(event, listener, false);
|
639
|
+
}
|
640
|
+
},
|
641
|
+
|
642
|
+
hasClassName: function(elem, className) { //copied and modified from Prototype.js
|
643
|
+
if (!(elem = util.$(elem))) return false;
|
644
|
+
var eClassName = elem.className;
|
645
|
+
return (eClassName.length > 0 && (eClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(eClassName)));
|
646
|
+
},
|
647
|
+
|
648
|
+
addClassName: function(elem, className) { //copied and modified from Prototype.js
|
649
|
+
if (!(elem = util.$(elem))) return;
|
650
|
+
if (!util.hasClassName(elem, className)) elem.className += (elem.className ? ' ' : '') + className;
|
651
|
+
},
|
652
|
+
|
653
|
+
removeClassName: function(elem, className) { //copied and modified from Prototype.js
|
654
|
+
if (!(elem = util.$(elem))) return;
|
655
|
+
elem.className = util.trimString(elem.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' '));
|
656
|
+
},
|
657
|
+
|
658
|
+
isFixed: function (elem) {
|
659
|
+
do {
|
660
|
+
if (util.getStyle(elem, 'position') === 'fixed') return true;
|
661
|
+
} while ((elem = elem.offsetParent));
|
662
|
+
return false;
|
663
|
+
},
|
664
|
+
|
665
|
+
scrollContainer: function (elem) {
|
666
|
+
do {
|
667
|
+
var overflow = util.getStyle(elem, 'overflow');
|
668
|
+
if (overflow === 'auto' || overflow === 'scroll') return elem;
|
669
|
+
} while ((elem = elem.parentNode) && elem != window.document.body);
|
670
|
+
return null;
|
671
|
+
},
|
672
|
+
|
673
|
+
getPosition: function (elem, isInner) {
|
674
|
+
var x = elem.offsetLeft,
|
675
|
+
y = elem.offsetTop,
|
676
|
+
r = {};
|
677
|
+
|
678
|
+
if (!isInner) {
|
679
|
+
while ((elem = elem.offsetParent)) {
|
680
|
+
x += elem.offsetLeft;
|
681
|
+
y += elem.offsetTop;
|
682
|
+
}
|
683
|
+
}
|
684
|
+
|
685
|
+
r[0] = r.left = x;
|
686
|
+
r[1] = r.top = y;
|
687
|
+
return r;
|
688
|
+
},
|
689
|
+
|
690
|
+
getHeight: function (elem) {
|
691
|
+
return elem.offsetHeight || elem.scrollHeight;
|
692
|
+
},
|
693
|
+
|
694
|
+
getWidth: function (elem) {
|
695
|
+
return elem.offsetWidth || elem.scrollWidth;
|
696
|
+
},
|
697
|
+
|
698
|
+
|
699
|
+
// TEXT FUNCTIONS
|
700
|
+
|
701
|
+
trimString: function (input) {
|
702
|
+
return input.replace(/^\s+/, '').replace(/\s+$/, '');
|
703
|
+
},
|
704
|
+
|
705
|
+
|
706
|
+
// OBJECT FUNCTIONS
|
707
|
+
|
708
|
+
merge: function () {
|
709
|
+
/* Combines multiple objects into one.
|
710
|
+
* Syntax: util.extend([true], object1, object2, ... objectN)
|
711
|
+
* If first argument is true, function will merge recursively.
|
712
|
+
*/
|
713
|
+
|
714
|
+
var deep = (arguments[0]===true),
|
715
|
+
d = {},
|
716
|
+
i = deep?1:0;
|
717
|
+
|
718
|
+
var _c = function (a, b) {
|
719
|
+
if (typeof b !== 'object') return;
|
720
|
+
for (var k in b) if (b.hasOwnProperty(k)) {
|
721
|
+
//if property is an object or array, merge the contents instead of overwriting, if extend() was called as such
|
722
|
+
if (deep && typeof a[k] === 'object' && typeof b[k] === 'object') _update(a[k], b[k]);
|
723
|
+
else a[k] = b[k];
|
724
|
+
}
|
725
|
+
return a;
|
726
|
+
};
|
727
|
+
|
728
|
+
for (; i < arguments.length; i++) {
|
729
|
+
_c(d, arguments[i]);
|
730
|
+
}
|
731
|
+
return d;
|
732
|
+
},
|
733
|
+
|
734
|
+
isArray: function (array) {
|
735
|
+
return Object.prototype.toString.call(array) == "[object Array]"
|
736
|
+
}
|
737
|
+
};
|
738
|
+
|
739
|
+
|
740
|
+
//auto-initializaiton code
|
741
|
+
if (typeof document.addEventListener === 'function') Kalendae.util.domReady(function () {
|
742
|
+
var els = util.$$('.auto-kal'),
|
743
|
+
i = els.length,
|
744
|
+
e,
|
745
|
+
options,
|
746
|
+
optionsRaw;
|
747
|
+
|
748
|
+
while (i--) {
|
749
|
+
e = els[i];
|
750
|
+
optionsRaw = e.getAttribute('data-kal');
|
751
|
+
options = (optionsRaw == null || optionsRaw == "") ? {} : (new Function('return {' + optionsRaw + '};'))();
|
752
|
+
|
753
|
+
if (e.tagName === 'INPUT') {
|
754
|
+
//if element is an input, bind a popup calendar to the input.
|
755
|
+
new Kalendae.Input(e, options);
|
756
|
+
} else {
|
757
|
+
//otherwise, insert a flat calendar into the element.
|
758
|
+
new Kalendae(util.merge(options, {attachTo:e}));
|
759
|
+
}
|
760
|
+
|
761
|
+
}
|
762
|
+
});
|
763
|
+
Kalendae.Input = function (targetElement, options) {
|
764
|
+
if (typeof document.addEventListener !== 'function' && !util.isIE8()) return;
|
765
|
+
|
766
|
+
var $input = this.input = util.$(targetElement),
|
767
|
+
overwriteInput,
|
768
|
+
$closeButton,
|
769
|
+
changing = false;
|
770
|
+
|
771
|
+
if (!$input || $input.tagName !== 'INPUT') throw "First argument for Kalendae.Input must be an <input> element or a valid element id.";
|
772
|
+
|
773
|
+
var self = this,
|
774
|
+
classes = self.classes,
|
775
|
+
opts = self.settings = util.merge(self.defaults, options);
|
776
|
+
|
777
|
+
//force attachment to the body
|
778
|
+
opts.attachTo = window.document.body;
|
779
|
+
|
780
|
+
//if no override provided, use the input's contents
|
781
|
+
if (!opts.selected) opts.selected = $input.value;
|
782
|
+
else overwriteInput = true;
|
783
|
+
|
784
|
+
//call our parent constructor
|
785
|
+
Kalendae.call(self, opts);
|
786
|
+
|
787
|
+
//create the close button
|
788
|
+
if (opts.closeButton) {
|
789
|
+
$closeButton = util.make('a', {'class':classes.closeButton}, self.container);
|
790
|
+
util.addEvent($closeButton, 'click', function () {
|
791
|
+
$input.blur();
|
792
|
+
});
|
793
|
+
}
|
794
|
+
|
795
|
+
if (overwriteInput) $input.value = self.getSelected();
|
796
|
+
|
797
|
+
var $container = self.container,
|
798
|
+
noclose = false;
|
799
|
+
|
800
|
+
$container.style.display = 'none';
|
801
|
+
util.addClassName($container, classes.positioned);
|
802
|
+
|
803
|
+
util.addEvent($container, 'mousedown', function (event, target) {
|
804
|
+
noclose = true; //IE8 doesn't obey event blocking when it comes to focusing, so we have to do this shit.
|
805
|
+
});
|
806
|
+
util.addEvent(window.document, 'mousedown', function (event, target) {
|
807
|
+
noclose = false;
|
808
|
+
});
|
809
|
+
|
810
|
+
util.addEvent($input, 'focus', function () {
|
811
|
+
changing = true; // prevent setSelected from altering the input contents.
|
812
|
+
self.setSelected(this.value);
|
813
|
+
changing = false;
|
814
|
+
self.show();
|
815
|
+
});
|
816
|
+
|
817
|
+
util.addEvent($input, 'blur', function () {
|
818
|
+
if (noclose && util.isIE8()) {
|
819
|
+
noclose = false;
|
820
|
+
$input.focus();
|
821
|
+
}
|
822
|
+
else self.hide();
|
823
|
+
});
|
824
|
+
util.addEvent($input, 'keyup', function (event) {
|
825
|
+
changing = true; // prevent setSelected from altering the input contents.
|
826
|
+
self.setSelected(this.value);
|
827
|
+
changing = false;
|
828
|
+
});
|
829
|
+
|
830
|
+
var $scrollContainer = util.scrollContainer($input);
|
831
|
+
|
832
|
+
if( $scrollContainer ) {
|
833
|
+
|
834
|
+
// Hide calendar when $scrollContainer is scrolled
|
835
|
+
util.addEvent($scrollContainer, 'scroll', function (event) {
|
836
|
+
$input.blur();
|
837
|
+
});
|
838
|
+
}
|
839
|
+
|
840
|
+
self.subscribe('change', function () {
|
841
|
+
if (changing) {
|
842
|
+
// the change event came from an internal modification, don't update the field contents
|
843
|
+
return;
|
844
|
+
}
|
845
|
+
$input.value = self.getSelected();
|
846
|
+
});
|
847
|
+
|
848
|
+
};
|
849
|
+
|
850
|
+
Kalendae.Input.prototype = util.merge(Kalendae.prototype, {
|
851
|
+
defaults : util.merge(Kalendae.prototype.defaults, {
|
852
|
+
format: 'MM/DD/YYYY',
|
853
|
+
side: 'bottom',
|
854
|
+
closeButton: true,
|
855
|
+
offsetLeft: 0,
|
856
|
+
offsetTop: 0
|
857
|
+
}),
|
858
|
+
classes : util.merge(Kalendae.prototype.classes, {
|
859
|
+
positioned : 'k-floating',
|
860
|
+
closeButton: 'k-btn-close'
|
861
|
+
}),
|
862
|
+
|
863
|
+
show : function () {
|
864
|
+
var $container = this.container,
|
865
|
+
style = $container.style,
|
866
|
+
$input = this.input,
|
867
|
+
pos = util.getPosition($input),
|
868
|
+
$scrollContainer = util.scrollContainer($input),
|
869
|
+
scrollTop = $scrollContainer ? $scrollContainer.scrollTop : 0,
|
870
|
+
opts = this.settings;
|
871
|
+
|
872
|
+
style.display = '';
|
873
|
+
switch (opts.side) {
|
874
|
+
case 'left':
|
875
|
+
style.left = (pos.left - util.getWidth($container) + opts.offsetLeft) + 'px';
|
876
|
+
style.top = (pos.top + opts.offsetTop - scrollTop) + 'px';
|
877
|
+
break;
|
878
|
+
case 'right':
|
879
|
+
style.left = (pos.left + util.getWidth($input)) + 'px';
|
880
|
+
style.top = (pos.top + opts.offsetTop - scrollTop) + 'px';
|
881
|
+
break;
|
882
|
+
case 'top':
|
883
|
+
style.left = (pos.left + opts.offsetLeft) + 'px';
|
884
|
+
style.top = (pos.top - util.getHeight($container) + opts.offsetTop - scrollTop) + 'px';
|
885
|
+
break;
|
886
|
+
case 'bottom':
|
887
|
+
/* falls through */
|
888
|
+
default:
|
889
|
+
style.left = (pos.left + opts.offsetLeft) + 'px';
|
890
|
+
style.top = (pos.top + util.getHeight($input) + opts.offsetTop - scrollTop) + 'px';
|
891
|
+
break;
|
892
|
+
}
|
893
|
+
|
894
|
+
style.position = util.isFixed($input) ? 'fixed' : 'absolute';
|
895
|
+
|
896
|
+
this.publish('show', this);
|
897
|
+
},
|
898
|
+
|
899
|
+
hide : function () {
|
900
|
+
this.container.style.display = 'none';
|
901
|
+
this.publish('hide', this);
|
902
|
+
}
|
903
|
+
|
904
|
+
});
|
905
|
+
|
906
|
+
|
907
|
+
/*!
|
908
|
+
* MinPubSub, modified for use on Kalendae
|
909
|
+
* Copyright(c) 2011 Daniel Lamb <daniellmb.com>
|
910
|
+
* https://github.com/daniellmb/MinPubSub
|
911
|
+
* MIT Licensed
|
912
|
+
*/
|
913
|
+
|
914
|
+
var MinPubSub = function(d){
|
915
|
+
|
916
|
+
if (!d) d = this;
|
917
|
+
|
918
|
+
// the topic/subscription hash
|
919
|
+
var cache = d.c_ || {}; //check for "c_" cache for unit testing
|
920
|
+
|
921
|
+
d.publish = function(/* String */ topic, /* Object */ target, /* Array? */ args){
|
922
|
+
// summary:
|
923
|
+
// Publish some data on a named topic.
|
924
|
+
// topic: String
|
925
|
+
// The channel to publish on
|
926
|
+
// args: Array?
|
927
|
+
// The data to publish. Each array item is converted into an ordered
|
928
|
+
// arguments on the subscribed functions.
|
929
|
+
//
|
930
|
+
// example:
|
931
|
+
// Publish stuff on '/some/topic'. Anything subscribed will be called
|
932
|
+
// with a function signature like: function(a,b,c){ ... }
|
933
|
+
//
|
934
|
+
// publish("/some/topic", ["a","b","c"]);
|
935
|
+
|
936
|
+
var subs = cache[topic],
|
937
|
+
len = subs ? subs.length : 0,
|
938
|
+
r;
|
939
|
+
|
940
|
+
//can change loop or reverse array if the order matters
|
941
|
+
while(len--){
|
942
|
+
r = subs[len].apply(target, args || []);
|
943
|
+
if (typeof r === 'boolean') return r;
|
944
|
+
}
|
945
|
+
};
|
946
|
+
|
947
|
+
d.subscribe = function(/* String */ topic, /* Function */ callback, /* Boolean */ topPriority){
|
948
|
+
// summary:
|
949
|
+
// Register a callback on a named topic.
|
950
|
+
// topic: String
|
951
|
+
// The channel to subscribe to
|
952
|
+
// callback: Function
|
953
|
+
// The handler event. Anytime something is publish'ed on a
|
954
|
+
// subscribed channel, the callback will be called with the
|
955
|
+
// published array as ordered arguments.
|
956
|
+
//
|
957
|
+
// returns: Array
|
958
|
+
// A handle which can be used to unsubscribe this particular subscription.
|
959
|
+
//
|
960
|
+
// example:
|
961
|
+
// subscribe("/some/topic", function(a, b, c){ /* handle data */ });
|
962
|
+
|
963
|
+
if(!cache[topic]){
|
964
|
+
cache[topic] = [];
|
965
|
+
}
|
966
|
+
if (topPriority)
|
967
|
+
cache[topic].push(callback);
|
968
|
+
else
|
969
|
+
cache[topic].unshift(callback);
|
970
|
+
return [topic, callback]; // Array
|
971
|
+
};
|
972
|
+
|
973
|
+
d.unsubscribe = function(/* Array */ handle){
|
974
|
+
// summary:
|
975
|
+
// Disconnect a subscribed function for a topic.
|
976
|
+
// handle: Array
|
977
|
+
// The return value from a subscribe call.
|
978
|
+
// example:
|
979
|
+
// var handle = subscribe("/some/topic", function(){});
|
980
|
+
// unsubscribe(handle);
|
981
|
+
|
982
|
+
var subs = cache[handle[0]],
|
983
|
+
callback = handle[1],
|
984
|
+
len = subs ? subs.length : 0;
|
985
|
+
|
986
|
+
while(len--){
|
987
|
+
if(subs[len] === callback){
|
988
|
+
subs.splice(len, 1);
|
989
|
+
}
|
990
|
+
}
|
991
|
+
};
|
992
|
+
|
993
|
+
};// moment.js
|
994
|
+
// version : 2.0.0
|
995
|
+
// author : Tim Wood
|
996
|
+
// license : MIT
|
997
|
+
// momentjs.com
|
998
|
+
|
999
|
+
(function (undefined) {
|
1000
|
+
|
1001
|
+
/************************************
|
1002
|
+
Constants
|
1003
|
+
************************************/
|
1004
|
+
|
1005
|
+
var moment,
|
1006
|
+
VERSION = "2.0.0",
|
1007
|
+
round = Math.round, i,
|
1008
|
+
// internal storage for language config files
|
1009
|
+
languages = {},
|
1010
|
+
|
1011
|
+
// check for nodeJS
|
1012
|
+
hasModule = (typeof module !== 'undefined' && module.exports),
|
1013
|
+
|
1014
|
+
// ASP.NET json date format regex
|
1015
|
+
aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
|
1016
|
+
|
1017
|
+
// format tokens
|
1018
|
+
formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,
|
1019
|
+
localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
|
1020
|
+
|
1021
|
+
// parsing tokens
|
1022
|
+
parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,
|
1023
|
+
|
1024
|
+
// parsing token regexes
|
1025
|
+
parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
|
1026
|
+
parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
|
1027
|
+
parseTokenThreeDigits = /\d{3}/, // 000 - 999
|
1028
|
+
parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
|
1029
|
+
parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
|
1030
|
+
parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic.
|
1031
|
+
parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
|
1032
|
+
parseTokenT = /T/i, // T (ISO seperator)
|
1033
|
+
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
|
1034
|
+
|
1035
|
+
// preliminary iso regex
|
1036
|
+
// 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
|
1037
|
+
isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,
|
1038
|
+
isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
|
1039
|
+
|
1040
|
+
// iso time formats and regexes
|
1041
|
+
isoTimes = [
|
1042
|
+
['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
|
1043
|
+
['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
|
1044
|
+
['HH:mm', /(T| )\d\d:\d\d/],
|
1045
|
+
['HH', /(T| )\d\d/]
|
1046
|
+
],
|
1047
|
+
|
1048
|
+
// timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
|
1049
|
+
parseTimezoneChunker = /([\+\-]|\d\d)/gi,
|
1050
|
+
|
1051
|
+
// getter and setter names
|
1052
|
+
proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
|
1053
|
+
unitMillisecondFactors = {
|
1054
|
+
'Milliseconds' : 1,
|
1055
|
+
'Seconds' : 1e3,
|
1056
|
+
'Minutes' : 6e4,
|
1057
|
+
'Hours' : 36e5,
|
1058
|
+
'Days' : 864e5,
|
1059
|
+
'Months' : 2592e6,
|
1060
|
+
'Years' : 31536e6
|
1061
|
+
},
|
1062
|
+
|
1063
|
+
// format function strings
|
1064
|
+
formatFunctions = {},
|
1065
|
+
|
1066
|
+
// tokens to ordinalize and pad
|
1067
|
+
ordinalizeTokens = 'DDD w W M D d'.split(' '),
|
1068
|
+
paddedTokens = 'M D H h m s w W'.split(' '),
|
1069
|
+
|
1070
|
+
formatTokenFunctions = {
|
1071
|
+
M : function () {
|
1072
|
+
return this.month() + 1;
|
1073
|
+
},
|
1074
|
+
MMM : function (format) {
|
1075
|
+
return this.lang().monthsShort(this, format);
|
1076
|
+
},
|
1077
|
+
MMMM : function (format) {
|
1078
|
+
return this.lang().months(this, format);
|
1079
|
+
},
|
1080
|
+
D : function () {
|
1081
|
+
return this.date();
|
1082
|
+
},
|
1083
|
+
DDD : function () {
|
1084
|
+
return this.dayOfYear();
|
1085
|
+
},
|
1086
|
+
d : function () {
|
1087
|
+
return this.day();
|
1088
|
+
},
|
1089
|
+
dd : function (format) {
|
1090
|
+
return this.lang().weekdaysMin(this, format);
|
1091
|
+
},
|
1092
|
+
ddd : function (format) {
|
1093
|
+
return this.lang().weekdaysShort(this, format);
|
1094
|
+
},
|
1095
|
+
dddd : function (format) {
|
1096
|
+
return this.lang().weekdays(this, format);
|
1097
|
+
},
|
1098
|
+
w : function () {
|
1099
|
+
return this.week();
|
1100
|
+
},
|
1101
|
+
W : function () {
|
1102
|
+
return this.isoWeek();
|
1103
|
+
},
|
1104
|
+
YY : function () {
|
1105
|
+
return leftZeroFill(this.year() % 100, 2);
|
1106
|
+
},
|
1107
|
+
YYYY : function () {
|
1108
|
+
return leftZeroFill(this.year(), 4);
|
1109
|
+
},
|
1110
|
+
YYYYY : function () {
|
1111
|
+
return leftZeroFill(this.year(), 5);
|
1112
|
+
},
|
1113
|
+
a : function () {
|
1114
|
+
return this.lang().meridiem(this.hours(), this.minutes(), true);
|
1115
|
+
},
|
1116
|
+
A : function () {
|
1117
|
+
return this.lang().meridiem(this.hours(), this.minutes(), false);
|
1118
|
+
},
|
1119
|
+
H : function () {
|
1120
|
+
return this.hours();
|
1121
|
+
},
|
1122
|
+
h : function () {
|
1123
|
+
return this.hours() % 12 || 12;
|
1124
|
+
},
|
1125
|
+
m : function () {
|
1126
|
+
return this.minutes();
|
1127
|
+
},
|
1128
|
+
s : function () {
|
1129
|
+
return this.seconds();
|
1130
|
+
},
|
1131
|
+
S : function () {
|
1132
|
+
return ~~(this.milliseconds() / 100);
|
1133
|
+
},
|
1134
|
+
SS : function () {
|
1135
|
+
return leftZeroFill(~~(this.milliseconds() / 10), 2);
|
1136
|
+
},
|
1137
|
+
SSS : function () {
|
1138
|
+
return leftZeroFill(this.milliseconds(), 3);
|
1139
|
+
},
|
1140
|
+
Z : function () {
|
1141
|
+
var a = -this.zone(),
|
1142
|
+
b = "+";
|
1143
|
+
if (a < 0) {
|
1144
|
+
a = -a;
|
1145
|
+
b = "-";
|
1146
|
+
}
|
1147
|
+
return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2);
|
1148
|
+
},
|
1149
|
+
ZZ : function () {
|
1150
|
+
var a = -this.zone(),
|
1151
|
+
b = "+";
|
1152
|
+
if (a < 0) {
|
1153
|
+
a = -a;
|
1154
|
+
b = "-";
|
1155
|
+
}
|
1156
|
+
return b + leftZeroFill(~~(10 * a / 6), 4);
|
1157
|
+
},
|
1158
|
+
X : function () {
|
1159
|
+
return this.unix();
|
1160
|
+
}
|
1161
|
+
};
|
1162
|
+
|
1163
|
+
function padToken(func, count) {
|
1164
|
+
return function (a) {
|
1165
|
+
return leftZeroFill(func.call(this, a), count);
|
1166
|
+
};
|
1167
|
+
}
|
1168
|
+
function ordinalizeToken(func) {
|
1169
|
+
return function (a) {
|
1170
|
+
return this.lang().ordinal(func.call(this, a));
|
1171
|
+
};
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
while (ordinalizeTokens.length) {
|
1175
|
+
i = ordinalizeTokens.pop();
|
1176
|
+
formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]);
|
1177
|
+
}
|
1178
|
+
while (paddedTokens.length) {
|
1179
|
+
i = paddedTokens.pop();
|
1180
|
+
formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
|
1181
|
+
}
|
1182
|
+
formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
|
1183
|
+
|
1184
|
+
|
1185
|
+
/************************************
|
1186
|
+
Constructors
|
1187
|
+
************************************/
|
1188
|
+
|
1189
|
+
function Language() {
|
1190
|
+
|
1191
|
+
}
|
1192
|
+
|
1193
|
+
// Moment prototype object
|
1194
|
+
function Moment(config) {
|
1195
|
+
extend(this, config);
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
// Duration Constructor
|
1199
|
+
function Duration(duration) {
|
1200
|
+
var data = this._data = {},
|
1201
|
+
years = duration.years || duration.year || duration.y || 0,
|
1202
|
+
months = duration.months || duration.month || duration.M || 0,
|
1203
|
+
weeks = duration.weeks || duration.week || duration.w || 0,
|
1204
|
+
days = duration.days || duration.day || duration.d || 0,
|
1205
|
+
hours = duration.hours || duration.hour || duration.h || 0,
|
1206
|
+
minutes = duration.minutes || duration.minute || duration.m || 0,
|
1207
|
+
seconds = duration.seconds || duration.second || duration.s || 0,
|
1208
|
+
milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;
|
1209
|
+
|
1210
|
+
// representation for dateAddRemove
|
1211
|
+
this._milliseconds = milliseconds +
|
1212
|
+
seconds * 1e3 + // 1000
|
1213
|
+
minutes * 6e4 + // 1000 * 60
|
1214
|
+
hours * 36e5; // 1000 * 60 * 60
|
1215
|
+
// Because of dateAddRemove treats 24 hours as different from a
|
1216
|
+
// day when working around DST, we need to store them separately
|
1217
|
+
this._days = days +
|
1218
|
+
weeks * 7;
|
1219
|
+
// It is impossible translate months into days without knowing
|
1220
|
+
// which months you are are talking about, so we have to store
|
1221
|
+
// it separately.
|
1222
|
+
this._months = months +
|
1223
|
+
years * 12;
|
1224
|
+
|
1225
|
+
// The following code bubbles up values, see the tests for
|
1226
|
+
// examples of what that means.
|
1227
|
+
data.milliseconds = milliseconds % 1000;
|
1228
|
+
seconds += absRound(milliseconds / 1000);
|
1229
|
+
|
1230
|
+
data.seconds = seconds % 60;
|
1231
|
+
minutes += absRound(seconds / 60);
|
1232
|
+
|
1233
|
+
data.minutes = minutes % 60;
|
1234
|
+
hours += absRound(minutes / 60);
|
1235
|
+
|
1236
|
+
data.hours = hours % 24;
|
1237
|
+
days += absRound(hours / 24);
|
1238
|
+
|
1239
|
+
days += weeks * 7;
|
1240
|
+
data.days = days % 30;
|
1241
|
+
|
1242
|
+
months += absRound(days / 30);
|
1243
|
+
|
1244
|
+
data.months = months % 12;
|
1245
|
+
years += absRound(months / 12);
|
1246
|
+
|
1247
|
+
data.years = years;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
|
1251
|
+
/************************************
|
1252
|
+
Helpers
|
1253
|
+
************************************/
|
1254
|
+
|
1255
|
+
|
1256
|
+
function extend(a, b) {
|
1257
|
+
for (var i in b) {
|
1258
|
+
if (b.hasOwnProperty(i)) {
|
1259
|
+
a[i] = b[i];
|
1260
|
+
}
|
1261
|
+
}
|
1262
|
+
return a;
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
function absRound(number) {
|
1266
|
+
if (number < 0) {
|
1267
|
+
return Math.ceil(number);
|
1268
|
+
} else {
|
1269
|
+
return Math.floor(number);
|
1270
|
+
}
|
1271
|
+
}
|
1272
|
+
|
1273
|
+
// left zero fill a number
|
1274
|
+
// see http://jsperf.com/left-zero-filling for performance comparison
|
1275
|
+
function leftZeroFill(number, targetLength) {
|
1276
|
+
var output = number + '';
|
1277
|
+
while (output.length < targetLength) {
|
1278
|
+
output = '0' + output;
|
1279
|
+
}
|
1280
|
+
return output;
|
1281
|
+
}
|
1282
|
+
|
1283
|
+
// helper function for _.addTime and _.subtractTime
|
1284
|
+
function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
|
1285
|
+
var ms = duration._milliseconds,
|
1286
|
+
d = duration._days,
|
1287
|
+
M = duration._months,
|
1288
|
+
currentDate;
|
1289
|
+
|
1290
|
+
if (ms) {
|
1291
|
+
mom._d.setTime(+mom + ms * isAdding);
|
1292
|
+
}
|
1293
|
+
if (d) {
|
1294
|
+
mom.date(mom.date() + d * isAdding);
|
1295
|
+
}
|
1296
|
+
if (M) {
|
1297
|
+
currentDate = mom.date();
|
1298
|
+
mom.date(1)
|
1299
|
+
.month(mom.month() + M * isAdding)
|
1300
|
+
.date(Math.min(currentDate, mom.daysInMonth()));
|
1301
|
+
}
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
// check if is an array
|
1305
|
+
function isArray(input) {
|
1306
|
+
return Object.prototype.toString.call(input) === '[object Array]';
|
1307
|
+
}
|
1308
|
+
|
1309
|
+
// compare two arrays, return the number of differences
|
1310
|
+
function compareArrays(array1, array2) {
|
1311
|
+
var len = Math.min(array1.length, array2.length),
|
1312
|
+
lengthDiff = Math.abs(array1.length - array2.length),
|
1313
|
+
diffs = 0,
|
1314
|
+
i;
|
1315
|
+
for (i = 0; i < len; i++) {
|
1316
|
+
if (~~array1[i] !== ~~array2[i]) {
|
1317
|
+
diffs++;
|
1318
|
+
}
|
1319
|
+
}
|
1320
|
+
return diffs + lengthDiff;
|
1321
|
+
}
|
1322
|
+
|
1323
|
+
|
1324
|
+
/************************************
|
1325
|
+
Languages
|
1326
|
+
************************************/
|
1327
|
+
|
1328
|
+
|
1329
|
+
Language.prototype = {
|
1330
|
+
set : function (config) {
|
1331
|
+
var prop, i;
|
1332
|
+
for (i in config) {
|
1333
|
+
prop = config[i];
|
1334
|
+
if (typeof prop === 'function') {
|
1335
|
+
this[i] = prop;
|
1336
|
+
} else {
|
1337
|
+
this['_' + i] = prop;
|
1338
|
+
}
|
1339
|
+
}
|
1340
|
+
},
|
1341
|
+
|
1342
|
+
_months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
|
1343
|
+
months : function (m) {
|
1344
|
+
return this._months[m.month()];
|
1345
|
+
},
|
1346
|
+
|
1347
|
+
_monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
|
1348
|
+
monthsShort : function (m) {
|
1349
|
+
return this._monthsShort[m.month()];
|
1350
|
+
},
|
1351
|
+
|
1352
|
+
monthsParse : function (monthName) {
|
1353
|
+
var i, mom, regex, output;
|
1354
|
+
|
1355
|
+
if (!this._monthsParse) {
|
1356
|
+
this._monthsParse = [];
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
for (i = 0; i < 12; i++) {
|
1360
|
+
// make the regex if we don't have it already
|
1361
|
+
if (!this._monthsParse[i]) {
|
1362
|
+
mom = moment([2000, i]);
|
1363
|
+
regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
|
1364
|
+
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
|
1365
|
+
}
|
1366
|
+
// test the regex
|
1367
|
+
if (this._monthsParse[i].test(monthName)) {
|
1368
|
+
return i;
|
1369
|
+
}
|
1370
|
+
}
|
1371
|
+
},
|
1372
|
+
|
1373
|
+
_weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
|
1374
|
+
weekdays : function (m) {
|
1375
|
+
return this._weekdays[m.day()];
|
1376
|
+
},
|
1377
|
+
|
1378
|
+
_weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
|
1379
|
+
weekdaysShort : function (m) {
|
1380
|
+
return this._weekdaysShort[m.day()];
|
1381
|
+
},
|
1382
|
+
|
1383
|
+
_weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
|
1384
|
+
weekdaysMin : function (m) {
|
1385
|
+
return this._weekdaysMin[m.day()];
|
1386
|
+
},
|
1387
|
+
|
1388
|
+
_longDateFormat : {
|
1389
|
+
LT : "h:mm A",
|
1390
|
+
L : "MM/DD/YYYY",
|
1391
|
+
LL : "MMMM D YYYY",
|
1392
|
+
LLL : "MMMM D YYYY LT",
|
1393
|
+
LLLL : "dddd, MMMM D YYYY LT"
|
1394
|
+
},
|
1395
|
+
longDateFormat : function (key) {
|
1396
|
+
var output = this._longDateFormat[key];
|
1397
|
+
if (!output && this._longDateFormat[key.toUpperCase()]) {
|
1398
|
+
output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
|
1399
|
+
return val.slice(1);
|
1400
|
+
});
|
1401
|
+
this._longDateFormat[key] = output;
|
1402
|
+
}
|
1403
|
+
return output;
|
1404
|
+
},
|
1405
|
+
|
1406
|
+
meridiem : function (hours, minutes, isLower) {
|
1407
|
+
if (hours > 11) {
|
1408
|
+
return isLower ? 'pm' : 'PM';
|
1409
|
+
} else {
|
1410
|
+
return isLower ? 'am' : 'AM';
|
1411
|
+
}
|
1412
|
+
},
|
1413
|
+
|
1414
|
+
_calendar : {
|
1415
|
+
sameDay : '[Today at] LT',
|
1416
|
+
nextDay : '[Tomorrow at] LT',
|
1417
|
+
nextWeek : 'dddd [at] LT',
|
1418
|
+
lastDay : '[Yesterday at] LT',
|
1419
|
+
lastWeek : '[last] dddd [at] LT',
|
1420
|
+
sameElse : 'L'
|
1421
|
+
},
|
1422
|
+
calendar : function (key, mom) {
|
1423
|
+
var output = this._calendar[key];
|
1424
|
+
return typeof output === 'function' ? output.apply(mom) : output;
|
1425
|
+
},
|
1426
|
+
|
1427
|
+
_relativeTime : {
|
1428
|
+
future : "in %s",
|
1429
|
+
past : "%s ago",
|
1430
|
+
s : "a few seconds",
|
1431
|
+
m : "a minute",
|
1432
|
+
mm : "%d minutes",
|
1433
|
+
h : "an hour",
|
1434
|
+
hh : "%d hours",
|
1435
|
+
d : "a day",
|
1436
|
+
dd : "%d days",
|
1437
|
+
M : "a month",
|
1438
|
+
MM : "%d months",
|
1439
|
+
y : "a year",
|
1440
|
+
yy : "%d years"
|
1441
|
+
},
|
1442
|
+
relativeTime : function (number, withoutSuffix, string, isFuture) {
|
1443
|
+
var output = this._relativeTime[string];
|
1444
|
+
return (typeof output === 'function') ?
|
1445
|
+
output(number, withoutSuffix, string, isFuture) :
|
1446
|
+
output.replace(/%d/i, number);
|
1447
|
+
},
|
1448
|
+
pastFuture : function (diff, output) {
|
1449
|
+
var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
|
1450
|
+
return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
|
1451
|
+
},
|
1452
|
+
|
1453
|
+
ordinal : function (number) {
|
1454
|
+
return this._ordinal.replace("%d", number);
|
1455
|
+
},
|
1456
|
+
_ordinal : "%d",
|
1457
|
+
|
1458
|
+
preparse : function (string) {
|
1459
|
+
return string;
|
1460
|
+
},
|
1461
|
+
|
1462
|
+
postformat : function (string) {
|
1463
|
+
return string;
|
1464
|
+
},
|
1465
|
+
|
1466
|
+
week : function (mom) {
|
1467
|
+
return weekOfYear(mom, this._week.dow, this._week.doy);
|
1468
|
+
},
|
1469
|
+
_week : {
|
1470
|
+
dow : 0, // Sunday is the first day of the week.
|
1471
|
+
doy : 6 // The week that contains Jan 1st is the first week of the year.
|
1472
|
+
}
|
1473
|
+
};
|
1474
|
+
|
1475
|
+
// Loads a language definition into the `languages` cache. The function
|
1476
|
+
// takes a key and optionally values. If not in the browser and no values
|
1477
|
+
// are provided, it will load the language file module. As a convenience,
|
1478
|
+
// this function also returns the language values.
|
1479
|
+
function loadLang(key, values) {
|
1480
|
+
values.abbr = key;
|
1481
|
+
if (!languages[key]) {
|
1482
|
+
languages[key] = new Language();
|
1483
|
+
}
|
1484
|
+
languages[key].set(values);
|
1485
|
+
return languages[key];
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
// Determines which language definition to use and returns it.
|
1489
|
+
//
|
1490
|
+
// With no parameters, it will return the global language. If you
|
1491
|
+
// pass in a language key, such as 'en', it will return the
|
1492
|
+
// definition for 'en', so long as 'en' has already been loaded using
|
1493
|
+
// moment.lang.
|
1494
|
+
function getLangDefinition(key) {
|
1495
|
+
if (!key) {
|
1496
|
+
return moment.fn._lang;
|
1497
|
+
}
|
1498
|
+
if (!languages[key] && hasModule) {
|
1499
|
+
require('./lang/' + key);
|
1500
|
+
}
|
1501
|
+
return languages[key];
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
|
1505
|
+
/************************************
|
1506
|
+
Formatting
|
1507
|
+
************************************/
|
1508
|
+
|
1509
|
+
|
1510
|
+
function removeFormattingTokens(input) {
|
1511
|
+
if (input.match(/\[.*\]/)) {
|
1512
|
+
return input.replace(/^\[|\]$/g, "");
|
1513
|
+
}
|
1514
|
+
return input.replace(/\\/g, "");
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
function makeFormatFunction(format) {
|
1518
|
+
var array = format.match(formattingTokens), i, length;
|
1519
|
+
|
1520
|
+
for (i = 0, length = array.length; i < length; i++) {
|
1521
|
+
if (formatTokenFunctions[array[i]]) {
|
1522
|
+
array[i] = formatTokenFunctions[array[i]];
|
1523
|
+
} else {
|
1524
|
+
array[i] = removeFormattingTokens(array[i]);
|
1525
|
+
}
|
1526
|
+
}
|
1527
|
+
|
1528
|
+
return function (mom) {
|
1529
|
+
var output = "";
|
1530
|
+
for (i = 0; i < length; i++) {
|
1531
|
+
output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i];
|
1532
|
+
}
|
1533
|
+
return output;
|
1534
|
+
};
|
1535
|
+
}
|
1536
|
+
|
1537
|
+
// format date using native date object
|
1538
|
+
function formatMoment(m, format) {
|
1539
|
+
var i = 5;
|
1540
|
+
|
1541
|
+
function replaceLongDateFormatTokens(input) {
|
1542
|
+
return m.lang().longDateFormat(input) || input;
|
1543
|
+
}
|
1544
|
+
|
1545
|
+
while (i-- && localFormattingTokens.test(format)) {
|
1546
|
+
format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
|
1547
|
+
}
|
1548
|
+
|
1549
|
+
if (!formatFunctions[format]) {
|
1550
|
+
formatFunctions[format] = makeFormatFunction(format);
|
1551
|
+
}
|
1552
|
+
|
1553
|
+
return formatFunctions[format](m);
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
|
1557
|
+
/************************************
|
1558
|
+
Parsing
|
1559
|
+
************************************/
|
1560
|
+
|
1561
|
+
|
1562
|
+
// get the regex to find the next token
|
1563
|
+
function getParseRegexForToken(token) {
|
1564
|
+
switch (token) {
|
1565
|
+
case 'DDDD':
|
1566
|
+
return parseTokenThreeDigits;
|
1567
|
+
case 'YYYY':
|
1568
|
+
return parseTokenFourDigits;
|
1569
|
+
case 'YYYYY':
|
1570
|
+
return parseTokenSixDigits;
|
1571
|
+
case 'S':
|
1572
|
+
case 'SS':
|
1573
|
+
case 'SSS':
|
1574
|
+
case 'DDD':
|
1575
|
+
return parseTokenOneToThreeDigits;
|
1576
|
+
case 'MMM':
|
1577
|
+
case 'MMMM':
|
1578
|
+
case 'dd':
|
1579
|
+
case 'ddd':
|
1580
|
+
case 'dddd':
|
1581
|
+
case 'a':
|
1582
|
+
case 'A':
|
1583
|
+
return parseTokenWord;
|
1584
|
+
case 'X':
|
1585
|
+
return parseTokenTimestampMs;
|
1586
|
+
case 'Z':
|
1587
|
+
case 'ZZ':
|
1588
|
+
return parseTokenTimezone;
|
1589
|
+
case 'T':
|
1590
|
+
return parseTokenT;
|
1591
|
+
case 'MM':
|
1592
|
+
case 'DD':
|
1593
|
+
case 'YY':
|
1594
|
+
case 'HH':
|
1595
|
+
case 'hh':
|
1596
|
+
case 'mm':
|
1597
|
+
case 'ss':
|
1598
|
+
case 'M':
|
1599
|
+
case 'D':
|
1600
|
+
case 'd':
|
1601
|
+
case 'H':
|
1602
|
+
case 'h':
|
1603
|
+
case 'm':
|
1604
|
+
case 's':
|
1605
|
+
return parseTokenOneOrTwoDigits;
|
1606
|
+
default :
|
1607
|
+
return new RegExp(token.replace('\\', ''));
|
1608
|
+
}
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
// function to convert string input to date
|
1612
|
+
function addTimeToArrayFromToken(token, input, config) {
|
1613
|
+
var a, b,
|
1614
|
+
datePartArray = config._a;
|
1615
|
+
|
1616
|
+
switch (token) {
|
1617
|
+
// MONTH
|
1618
|
+
case 'M' : // fall through to MM
|
1619
|
+
case 'MM' :
|
1620
|
+
datePartArray[1] = (input == null) ? 0 : ~~input - 1;
|
1621
|
+
break;
|
1622
|
+
case 'MMM' : // fall through to MMMM
|
1623
|
+
case 'MMMM' :
|
1624
|
+
a = getLangDefinition(config._l).monthsParse(input);
|
1625
|
+
// if we didn't find a month name, mark the date as invalid.
|
1626
|
+
if (a != null) {
|
1627
|
+
datePartArray[1] = a;
|
1628
|
+
} else {
|
1629
|
+
config._isValid = false;
|
1630
|
+
}
|
1631
|
+
break;
|
1632
|
+
// DAY OF MONTH
|
1633
|
+
case 'D' : // fall through to DDDD
|
1634
|
+
case 'DD' : // fall through to DDDD
|
1635
|
+
case 'DDD' : // fall through to DDDD
|
1636
|
+
case 'DDDD' :
|
1637
|
+
if (input != null) {
|
1638
|
+
datePartArray[2] = ~~input;
|
1639
|
+
}
|
1640
|
+
break;
|
1641
|
+
// YEAR
|
1642
|
+
case 'YY' :
|
1643
|
+
datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000);
|
1644
|
+
break;
|
1645
|
+
case 'YYYY' :
|
1646
|
+
case 'YYYYY' :
|
1647
|
+
datePartArray[0] = ~~input;
|
1648
|
+
break;
|
1649
|
+
// AM / PM
|
1650
|
+
case 'a' : // fall through to A
|
1651
|
+
case 'A' :
|
1652
|
+
config._isPm = ((input + '').toLowerCase() === 'pm');
|
1653
|
+
break;
|
1654
|
+
// 24 HOUR
|
1655
|
+
case 'H' : // fall through to hh
|
1656
|
+
case 'HH' : // fall through to hh
|
1657
|
+
case 'h' : // fall through to hh
|
1658
|
+
case 'hh' :
|
1659
|
+
datePartArray[3] = ~~input;
|
1660
|
+
break;
|
1661
|
+
// MINUTE
|
1662
|
+
case 'm' : // fall through to mm
|
1663
|
+
case 'mm' :
|
1664
|
+
datePartArray[4] = ~~input;
|
1665
|
+
break;
|
1666
|
+
// SECOND
|
1667
|
+
case 's' : // fall through to ss
|
1668
|
+
case 'ss' :
|
1669
|
+
datePartArray[5] = ~~input;
|
1670
|
+
break;
|
1671
|
+
// MILLISECOND
|
1672
|
+
case 'S' :
|
1673
|
+
case 'SS' :
|
1674
|
+
case 'SSS' :
|
1675
|
+
datePartArray[6] = ~~ (('0.' + input) * 1000);
|
1676
|
+
break;
|
1677
|
+
// UNIX TIMESTAMP WITH MS
|
1678
|
+
case 'X':
|
1679
|
+
config._d = new Date(parseFloat(input) * 1000);
|
1680
|
+
break;
|
1681
|
+
// TIMEZONE
|
1682
|
+
case 'Z' : // fall through to ZZ
|
1683
|
+
case 'ZZ' :
|
1684
|
+
config._useUTC = true;
|
1685
|
+
a = (input + '').match(parseTimezoneChunker);
|
1686
|
+
if (a && a[1]) {
|
1687
|
+
config._tzh = ~~a[1];
|
1688
|
+
}
|
1689
|
+
if (a && a[2]) {
|
1690
|
+
config._tzm = ~~a[2];
|
1691
|
+
}
|
1692
|
+
// reverse offsets
|
1693
|
+
if (a && a[0] === '+') {
|
1694
|
+
config._tzh = -config._tzh;
|
1695
|
+
config._tzm = -config._tzm;
|
1696
|
+
}
|
1697
|
+
break;
|
1698
|
+
}
|
1699
|
+
|
1700
|
+
// if the input is null, the date is not valid
|
1701
|
+
if (input == null) {
|
1702
|
+
config._isValid = false;
|
1703
|
+
}
|
1704
|
+
}
|
1705
|
+
|
1706
|
+
// convert an array to a date.
|
1707
|
+
// the array should mirror the parameters below
|
1708
|
+
// note: all values past the year are optional and will default to the lowest possible value.
|
1709
|
+
// [year, month, day , hour, minute, second, millisecond]
|
1710
|
+
function dateFromArray(config) {
|
1711
|
+
var i, date, input = [];
|
1712
|
+
|
1713
|
+
if (config._d) {
|
1714
|
+
return;
|
1715
|
+
}
|
1716
|
+
|
1717
|
+
for (i = 0; i < 7; i++) {
|
1718
|
+
config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
|
1719
|
+
}
|
1720
|
+
|
1721
|
+
// add the offsets to the time to be parsed so that we can have a clean array for checking isValid
|
1722
|
+
input[3] += config._tzh || 0;
|
1723
|
+
input[4] += config._tzm || 0;
|
1724
|
+
|
1725
|
+
date = new Date(0);
|
1726
|
+
|
1727
|
+
if (config._useUTC) {
|
1728
|
+
date.setUTCFullYear(input[0], input[1], input[2]);
|
1729
|
+
date.setUTCHours(input[3], input[4], input[5], input[6]);
|
1730
|
+
} else {
|
1731
|
+
date.setFullYear(input[0], input[1], input[2]);
|
1732
|
+
date.setHours(input[3], input[4], input[5], input[6]);
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
config._d = date;
|
1736
|
+
}
|
1737
|
+
|
1738
|
+
// date from string and format string
|
1739
|
+
function makeDateFromStringAndFormat(config) {
|
1740
|
+
// This array is used to make a Date, either with `new Date` or `Date.UTC`
|
1741
|
+
var tokens = config._f.match(formattingTokens),
|
1742
|
+
string = config._i,
|
1743
|
+
i, parsedInput;
|
1744
|
+
|
1745
|
+
config._a = [];
|
1746
|
+
|
1747
|
+
for (i = 0; i < tokens.length; i++) {
|
1748
|
+
parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0];
|
1749
|
+
if (parsedInput) {
|
1750
|
+
string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
|
1751
|
+
}
|
1752
|
+
// don't parse if its not a known token
|
1753
|
+
if (formatTokenFunctions[tokens[i]]) {
|
1754
|
+
addTimeToArrayFromToken(tokens[i], parsedInput, config);
|
1755
|
+
}
|
1756
|
+
}
|
1757
|
+
// handle am pm
|
1758
|
+
if (config._isPm && config._a[3] < 12) {
|
1759
|
+
config._a[3] += 12;
|
1760
|
+
}
|
1761
|
+
// if is 12 am, change hours to 0
|
1762
|
+
if (config._isPm === false && config._a[3] === 12) {
|
1763
|
+
config._a[3] = 0;
|
1764
|
+
}
|
1765
|
+
// return
|
1766
|
+
dateFromArray(config);
|
1767
|
+
}
|
1768
|
+
|
1769
|
+
// date from string and array of format strings
|
1770
|
+
function makeDateFromStringAndArray(config) {
|
1771
|
+
var tempConfig,
|
1772
|
+
tempMoment,
|
1773
|
+
bestMoment,
|
1774
|
+
|
1775
|
+
scoreToBeat = 99,
|
1776
|
+
i,
|
1777
|
+
currentDate,
|
1778
|
+
currentScore;
|
1779
|
+
|
1780
|
+
while (config._f.length) {
|
1781
|
+
tempConfig = extend({}, config);
|
1782
|
+
tempConfig._f = config._f.pop();
|
1783
|
+
makeDateFromStringAndFormat(tempConfig);
|
1784
|
+
tempMoment = new Moment(tempConfig);
|
1785
|
+
|
1786
|
+
if (tempMoment.isValid()) {
|
1787
|
+
bestMoment = tempMoment;
|
1788
|
+
break;
|
1789
|
+
}
|
1790
|
+
|
1791
|
+
currentScore = compareArrays(tempConfig._a, tempMoment.toArray());
|
1792
|
+
|
1793
|
+
if (currentScore < scoreToBeat) {
|
1794
|
+
scoreToBeat = currentScore;
|
1795
|
+
bestMoment = tempMoment;
|
1796
|
+
}
|
1797
|
+
}
|
1798
|
+
|
1799
|
+
extend(config, bestMoment);
|
1800
|
+
}
|
1801
|
+
|
1802
|
+
// date from iso format
|
1803
|
+
function makeDateFromString(config) {
|
1804
|
+
var i,
|
1805
|
+
string = config._i;
|
1806
|
+
if (isoRegex.exec(string)) {
|
1807
|
+
config._f = 'YYYY-MM-DDT';
|
1808
|
+
for (i = 0; i < 4; i++) {
|
1809
|
+
if (isoTimes[i][1].exec(string)) {
|
1810
|
+
config._f += isoTimes[i][0];
|
1811
|
+
break;
|
1812
|
+
}
|
1813
|
+
}
|
1814
|
+
if (parseTokenTimezone.exec(string)) {
|
1815
|
+
config._f += " Z";
|
1816
|
+
}
|
1817
|
+
makeDateFromStringAndFormat(config);
|
1818
|
+
} else {
|
1819
|
+
config._d = new Date(string);
|
1820
|
+
}
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
function makeDateFromInput(config) {
|
1824
|
+
var input = config._i,
|
1825
|
+
matched = aspNetJsonRegex.exec(input);
|
1826
|
+
|
1827
|
+
if (input === undefined) {
|
1828
|
+
config._d = new Date();
|
1829
|
+
} else if (matched) {
|
1830
|
+
config._d = new Date(+matched[1]);
|
1831
|
+
} else if (typeof input === 'string') {
|
1832
|
+
makeDateFromString(config);
|
1833
|
+
} else if (isArray(input)) {
|
1834
|
+
config._a = input.slice(0);
|
1835
|
+
dateFromArray(config);
|
1836
|
+
} else {
|
1837
|
+
config._d = input instanceof Date ? new Date(+input) : new Date(input);
|
1838
|
+
}
|
1839
|
+
}
|
1840
|
+
|
1841
|
+
|
1842
|
+
/************************************
|
1843
|
+
Relative Time
|
1844
|
+
************************************/
|
1845
|
+
|
1846
|
+
|
1847
|
+
// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
|
1848
|
+
function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
|
1849
|
+
return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
|
1850
|
+
}
|
1851
|
+
|
1852
|
+
function relativeTime(milliseconds, withoutSuffix, lang) {
|
1853
|
+
var seconds = round(Math.abs(milliseconds) / 1000),
|
1854
|
+
minutes = round(seconds / 60),
|
1855
|
+
hours = round(minutes / 60),
|
1856
|
+
days = round(hours / 24),
|
1857
|
+
years = round(days / 365),
|
1858
|
+
args = seconds < 45 && ['s', seconds] ||
|
1859
|
+
minutes === 1 && ['m'] ||
|
1860
|
+
minutes < 45 && ['mm', minutes] ||
|
1861
|
+
hours === 1 && ['h'] ||
|
1862
|
+
hours < 22 && ['hh', hours] ||
|
1863
|
+
days === 1 && ['d'] ||
|
1864
|
+
days <= 25 && ['dd', days] ||
|
1865
|
+
days <= 45 && ['M'] ||
|
1866
|
+
days < 345 && ['MM', round(days / 30)] ||
|
1867
|
+
years === 1 && ['y'] || ['yy', years];
|
1868
|
+
args[2] = withoutSuffix;
|
1869
|
+
args[3] = milliseconds > 0;
|
1870
|
+
args[4] = lang;
|
1871
|
+
return substituteTimeAgo.apply({}, args);
|
1872
|
+
}
|
1873
|
+
|
1874
|
+
|
1875
|
+
/************************************
|
1876
|
+
Week of Year
|
1877
|
+
************************************/
|
1878
|
+
|
1879
|
+
|
1880
|
+
// firstDayOfWeek 0 = sun, 6 = sat
|
1881
|
+
// the day of the week that starts the week
|
1882
|
+
// (usually sunday or monday)
|
1883
|
+
// firstDayOfWeekOfYear 0 = sun, 6 = sat
|
1884
|
+
// the first week is the week that contains the first
|
1885
|
+
// of this day of the week
|
1886
|
+
// (eg. ISO weeks use thursday (4))
|
1887
|
+
function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
|
1888
|
+
var end = firstDayOfWeekOfYear - firstDayOfWeek,
|
1889
|
+
daysToDayOfWeek = firstDayOfWeekOfYear - mom.day();
|
1890
|
+
|
1891
|
+
|
1892
|
+
if (daysToDayOfWeek > end) {
|
1893
|
+
daysToDayOfWeek -= 7;
|
1894
|
+
}
|
1895
|
+
|
1896
|
+
if (daysToDayOfWeek < end - 7) {
|
1897
|
+
daysToDayOfWeek += 7;
|
1898
|
+
}
|
1899
|
+
|
1900
|
+
return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7);
|
1901
|
+
}
|
1902
|
+
|
1903
|
+
|
1904
|
+
/************************************
|
1905
|
+
Top Level Functions
|
1906
|
+
************************************/
|
1907
|
+
|
1908
|
+
function makeMoment(config) {
|
1909
|
+
var input = config._i,
|
1910
|
+
format = config._f;
|
1911
|
+
|
1912
|
+
if (input === null || input === '') {
|
1913
|
+
return null;
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
if (typeof input === 'string') {
|
1917
|
+
config._i = input = getLangDefinition().preparse(input);
|
1918
|
+
}
|
1919
|
+
|
1920
|
+
if (moment.isMoment(input)) {
|
1921
|
+
config = extend({}, input);
|
1922
|
+
config._d = new Date(+input._d);
|
1923
|
+
} else if (format) {
|
1924
|
+
if (isArray(format)) {
|
1925
|
+
makeDateFromStringAndArray(config);
|
1926
|
+
} else {
|
1927
|
+
makeDateFromStringAndFormat(config);
|
1928
|
+
}
|
1929
|
+
} else {
|
1930
|
+
makeDateFromInput(config);
|
1931
|
+
}
|
1932
|
+
|
1933
|
+
return new Moment(config);
|
1934
|
+
}
|
1935
|
+
|
1936
|
+
moment = function (input, format, lang) {
|
1937
|
+
return makeMoment({
|
1938
|
+
_i : input,
|
1939
|
+
_f : format,
|
1940
|
+
_l : lang,
|
1941
|
+
_isUTC : false
|
1942
|
+
});
|
1943
|
+
};
|
1944
|
+
|
1945
|
+
// creating with utc
|
1946
|
+
moment.utc = function (input, format, lang) {
|
1947
|
+
return makeMoment({
|
1948
|
+
_useUTC : true,
|
1949
|
+
_isUTC : true,
|
1950
|
+
_l : lang,
|
1951
|
+
_i : input,
|
1952
|
+
_f : format
|
1953
|
+
});
|
1954
|
+
};
|
1955
|
+
|
1956
|
+
// creating with unix timestamp (in seconds)
|
1957
|
+
moment.unix = function (input) {
|
1958
|
+
return moment(input * 1000);
|
1959
|
+
};
|
1960
|
+
|
1961
|
+
// duration
|
1962
|
+
moment.duration = function (input, key) {
|
1963
|
+
var isDuration = moment.isDuration(input),
|
1964
|
+
isNumber = (typeof input === 'number'),
|
1965
|
+
duration = (isDuration ? input._data : (isNumber ? {} : input)),
|
1966
|
+
ret;
|
1967
|
+
|
1968
|
+
if (isNumber) {
|
1969
|
+
if (key) {
|
1970
|
+
duration[key] = input;
|
1971
|
+
} else {
|
1972
|
+
duration.milliseconds = input;
|
1973
|
+
}
|
1974
|
+
}
|
1975
|
+
|
1976
|
+
ret = new Duration(duration);
|
1977
|
+
|
1978
|
+
if (isDuration && input.hasOwnProperty('_lang')) {
|
1979
|
+
ret._lang = input._lang;
|
1980
|
+
}
|
1981
|
+
|
1982
|
+
return ret;
|
1983
|
+
};
|
1984
|
+
|
1985
|
+
// version number
|
1986
|
+
moment.version = VERSION;
|
1987
|
+
|
1988
|
+
// default format
|
1989
|
+
moment.defaultFormat = isoFormat;
|
1990
|
+
|
1991
|
+
// This function will load languages and then set the global language. If
|
1992
|
+
// no arguments are passed in, it will simply return the current global
|
1993
|
+
// language key.
|
1994
|
+
moment.lang = function (key, values) {
|
1995
|
+
var i;
|
1996
|
+
|
1997
|
+
if (!key) {
|
1998
|
+
return moment.fn._lang._abbr;
|
1999
|
+
}
|
2000
|
+
if (values) {
|
2001
|
+
loadLang(key, values);
|
2002
|
+
} else if (!languages[key]) {
|
2003
|
+
getLangDefinition(key);
|
2004
|
+
}
|
2005
|
+
moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
|
2006
|
+
};
|
2007
|
+
|
2008
|
+
// returns language data
|
2009
|
+
moment.langData = function (key) {
|
2010
|
+
if (key && key._lang && key._lang._abbr) {
|
2011
|
+
key = key._lang._abbr;
|
2012
|
+
}
|
2013
|
+
return getLangDefinition(key);
|
2014
|
+
};
|
2015
|
+
|
2016
|
+
// compare moment object
|
2017
|
+
moment.isMoment = function (obj) {
|
2018
|
+
return obj instanceof Moment;
|
2019
|
+
};
|
2020
|
+
|
2021
|
+
// for typechecking Duration objects
|
2022
|
+
moment.isDuration = function (obj) {
|
2023
|
+
return obj instanceof Duration;
|
2024
|
+
};
|
2025
|
+
|
2026
|
+
|
2027
|
+
/************************************
|
2028
|
+
Moment Prototype
|
2029
|
+
************************************/
|
2030
|
+
|
2031
|
+
|
2032
|
+
moment.fn = Moment.prototype = {
|
2033
|
+
|
2034
|
+
clone : function () {
|
2035
|
+
return moment(this);
|
2036
|
+
},
|
2037
|
+
|
2038
|
+
valueOf : function () {
|
2039
|
+
return +this._d;
|
2040
|
+
},
|
2041
|
+
|
2042
|
+
unix : function () {
|
2043
|
+
return Math.floor(+this._d / 1000);
|
2044
|
+
},
|
2045
|
+
|
2046
|
+
toString : function () {
|
2047
|
+
return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
|
2048
|
+
},
|
2049
|
+
|
2050
|
+
toDate : function () {
|
2051
|
+
return this._d;
|
2052
|
+
},
|
2053
|
+
|
2054
|
+
toJSON : function () {
|
2055
|
+
return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
|
2056
|
+
},
|
2057
|
+
|
2058
|
+
toArray : function () {
|
2059
|
+
var m = this;
|
2060
|
+
return [
|
2061
|
+
m.year(),
|
2062
|
+
m.month(),
|
2063
|
+
m.date(),
|
2064
|
+
m.hours(),
|
2065
|
+
m.minutes(),
|
2066
|
+
m.seconds(),
|
2067
|
+
m.milliseconds()
|
2068
|
+
];
|
2069
|
+
},
|
2070
|
+
|
2071
|
+
isValid : function () {
|
2072
|
+
if (this._isValid == null) {
|
2073
|
+
if (this._a) {
|
2074
|
+
this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
|
2075
|
+
} else {
|
2076
|
+
this._isValid = !isNaN(this._d.getTime());
|
2077
|
+
}
|
2078
|
+
}
|
2079
|
+
return !!this._isValid;
|
2080
|
+
},
|
2081
|
+
|
2082
|
+
utc : function () {
|
2083
|
+
this._isUTC = true;
|
2084
|
+
return this;
|
2085
|
+
},
|
2086
|
+
|
2087
|
+
local : function () {
|
2088
|
+
this._isUTC = false;
|
2089
|
+
return this;
|
2090
|
+
},
|
2091
|
+
|
2092
|
+
format : function (inputString) {
|
2093
|
+
var output = formatMoment(this, inputString || moment.defaultFormat);
|
2094
|
+
return this.lang().postformat(output);
|
2095
|
+
},
|
2096
|
+
|
2097
|
+
add : function (input, val) {
|
2098
|
+
var dur;
|
2099
|
+
// switch args to support add('s', 1) and add(1, 's')
|
2100
|
+
if (typeof input === 'string') {
|
2101
|
+
dur = moment.duration(+val, input);
|
2102
|
+
} else {
|
2103
|
+
dur = moment.duration(input, val);
|
2104
|
+
}
|
2105
|
+
addOrSubtractDurationFromMoment(this, dur, 1);
|
2106
|
+
return this;
|
2107
|
+
},
|
2108
|
+
|
2109
|
+
subtract : function (input, val) {
|
2110
|
+
var dur;
|
2111
|
+
// switch args to support subtract('s', 1) and subtract(1, 's')
|
2112
|
+
if (typeof input === 'string') {
|
2113
|
+
dur = moment.duration(+val, input);
|
2114
|
+
} else {
|
2115
|
+
dur = moment.duration(input, val);
|
2116
|
+
}
|
2117
|
+
addOrSubtractDurationFromMoment(this, dur, -1);
|
2118
|
+
return this;
|
2119
|
+
},
|
2120
|
+
|
2121
|
+
diff : function (input, units, asFloat) {
|
2122
|
+
var that = this._isUTC ? moment(input).utc() : moment(input).local(),
|
2123
|
+
zoneDiff = (this.zone() - that.zone()) * 6e4,
|
2124
|
+
diff, output;
|
2125
|
+
|
2126
|
+
if (units) {
|
2127
|
+
// standardize on singular form
|
2128
|
+
units = units.replace(/s$/, '');
|
2129
|
+
}
|
2130
|
+
|
2131
|
+
if (units === 'year' || units === 'month') {
|
2132
|
+
diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
|
2133
|
+
output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
|
2134
|
+
output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff;
|
2135
|
+
if (units === 'year') {
|
2136
|
+
output = output / 12;
|
2137
|
+
}
|
2138
|
+
} else {
|
2139
|
+
diff = (this - that) - zoneDiff;
|
2140
|
+
output = units === 'second' ? diff / 1e3 : // 1000
|
2141
|
+
units === 'minute' ? diff / 6e4 : // 1000 * 60
|
2142
|
+
units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
|
2143
|
+
units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24
|
2144
|
+
units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
|
2145
|
+
diff;
|
2146
|
+
}
|
2147
|
+
return asFloat ? output : absRound(output);
|
2148
|
+
},
|
2149
|
+
|
2150
|
+
from : function (time, withoutSuffix) {
|
2151
|
+
return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
|
2152
|
+
},
|
2153
|
+
|
2154
|
+
fromNow : function (withoutSuffix) {
|
2155
|
+
return this.from(moment(), withoutSuffix);
|
2156
|
+
},
|
2157
|
+
|
2158
|
+
calendar : function () {
|
2159
|
+
var diff = this.diff(moment().startOf('day'), 'days', true),
|
2160
|
+
format = diff < -6 ? 'sameElse' :
|
2161
|
+
diff < -1 ? 'lastWeek' :
|
2162
|
+
diff < 0 ? 'lastDay' :
|
2163
|
+
diff < 1 ? 'sameDay' :
|
2164
|
+
diff < 2 ? 'nextDay' :
|
2165
|
+
diff < 7 ? 'nextWeek' : 'sameElse';
|
2166
|
+
return this.format(this.lang().calendar(format, this));
|
2167
|
+
},
|
2168
|
+
|
2169
|
+
isLeapYear : function () {
|
2170
|
+
var year = this.year();
|
2171
|
+
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
2172
|
+
},
|
2173
|
+
|
2174
|
+
isDST : function () {
|
2175
|
+
return (this.zone() < moment([this.year()]).zone() ||
|
2176
|
+
this.zone() < moment([this.year(), 5]).zone());
|
2177
|
+
},
|
2178
|
+
|
2179
|
+
day : function (input) {
|
2180
|
+
var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
|
2181
|
+
return input == null ? day :
|
2182
|
+
this.add({ d : input - day });
|
2183
|
+
},
|
2184
|
+
|
2185
|
+
startOf: function (units) {
|
2186
|
+
units = units.replace(/s$/, '');
|
2187
|
+
// the following switch intentionally omits break keywords
|
2188
|
+
// to utilize falling through the cases.
|
2189
|
+
switch (units) {
|
2190
|
+
case 'year':
|
2191
|
+
this.month(0);
|
2192
|
+
/* falls through */
|
2193
|
+
case 'month':
|
2194
|
+
this.date(1);
|
2195
|
+
/* falls through */
|
2196
|
+
case 'week':
|
2197
|
+
case 'day':
|
2198
|
+
this.hours(0);
|
2199
|
+
/* falls through */
|
2200
|
+
case 'hour':
|
2201
|
+
this.minutes(0);
|
2202
|
+
/* falls through */
|
2203
|
+
case 'minute':
|
2204
|
+
this.seconds(0);
|
2205
|
+
/* falls through */
|
2206
|
+
case 'second':
|
2207
|
+
this.milliseconds(0);
|
2208
|
+
/* falls through */
|
2209
|
+
}
|
2210
|
+
|
2211
|
+
// weeks are a special case
|
2212
|
+
if (units === 'week') {
|
2213
|
+
this.day(0);
|
2214
|
+
}
|
2215
|
+
|
2216
|
+
return this;
|
2217
|
+
},
|
2218
|
+
|
2219
|
+
endOf: function (units) {
|
2220
|
+
return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1);
|
2221
|
+
},
|
2222
|
+
|
2223
|
+
isAfter: function (input, units) {
|
2224
|
+
units = typeof units !== 'undefined' ? units : 'millisecond';
|
2225
|
+
return +this.clone().startOf(units) > +moment(input).startOf(units);
|
2226
|
+
},
|
2227
|
+
|
2228
|
+
isBefore: function (input, units) {
|
2229
|
+
units = typeof units !== 'undefined' ? units : 'millisecond';
|
2230
|
+
return +this.clone().startOf(units) < +moment(input).startOf(units);
|
2231
|
+
},
|
2232
|
+
|
2233
|
+
isSame: function (input, units) {
|
2234
|
+
units = typeof units !== 'undefined' ? units : 'millisecond';
|
2235
|
+
return +this.clone().startOf(units) === +moment(input).startOf(units);
|
2236
|
+
},
|
2237
|
+
|
2238
|
+
zone : function () {
|
2239
|
+
return this._isUTC ? 0 : this._d.getTimezoneOffset();
|
2240
|
+
},
|
2241
|
+
|
2242
|
+
daysInMonth : function () {
|
2243
|
+
return moment.utc([this.year(), this.month() + 1, 0]).date();
|
2244
|
+
},
|
2245
|
+
|
2246
|
+
dayOfYear : function (input) {
|
2247
|
+
var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
|
2248
|
+
return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
|
2249
|
+
},
|
2250
|
+
|
2251
|
+
isoWeek : function (input) {
|
2252
|
+
var week = weekOfYear(this, 1, 4);
|
2253
|
+
return input == null ? week : this.add("d", (input - week) * 7);
|
2254
|
+
},
|
2255
|
+
|
2256
|
+
week : function (input) {
|
2257
|
+
var week = this.lang().week(this);
|
2258
|
+
return input == null ? week : this.add("d", (input - week) * 7);
|
2259
|
+
},
|
2260
|
+
|
2261
|
+
// If passed a language key, it will set the language for this
|
2262
|
+
// instance. Otherwise, it will return the language configuration
|
2263
|
+
// variables for this instance.
|
2264
|
+
lang : function (key) {
|
2265
|
+
if (key === undefined) {
|
2266
|
+
return this._lang;
|
2267
|
+
} else {
|
2268
|
+
this._lang = getLangDefinition(key);
|
2269
|
+
return this;
|
2270
|
+
}
|
2271
|
+
}
|
2272
|
+
};
|
2273
|
+
|
2274
|
+
// helper for adding shortcuts
|
2275
|
+
function makeGetterAndSetter(name, key) {
|
2276
|
+
moment.fn[name] = moment.fn[name + 's'] = function (input) {
|
2277
|
+
var utc = this._isUTC ? 'UTC' : '';
|
2278
|
+
if (input != null) {
|
2279
|
+
this._d['set' + utc + key](input);
|
2280
|
+
return this;
|
2281
|
+
} else {
|
2282
|
+
return this._d['get' + utc + key]();
|
2283
|
+
}
|
2284
|
+
};
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
// loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
|
2288
|
+
for (i = 0; i < proxyGettersAndSetters.length; i ++) {
|
2289
|
+
makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
|
2290
|
+
}
|
2291
|
+
|
2292
|
+
// add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
|
2293
|
+
makeGetterAndSetter('year', 'FullYear');
|
2294
|
+
|
2295
|
+
// add plural methods
|
2296
|
+
moment.fn.days = moment.fn.day;
|
2297
|
+
moment.fn.weeks = moment.fn.week;
|
2298
|
+
moment.fn.isoWeeks = moment.fn.isoWeek;
|
2299
|
+
|
2300
|
+
/************************************
|
2301
|
+
Duration Prototype
|
2302
|
+
************************************/
|
2303
|
+
|
2304
|
+
|
2305
|
+
moment.duration.fn = Duration.prototype = {
|
2306
|
+
weeks : function () {
|
2307
|
+
return absRound(this.days() / 7);
|
2308
|
+
},
|
2309
|
+
|
2310
|
+
valueOf : function () {
|
2311
|
+
return this._milliseconds +
|
2312
|
+
this._days * 864e5 +
|
2313
|
+
this._months * 2592e6;
|
2314
|
+
},
|
2315
|
+
|
2316
|
+
humanize : function (withSuffix) {
|
2317
|
+
var difference = +this,
|
2318
|
+
output = relativeTime(difference, !withSuffix, this.lang());
|
2319
|
+
|
2320
|
+
if (withSuffix) {
|
2321
|
+
output = this.lang().pastFuture(difference, output);
|
2322
|
+
}
|
2323
|
+
|
2324
|
+
return this.lang().postformat(output);
|
2325
|
+
},
|
2326
|
+
|
2327
|
+
lang : moment.fn.lang
|
2328
|
+
};
|
2329
|
+
|
2330
|
+
function makeDurationGetter(name) {
|
2331
|
+
moment.duration.fn[name] = function () {
|
2332
|
+
return this._data[name];
|
2333
|
+
};
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
function makeDurationAsGetter(name, factor) {
|
2337
|
+
moment.duration.fn['as' + name] = function () {
|
2338
|
+
return +this / factor;
|
2339
|
+
};
|
2340
|
+
}
|
2341
|
+
|
2342
|
+
for (i in unitMillisecondFactors) {
|
2343
|
+
if (unitMillisecondFactors.hasOwnProperty(i)) {
|
2344
|
+
makeDurationAsGetter(i, unitMillisecondFactors[i]);
|
2345
|
+
makeDurationGetter(i.toLowerCase());
|
2346
|
+
}
|
2347
|
+
}
|
2348
|
+
|
2349
|
+
makeDurationAsGetter('Weeks', 6048e5);
|
2350
|
+
|
2351
|
+
|
2352
|
+
/************************************
|
2353
|
+
Default Lang
|
2354
|
+
************************************/
|
2355
|
+
|
2356
|
+
|
2357
|
+
// Set default language, other languages will inherit from English.
|
2358
|
+
moment.lang('en', {
|
2359
|
+
ordinal : function (number) {
|
2360
|
+
var b = number % 10,
|
2361
|
+
output = (~~ (number % 100 / 10) === 1) ? 'th' :
|
2362
|
+
(b === 1) ? 'st' :
|
2363
|
+
(b === 2) ? 'nd' :
|
2364
|
+
(b === 3) ? 'rd' : 'th';
|
2365
|
+
return number + output;
|
2366
|
+
}
|
2367
|
+
});
|
2368
|
+
|
2369
|
+
|
2370
|
+
/************************************
|
2371
|
+
Exposing Moment
|
2372
|
+
************************************/
|
2373
|
+
|
2374
|
+
this['moment'] = moment;
|
2375
|
+
|
2376
|
+
}).call(typeof Kalendae === 'undefined' ? window : Kalendae);
|
2377
|
+
|
2378
|
+
if (!Kalendae.moment) {
|
2379
|
+
if (window.moment) {
|
2380
|
+
Kalendae.moment = window.moment;
|
2381
|
+
} else {
|
2382
|
+
throw "Kalendae requires moment.js. You must use kalendae.standalone.js if moment is not available on the page.";
|
2383
|
+
}
|
2384
|
+
}
|
2385
|
+
|
2386
|
+
moment = Kalendae.moment;
|
2387
|
+
|
2388
|
+
//function to reset the date object to 00:00 GMT
|
2389
|
+
moment.fn.stripTime = function () {
|
2390
|
+
this._d = new Date(Math.floor(this._d.valueOf() / 86400000) * 86400000);
|
2391
|
+
return this;
|
2392
|
+
};
|
2393
|
+
|
2394
|
+
|
2395
|
+
//function to get the total number of days since the epoch.
|
2396
|
+
moment.fn.yearDay = function (input) {
|
2397
|
+
var yearday = Math.floor(this._d / 86400000);
|
2398
|
+
return (typeof input === 'undefined') ? yearday :
|
2399
|
+
this.add({ d : input - yearday });
|
2400
|
+
};
|
2401
|
+
|
2402
|
+
today = Kalendae.moment().stripTime();
|
2403
|
+
|
2404
|
+
if (typeof jQuery !== 'undefined' && (typeof document.addEventListener === 'function' || util.isIE8())) {
|
2405
|
+
jQuery.fn.kalendae = function (options) {
|
2406
|
+
this.each(function (i, e) {
|
2407
|
+
if (e.tagName === 'INPUT') {
|
2408
|
+
//if element is an input, bind a popup calendar to the input.
|
2409
|
+
$(e).data('kalendae', new Kalendae.Input(e, options));
|
2410
|
+
} else {
|
2411
|
+
//otherwise, insert a flat calendar into the element.
|
2412
|
+
$(e).data('kalendae', new Kalendae($.extend({}, {attachTo:e}, options)));
|
2413
|
+
}
|
2414
|
+
});
|
2415
|
+
return this;
|
2416
|
+
};
|
2417
|
+
}
|
2418
|
+
|
2419
|
+
|
2420
|
+
})();
|