@noe-teritorio/opening_hours 3.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +816 -0
- package/LICENSES/AGPL-3.0-only.txt +235 -0
- package/LICENSES/AGPL-3.0-or-later.txt +235 -0
- package/LICENSES/CC0-1.0.txt +121 -0
- package/LICENSES/LGPL-3.0-only.txt +304 -0
- package/LICENSES/ODbL-1.0.txt +540 -0
- package/Makefile +526 -0
- package/README.md +926 -0
- package/REUSE.toml +40 -0
- package/build/opening_hours.esm.mjs +45870 -0
- package/build/opening_hours.esm.mjs.map +1 -0
- package/build/opening_hours.js +45875 -0
- package/package.json +133 -0
- package/site/js/countryToLanguageMapping.js +247 -0
- package/site/js/helpers.js +735 -0
- package/site/js/i18n-resources.js +2284 -0
- package/site/js/main.js +401 -0
- package/site/js/opening_hours_table.js +414 -0
- package/site/js/theme.js +73 -0
- package/site/js/yohours_model.js +2791 -0
- package/src/locales/i18n.js +97 -0
- package/types/index.d.ts +159 -0
|
@@ -0,0 +1,2791 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: Adrien PAVIE
|
|
3
|
+
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
*
|
|
5
|
+
* This file is part of YoHours.
|
|
6
|
+
*
|
|
7
|
+
* YoHours is free software: you can redistribute it and/or modify
|
|
8
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
9
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
* any later version.
|
|
11
|
+
*
|
|
12
|
+
* YoHours is distributed in the hope that it will be useful,
|
|
13
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
* GNU Affero General Public License for more details.
|
|
16
|
+
*
|
|
17
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
18
|
+
* along with YoHours. If not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* YoHours
|
|
23
|
+
* Web interface to make opening hours data for OpenStreetMap the easy way
|
|
24
|
+
* Author: Adrien PAVIE
|
|
25
|
+
*
|
|
26
|
+
* Model JS classes
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* ========= CONSTANTS =========
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* The days in a week
|
|
34
|
+
*/
|
|
35
|
+
const DAYS = {
|
|
36
|
+
MONDAY: 0,
|
|
37
|
+
TUESDAY: 1,
|
|
38
|
+
WEDNESDAY: 2,
|
|
39
|
+
THURSDAY: 3,
|
|
40
|
+
FRIDAY: 4,
|
|
41
|
+
SATURDAY: 5,
|
|
42
|
+
SUNDAY: 6
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The days in OSM
|
|
47
|
+
*/
|
|
48
|
+
const OSM_DAYS = [ "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" ];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The days IRL
|
|
52
|
+
*/
|
|
53
|
+
const IRL_DAYS = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The month in OSM
|
|
57
|
+
*/
|
|
58
|
+
const OSM_MONTHS = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The months IRL
|
|
62
|
+
*/
|
|
63
|
+
const IRL_MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The last day of month
|
|
67
|
+
*/
|
|
68
|
+
const MONTH_END_DAY = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The maximal minute that an interval can have
|
|
72
|
+
*/
|
|
73
|
+
const MINUTES_MAX = 1440;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The maximal value of days
|
|
77
|
+
*/
|
|
78
|
+
const DAYS_MAX = 6;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The weekday ID for PH
|
|
82
|
+
*/
|
|
83
|
+
const PH_WEEKDAY = -2;
|
|
84
|
+
|
|
85
|
+
/*
|
|
86
|
+
* ========== CLASSES ==========
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Class Interval, defines an interval in a week where the POI is open.
|
|
91
|
+
* @param dayStart The start week day (use DAYS constants)
|
|
92
|
+
* @param dayEnd The end week day (use DAYS constants)
|
|
93
|
+
* @param minStart The interval start (in minutes since midnight)
|
|
94
|
+
* @param minEnd The interval end (in minutes since midnight)
|
|
95
|
+
*/
|
|
96
|
+
var Interval = function(dayStart, dayEnd, minStart, minEnd) {
|
|
97
|
+
//ATTRIBUTES
|
|
98
|
+
/** The start day in the week, see DAYS **/
|
|
99
|
+
this._dayStart = dayStart;
|
|
100
|
+
|
|
101
|
+
/** The end day in the week, see DAYS **/
|
|
102
|
+
this._dayEnd = dayEnd;
|
|
103
|
+
|
|
104
|
+
/** The interval start, in minutes since midnight (local hour) **/
|
|
105
|
+
this._start = minStart;
|
|
106
|
+
|
|
107
|
+
/** The interval end, in minutes since midnight (local hour) **/
|
|
108
|
+
this._end = minEnd;
|
|
109
|
+
|
|
110
|
+
//CONSTRUCTOR
|
|
111
|
+
if(this._dayEnd == 0 && this._end == 0) {
|
|
112
|
+
this._dayEnd = DAYS_MAX;
|
|
113
|
+
this._end = MINUTES_MAX;
|
|
114
|
+
}
|
|
115
|
+
//console.log("Interval", this._dayStart, this._dayEnd, this._start, this._end);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
//ACCESSORS
|
|
119
|
+
/**
|
|
120
|
+
* @return The start day in the week, see DAYS constants
|
|
121
|
+
*/
|
|
122
|
+
Interval.prototype.getStartDay = function() {
|
|
123
|
+
return this._dayStart;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @return The end day in the week, see DAYS constants
|
|
128
|
+
*/
|
|
129
|
+
Interval.prototype.getEndDay = function() {
|
|
130
|
+
return this._dayEnd;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @return The interval start, in minutes since midnight
|
|
135
|
+
*/
|
|
136
|
+
Interval.prototype.getFrom = function() {
|
|
137
|
+
return this._start;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @return The interval end, in minutes since midnight
|
|
142
|
+
*/
|
|
143
|
+
Interval.prototype.getTo = function() {
|
|
144
|
+
return this._end;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A wide interval is an interval of one or more days, weeks, months, holidays.
|
|
151
|
+
* Use WideInterval.days/weeks/months/holidays methods to construct one object.
|
|
152
|
+
*/
|
|
153
|
+
var WideInterval = function() {
|
|
154
|
+
//ATTRIBUTES
|
|
155
|
+
/** The start of the interval **/
|
|
156
|
+
this._start = null;
|
|
157
|
+
|
|
158
|
+
/** The end of the interval **/
|
|
159
|
+
this._end = null;
|
|
160
|
+
|
|
161
|
+
/** The kind of interval **/
|
|
162
|
+
this._type = null;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
//CONSTRUCTORS
|
|
166
|
+
/**
|
|
167
|
+
* @return a day-based interval
|
|
168
|
+
*/
|
|
169
|
+
WideInterval.prototype.day = function(startDay, startMonth, endDay, endMonth) {
|
|
170
|
+
if(startDay == null || startMonth == null) {
|
|
171
|
+
throw Error("Start day and month can't be null");
|
|
172
|
+
}
|
|
173
|
+
this._start = { day: startDay, month: startMonth };
|
|
174
|
+
this._end = (endDay != null && endMonth != null && (endDay != startDay || endMonth != startMonth)) ? { day: endDay, month: endMonth } : null;
|
|
175
|
+
this._type = "day";
|
|
176
|
+
return this;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @return a week-based interval
|
|
181
|
+
*/
|
|
182
|
+
WideInterval.prototype.week = function(startWeek, endWeek) {
|
|
183
|
+
if(startWeek == null) {
|
|
184
|
+
throw Error("Start week can't be null");
|
|
185
|
+
}
|
|
186
|
+
this._start = { week: startWeek };
|
|
187
|
+
this._end = (endWeek != null && endWeek != startWeek) ? { week: endWeek } : null;
|
|
188
|
+
this._type = "week";
|
|
189
|
+
return this;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @return a month-based interval
|
|
194
|
+
*/
|
|
195
|
+
WideInterval.prototype.month = function(startMonth, endMonth) {
|
|
196
|
+
if(startMonth == null) {
|
|
197
|
+
throw Error("Start month can't be null");
|
|
198
|
+
}
|
|
199
|
+
this._start = { month: startMonth };
|
|
200
|
+
this._end = (endMonth != null && endMonth != startMonth) ? { month: endMonth } : null;
|
|
201
|
+
this._type = "month";
|
|
202
|
+
return this;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @return a holiday-based interval
|
|
207
|
+
*/
|
|
208
|
+
WideInterval.prototype.holiday = function(holiday) {
|
|
209
|
+
if(holiday == null || (holiday != "PH" && holiday != "SH" && holiday != "easter")) {
|
|
210
|
+
throw Error("Invalid holiday, must be PH, SH or easter");
|
|
211
|
+
}
|
|
212
|
+
this._start = { holiday: holiday };
|
|
213
|
+
this._end = null;
|
|
214
|
+
this._type = "holiday";
|
|
215
|
+
return this;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @return a holiday-based interval
|
|
220
|
+
*/
|
|
221
|
+
WideInterval.prototype.always = function() {
|
|
222
|
+
this._start = null;
|
|
223
|
+
this._end = null;
|
|
224
|
+
this._type = "always";
|
|
225
|
+
return this;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
//ACCESSORS
|
|
229
|
+
/**
|
|
230
|
+
* @return The kind of wide interval (always, day, month, week, holiday)
|
|
231
|
+
*/
|
|
232
|
+
WideInterval.prototype.getType = function() {
|
|
233
|
+
return this._type;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @return The start moment
|
|
238
|
+
*/
|
|
239
|
+
WideInterval.prototype.getStart = function() {
|
|
240
|
+
return this._start;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @return The end moment
|
|
245
|
+
*/
|
|
246
|
+
WideInterval.prototype.getEnd = function() {
|
|
247
|
+
return this._end;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @return True if the given object concerns the same interval as this one
|
|
252
|
+
*/
|
|
253
|
+
WideInterval.prototype.equals = function(o) {
|
|
254
|
+
if(!o instanceof WideInterval) { return false; }
|
|
255
|
+
if(this === o) { return true; }
|
|
256
|
+
if(o._type == "always") { return this._type == "always"; }
|
|
257
|
+
var result = false;
|
|
258
|
+
|
|
259
|
+
switch(this._type) {
|
|
260
|
+
case "always":
|
|
261
|
+
result = o._start == null;
|
|
262
|
+
break;
|
|
263
|
+
case "day":
|
|
264
|
+
result =
|
|
265
|
+
(
|
|
266
|
+
o._type == "day"
|
|
267
|
+
&& o._start.month == this._start.month
|
|
268
|
+
&& o._start.day == this._start.day
|
|
269
|
+
&& (
|
|
270
|
+
(o._end == null && this._end == null)
|
|
271
|
+
|| (o._end != null && this._end != null && this._end.month == o._end.month && this._end.day == o._end.day)
|
|
272
|
+
))
|
|
273
|
+
||
|
|
274
|
+
(
|
|
275
|
+
o._type == "month"
|
|
276
|
+
&& o._start.month == this._start.month
|
|
277
|
+
&& (this.isFullMonth() && o.isFullMonth())
|
|
278
|
+
|| (o._end != null && this._end != null && this._end.month == o._end.month && this.endsMonth() && o.endsMonth())
|
|
279
|
+
);
|
|
280
|
+
break;
|
|
281
|
+
|
|
282
|
+
case "week":
|
|
283
|
+
result =
|
|
284
|
+
o._start.week == this._start.week
|
|
285
|
+
&& (o._end == this._end || (this._end != null && o._end != null && o._end.week == this._end.week));
|
|
286
|
+
break;
|
|
287
|
+
|
|
288
|
+
case "month":
|
|
289
|
+
result =
|
|
290
|
+
(
|
|
291
|
+
o._type == "day"
|
|
292
|
+
&& this._start.month == o._start.month
|
|
293
|
+
&& o.startsMonth()
|
|
294
|
+
&& (
|
|
295
|
+
(this._end == null && o._end != null && this._start.month == o._end.month && o.endsMonth())
|
|
296
|
+
||
|
|
297
|
+
(this._end != null && o._end != null && this._end.month == o._end.month && o.endsMonth())
|
|
298
|
+
)
|
|
299
|
+
)
|
|
300
|
+
||
|
|
301
|
+
(
|
|
302
|
+
o._type == "month"
|
|
303
|
+
&& o._start.month == this._start.month
|
|
304
|
+
&& (
|
|
305
|
+
(this._end == null && o._end == null)
|
|
306
|
+
||
|
|
307
|
+
(this._end != null && o._end != null && this._end.month == o._end.month)
|
|
308
|
+
)
|
|
309
|
+
);
|
|
310
|
+
break;
|
|
311
|
+
|
|
312
|
+
case "holiday":
|
|
313
|
+
result = o._start.holiday == this._start.holiday;
|
|
314
|
+
break;
|
|
315
|
+
default:
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return result;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @return The human readable time
|
|
323
|
+
*/
|
|
324
|
+
WideInterval.prototype.getTimeForHumans = function() {
|
|
325
|
+
var result;
|
|
326
|
+
|
|
327
|
+
switch(this._type) {
|
|
328
|
+
case "day":
|
|
329
|
+
if(this._end != null) {
|
|
330
|
+
result = "every week from "+IRL_MONTHS[this._start.month-1]+" "+this._start.day+" to ";
|
|
331
|
+
if(this._start.month != this._end.month) { result += IRL_MONTHS[this._end.month-1]+" "; }
|
|
332
|
+
result += this._end.day;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
result = "day "+IRL_MONTHS[this._start.month-1]+" "+this._start.day;
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
|
|
339
|
+
case "week":
|
|
340
|
+
if(this._end != null) {
|
|
341
|
+
result = "every week from week "+this._start.week+" to "+this._end.week;
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
result = "week "+this._start.week;
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
347
|
+
|
|
348
|
+
case "month":
|
|
349
|
+
if(this._end != null) {
|
|
350
|
+
result = "every week from "+IRL_MONTHS[this._start.month-1]+" to "+IRL_MONTHS[this._end.month-1];
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
result = "every week in "+IRL_MONTHS[this._start.month-1];
|
|
354
|
+
}
|
|
355
|
+
break;
|
|
356
|
+
|
|
357
|
+
case "holiday":
|
|
358
|
+
if(this._start.holiday == "SH") {
|
|
359
|
+
result = "every week during school holidays";
|
|
360
|
+
}
|
|
361
|
+
else if(this._start.holiday == "PH") {
|
|
362
|
+
result = "every public holidays";
|
|
363
|
+
}
|
|
364
|
+
else if(this._start.holiday == "easter") {
|
|
365
|
+
result = "each easter day";
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
throw new Error("Invalid holiday type: "+this._start.holiday);
|
|
369
|
+
}
|
|
370
|
+
break;
|
|
371
|
+
|
|
372
|
+
case "always":
|
|
373
|
+
result = "every week of year";
|
|
374
|
+
break;
|
|
375
|
+
default:
|
|
376
|
+
result = "invalid time";
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return result;
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @return The time selector for OSM opening_hours
|
|
384
|
+
*/
|
|
385
|
+
WideInterval.prototype.getTimeSelector = function() {
|
|
386
|
+
var result;
|
|
387
|
+
|
|
388
|
+
switch(this._type) {
|
|
389
|
+
case "day":
|
|
390
|
+
result = OSM_MONTHS[this._start.month-1]+" "+((this._start.day < 10) ? "0" : "")+this._start.day;
|
|
391
|
+
if(this._end != null) {
|
|
392
|
+
//Same month as start ?
|
|
393
|
+
if(this._start.month == this._end.month) {
|
|
394
|
+
result += "-"+((this._end.day < 10) ? "0" : "")+this._end.day;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
result += "-"+OSM_MONTHS[this._end.month-1]+" "+((this._end.day < 10) ? "0" : "")+this._end.day;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
break;
|
|
401
|
+
|
|
402
|
+
case "week":
|
|
403
|
+
result = "week "+((this._start.week < 10) ? "0" : "")+this._start.week;
|
|
404
|
+
if(this._end != null) {
|
|
405
|
+
result += "-"+((this._end.week < 10) ? "0" : "")+this._end.week;
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
408
|
+
|
|
409
|
+
case "month":
|
|
410
|
+
result = OSM_MONTHS[this._start.month-1];
|
|
411
|
+
if(this._end != null) {
|
|
412
|
+
result += "-"+OSM_MONTHS[this._end.month-1];
|
|
413
|
+
}
|
|
414
|
+
break;
|
|
415
|
+
|
|
416
|
+
case "holiday":
|
|
417
|
+
result = this._start.holiday;
|
|
418
|
+
break;
|
|
419
|
+
|
|
420
|
+
case "always":
|
|
421
|
+
default:
|
|
422
|
+
result = "";
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return result;
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Does this interval corresponds to a full month ?
|
|
430
|
+
*/
|
|
431
|
+
WideInterval.prototype.isFullMonth = function() {
|
|
432
|
+
if(this._type == "month" && this._end == null) {
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
else if(this._type == "day") {
|
|
436
|
+
return (this._start.day == 1 && this._end != null && this._end.month == this._start.month && this._end.day != undefined && this._end.day == MONTH_END_DAY[this._end.month-1]);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Does this interval starts the first day of a month
|
|
445
|
+
*/
|
|
446
|
+
WideInterval.prototype.startsMonth = function() {
|
|
447
|
+
return this._type == "month" || this._type == "always" || (this._type == "day" && this._start.day == 1);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Does this interval ends the last day of a month
|
|
452
|
+
*/
|
|
453
|
+
WideInterval.prototype.endsMonth = function() {
|
|
454
|
+
return this._type == "month" || this._type == "always" || (this._type == "day" && this._end != null && this._end.day == MONTH_END_DAY[this._end.month-1]);
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Does this interval strictly contains the given one (ie the second is a refinement of the first, and not strictly equal)
|
|
459
|
+
* @param o The other wide interval
|
|
460
|
+
* @return True if this date contains the given one (and is not strictly equal to)
|
|
461
|
+
*/
|
|
462
|
+
WideInterval.prototype.contains = function(o) {
|
|
463
|
+
var result = false;
|
|
464
|
+
|
|
465
|
+
/*
|
|
466
|
+
* Check if it is contained in this one
|
|
467
|
+
*/
|
|
468
|
+
if(this.equals(o)) {
|
|
469
|
+
result = false;
|
|
470
|
+
}
|
|
471
|
+
else if(this._type == "always") {
|
|
472
|
+
result = true;
|
|
473
|
+
}
|
|
474
|
+
else if(this._type == "day") {
|
|
475
|
+
if(o._type == "day") {
|
|
476
|
+
//Starting after
|
|
477
|
+
if(o._start.month > this._start.month || (o._start.month == this._start.month && o._start.day >= this._start.day)) {
|
|
478
|
+
//Ending before
|
|
479
|
+
if(o._end != null) {
|
|
480
|
+
if(this._end != null && (o._end.month < this._end.month || (o._end.month == this._end.month && o._end.day <= this._end.day))) {
|
|
481
|
+
result = true;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
if(this._end != null && (o._start.month < this._end.month || (o._start.month == this._end.month && o._start.day <= this._end.day))) {
|
|
486
|
+
result = true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else if(o._type == "month"){
|
|
492
|
+
//Starting after
|
|
493
|
+
if(o._start.month > this._start.month || (o._start.month == this._start.month && this._start.day == 1)) {
|
|
494
|
+
//Ending before
|
|
495
|
+
if(o._end != null && this._end != null && (o._end.month < this._end.month || (o._end.month == this._end.month && this._end.day == MONTH_END_DAY[end.month-1]))) {
|
|
496
|
+
result = true;
|
|
497
|
+
}
|
|
498
|
+
else if(o._end == null && (this._end != null && o._start.month < this._end.month)) {
|
|
499
|
+
result = true;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else if(this._type == "week") {
|
|
505
|
+
if(o._type == "week") {
|
|
506
|
+
if(o._start.week >= this._start.week) {
|
|
507
|
+
if(o._end != null && this._end != null && o._end.week <= this._end.week) {
|
|
508
|
+
result = true;
|
|
509
|
+
}
|
|
510
|
+
else if(o._end == null && ((this._end != null && o._start.week <= this._end.week) || o._start.week == this._start.week)) {
|
|
511
|
+
result = true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
else if(this._type == "month") {
|
|
517
|
+
if(o._type == "month") {
|
|
518
|
+
if(o._start.month >= this._start.month) {
|
|
519
|
+
if(o._end != null && this._end != null && o._end.month <= this._end.month) {
|
|
520
|
+
result = true;
|
|
521
|
+
}
|
|
522
|
+
else if(o._end == null && ((this._end != null && o._start.month <= this._end.month) || o._start.month == this._start.month)) {
|
|
523
|
+
result = true;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else if(o._type == "day") {
|
|
528
|
+
if(o._end != null) {
|
|
529
|
+
if(this._end == null) {
|
|
530
|
+
if(
|
|
531
|
+
o._start.month == this._start.month
|
|
532
|
+
&& o._end.month == this._start.month
|
|
533
|
+
&& ((o._start.day >= 1 && o._end.day < MONTH_END_DAY[o._start.month-1])
|
|
534
|
+
|| (o._start.day > 1 && o._end.day <= MONTH_END_DAY[o._start.month-1]))
|
|
535
|
+
) {
|
|
536
|
+
result = true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
if(o._start.month >= this._start.month && o._end.month <= this._end.month) {
|
|
541
|
+
if(
|
|
542
|
+
(o._start.month > this._start.month && o._end.month < this._end.month)
|
|
543
|
+
|| (o._start.month == this._start.month && o._end.month < this._end.month && start.day > 1)
|
|
544
|
+
|| (o._start.month > this._start.month && o._end.month == this._end.month && o._end.day < MONTH_END_DAY[o._end.month-1])
|
|
545
|
+
|| (o._start.day >= 1 && o._end.day < MONTH_END_DAY[o._end.month-1])
|
|
546
|
+
|| (o._start.day > 1 && o._end.day <= MONTH_END_DAY[o._end.month-1])
|
|
547
|
+
) {
|
|
548
|
+
result = true;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
else {
|
|
554
|
+
if(this._end == null) {
|
|
555
|
+
if(this._start.month == o._start.month) {
|
|
556
|
+
result = true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
else {
|
|
560
|
+
if(o._start.month >= this._start.month && o._start.month <= this._end.month) {
|
|
561
|
+
result = true;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return result;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Class Day, represents a typical day
|
|
575
|
+
*/
|
|
576
|
+
var Day = function() {
|
|
577
|
+
//ATTRIBUTES
|
|
578
|
+
/** The intervals defining this week **/
|
|
579
|
+
this._intervals = [];
|
|
580
|
+
|
|
581
|
+
/** The next interval ID **/
|
|
582
|
+
this._nextInterval = 0;
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
//ACCESSORS
|
|
586
|
+
/**
|
|
587
|
+
* @return This day, as a boolean array (minutes since midnight). True if open, false else.
|
|
588
|
+
*/
|
|
589
|
+
Day.prototype.getAsMinutesArray = function() {
|
|
590
|
+
//Create array with all values set to false
|
|
591
|
+
//For each minute
|
|
592
|
+
var minuteArray = [];
|
|
593
|
+
for (var minute = 0; minute <= MINUTES_MAX; minute++) {
|
|
594
|
+
minuteArray[minute] = false;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
//Set to true values where an interval is defined
|
|
598
|
+
for(var id=0, l=this._intervals.length; id < l; id++) {
|
|
599
|
+
if(this._intervals[id] != undefined) {
|
|
600
|
+
var startMinute = null;
|
|
601
|
+
var endMinute = null;
|
|
602
|
+
|
|
603
|
+
if(
|
|
604
|
+
this._intervals[id].getStartDay() == this._intervals[id].getEndDay()
|
|
605
|
+
|| (this._intervals[id].getEndDay() == DAYS_MAX && this._intervals[id].getTo() == MINUTES_MAX)
|
|
606
|
+
) {
|
|
607
|
+
//Define start and end minute regarding the current day
|
|
608
|
+
startMinute = this._intervals[id].getFrom();
|
|
609
|
+
endMinute = this._intervals[id].getTo();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
//Set to true the minutes for this day
|
|
613
|
+
if(startMinute != null && endMinute != null){
|
|
614
|
+
for(var minute = startMinute; minute <= endMinute; minute++) {
|
|
615
|
+
minuteArray[minute] = true;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
else {
|
|
619
|
+
console.log(this._intervals[id].getFrom()+" "+this._intervals[id].getTo()+" "+this._intervals[id].getStartDay()+" "+this._intervals[id].getEndDay());
|
|
620
|
+
throw new Error("Invalid interval");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
return minuteArray;
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @param clean Clean intervals ? (default: false)
|
|
630
|
+
* @return The intervals in this week
|
|
631
|
+
*/
|
|
632
|
+
Day.prototype.getIntervals = function(clean) {
|
|
633
|
+
clean = clean || false;
|
|
634
|
+
|
|
635
|
+
if(clean) {
|
|
636
|
+
//Create continuous intervals over days
|
|
637
|
+
var minuteArray = this.getAsMinutesArray();
|
|
638
|
+
var intervals = [];
|
|
639
|
+
var minStart = -1, minEnd;
|
|
640
|
+
|
|
641
|
+
for(var min=0, lm=minuteArray.length; min < lm; min++) {
|
|
642
|
+
//First minute
|
|
643
|
+
if(min == 0) {
|
|
644
|
+
if(minuteArray[min]) {
|
|
645
|
+
minStart = min;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
//Last minute
|
|
649
|
+
else if(min == lm-1) {
|
|
650
|
+
if(minuteArray[min]) {
|
|
651
|
+
intervals.push(new Interval(
|
|
652
|
+
0,
|
|
653
|
+
0,
|
|
654
|
+
minStart,
|
|
655
|
+
min
|
|
656
|
+
));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
//Other minutes
|
|
660
|
+
else {
|
|
661
|
+
//New interval
|
|
662
|
+
if(minuteArray[min] && minStart < 0) {
|
|
663
|
+
minStart = min;
|
|
664
|
+
}
|
|
665
|
+
//Ending interval
|
|
666
|
+
else if(!minuteArray[min] && minStart >= 0) {
|
|
667
|
+
intervals.push(new Interval(
|
|
668
|
+
0,
|
|
669
|
+
0,
|
|
670
|
+
minStart,
|
|
671
|
+
min-1
|
|
672
|
+
));
|
|
673
|
+
|
|
674
|
+
minStart = -1;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return intervals;
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
return this._intervals;
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
//MODIFIERS
|
|
687
|
+
/**
|
|
688
|
+
* Add a new interval to this week
|
|
689
|
+
* @param interval The new interval
|
|
690
|
+
* @return The ID of the added interval
|
|
691
|
+
*/
|
|
692
|
+
Day.prototype.addInterval = function(interval) {
|
|
693
|
+
this._intervals[this._nextInterval] = interval;
|
|
694
|
+
this._nextInterval++;
|
|
695
|
+
|
|
696
|
+
return this._nextInterval-1;
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Edits the given interval
|
|
701
|
+
* @param id The interval ID
|
|
702
|
+
* @param interval The new interval
|
|
703
|
+
*/
|
|
704
|
+
Day.prototype.editInterval = function(id, interval) {
|
|
705
|
+
this._intervals[id] = interval;
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Remove the given interval
|
|
710
|
+
* @param id the interval ID
|
|
711
|
+
*/
|
|
712
|
+
Day.prototype.removeInterval = function(id) {
|
|
713
|
+
this._intervals[id] = undefined;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Redefines this date range intervals with a copy of the given ones
|
|
718
|
+
*/
|
|
719
|
+
Day.prototype.copyIntervals = function(intervals) {
|
|
720
|
+
this._intervals = [];
|
|
721
|
+
for(var i=0; i < intervals.length; i++) {
|
|
722
|
+
if(intervals[i] != undefined && intervals[i].getStartDay() == 0 && intervals[i].getEndDay() == 0) {
|
|
723
|
+
this._intervals.push(structuredClone(intervals[i]));
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
this._intervals = this.getIntervals(true);
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Removes all defined intervals
|
|
732
|
+
*/
|
|
733
|
+
Day.prototype.clearIntervals = function() {
|
|
734
|
+
this._intervals = [];
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
//OTHER METHODS
|
|
738
|
+
/**
|
|
739
|
+
* Is this day defining the same intervals as the given one ?
|
|
740
|
+
*/
|
|
741
|
+
Day.prototype.sameAs = function(d) {
|
|
742
|
+
return d.getAsMinutesArray().equals(this.getAsMinutesArray());
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Class Week, represents a typical week of opening hours.
|
|
749
|
+
*/
|
|
750
|
+
var Week = function() {
|
|
751
|
+
//ATTRIBUTES
|
|
752
|
+
/** The intervals defining this week **/
|
|
753
|
+
this._intervals = [];
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
//ACCESSORS
|
|
757
|
+
/**
|
|
758
|
+
* @return This week, as a two-dimensional boolean array. First dimension is for days (see DAYS), second dimension for minutes since midnight. True if open, false else.
|
|
759
|
+
*/
|
|
760
|
+
Week.prototype.getAsMinutesArray = function() {
|
|
761
|
+
//Create array with all values set to false
|
|
762
|
+
//For each day
|
|
763
|
+
var minuteArray = [];
|
|
764
|
+
for(var day = 0; day <= DAYS_MAX; day++) {
|
|
765
|
+
//For each minute
|
|
766
|
+
minuteArray[day] = [];
|
|
767
|
+
for (var minute = 0; minute <= MINUTES_MAX; minute++) {
|
|
768
|
+
minuteArray[day][minute] = false;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
//Set to true values where an interval is defined
|
|
773
|
+
for(var id=0, l=this._intervals.length; id < l; id++) {
|
|
774
|
+
if(this._intervals[id] != undefined) {
|
|
775
|
+
for(var day = this._intervals[id].getStartDay(); day <= this._intervals[id].getEndDay(); day++) {
|
|
776
|
+
//Define start and end minute regarding the current day
|
|
777
|
+
var startMinute = (day == this._intervals[id].getStartDay()) ? this._intervals[id].getFrom() : 0;
|
|
778
|
+
var endMinute = (day == this._intervals[id].getEndDay()) ? this._intervals[id].getTo() : MINUTES_MAX;
|
|
779
|
+
|
|
780
|
+
//Set to true the minutes for this day
|
|
781
|
+
if(startMinute != null && endMinute != null) {
|
|
782
|
+
for(var minute = startMinute; minute <= endMinute; minute++) {
|
|
783
|
+
minuteArray[day][minute] = true;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
return minuteArray;
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* @param clean Clean intervals ? (default: false)
|
|
795
|
+
* @return The intervals in this week
|
|
796
|
+
*/
|
|
797
|
+
Week.prototype.getIntervals = function(clean) {
|
|
798
|
+
clean = clean || false;
|
|
799
|
+
|
|
800
|
+
if(clean) {
|
|
801
|
+
//Create continuous intervals over days
|
|
802
|
+
var minuteArray = this.getAsMinutesArray();
|
|
803
|
+
var intervals = [];
|
|
804
|
+
var dayStart = -1, minStart = -1, minEnd;
|
|
805
|
+
|
|
806
|
+
for(var day=0, l=minuteArray.length; day < l; day++) {
|
|
807
|
+
for(var min=0, lm=minuteArray[day].length; min < lm; min++) {
|
|
808
|
+
//First minute of monday
|
|
809
|
+
if(day == 0 && min == 0) {
|
|
810
|
+
if(minuteArray[day][min]) {
|
|
811
|
+
dayStart = day;
|
|
812
|
+
minStart = min;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
//Last minute of sunday
|
|
816
|
+
else if(day == DAYS_MAX && min == lm-1) {
|
|
817
|
+
if(dayStart >= 0 && minuteArray[day][min]) {
|
|
818
|
+
intervals.push(new Interval(
|
|
819
|
+
dayStart,
|
|
820
|
+
day,
|
|
821
|
+
minStart,
|
|
822
|
+
min
|
|
823
|
+
));
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
//Other days or minutes
|
|
827
|
+
else {
|
|
828
|
+
//New interval
|
|
829
|
+
if(minuteArray[day][min] && dayStart < 0) {
|
|
830
|
+
dayStart = day;
|
|
831
|
+
minStart = min;
|
|
832
|
+
}
|
|
833
|
+
//Ending interval
|
|
834
|
+
else if(!minuteArray[day][min] && dayStart >= 0) {
|
|
835
|
+
if(min == 0) {
|
|
836
|
+
intervals.push(new Interval(
|
|
837
|
+
dayStart,
|
|
838
|
+
day-1,
|
|
839
|
+
minStart,
|
|
840
|
+
MINUTES_MAX
|
|
841
|
+
));
|
|
842
|
+
}
|
|
843
|
+
else {
|
|
844
|
+
intervals.push(new Interval(
|
|
845
|
+
dayStart,
|
|
846
|
+
day,
|
|
847
|
+
minStart,
|
|
848
|
+
min-1
|
|
849
|
+
));
|
|
850
|
+
}
|
|
851
|
+
dayStart = -1;
|
|
852
|
+
minStart = -1;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return intervals;
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
return this._intervals;
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Returns the intervals which are different from those defined in the given week
|
|
867
|
+
* @param w The general week
|
|
868
|
+
* @return The intervals which are different, as object { open: [ Intervals ], closed: [ Intervals ] }
|
|
869
|
+
*/
|
|
870
|
+
Week.prototype.getIntervalsDiff = function(w) {
|
|
871
|
+
//Get minutes arrays
|
|
872
|
+
var myMinArray = this.getAsMinutesArray();
|
|
873
|
+
var wMinArray = w.getAsMinutesArray();
|
|
874
|
+
|
|
875
|
+
//Create diff array
|
|
876
|
+
var intervals = { open: [], closed: [] };
|
|
877
|
+
var dayStart = -1, minStart = -1, minEnd;
|
|
878
|
+
var diffDay, m, intervalsLength;
|
|
879
|
+
|
|
880
|
+
for(var d=0; d <= DAYS_MAX; d++) {
|
|
881
|
+
diffDay = false;
|
|
882
|
+
m = 0;
|
|
883
|
+
intervalsLength = intervals.open.length;
|
|
884
|
+
|
|
885
|
+
while(m <= MINUTES_MAX) {
|
|
886
|
+
//Copy entire day
|
|
887
|
+
if(diffDay) {
|
|
888
|
+
//First minute of monday
|
|
889
|
+
if(d == 0 && m == 0) {
|
|
890
|
+
if(myMinArray[d][m]) {
|
|
891
|
+
dayStart = d;
|
|
892
|
+
minStart = m;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
//Last minute of sunday
|
|
896
|
+
else if(d == DAYS_MAX && m == MINUTES_MAX) {
|
|
897
|
+
if(dayStart >= 0 && myMinArray[d][m]) {
|
|
898
|
+
intervals.open.push(new Interval(
|
|
899
|
+
dayStart,
|
|
900
|
+
d,
|
|
901
|
+
minStart,
|
|
902
|
+
m
|
|
903
|
+
));
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
//Other days or minutes
|
|
907
|
+
else {
|
|
908
|
+
//New interval
|
|
909
|
+
if(myMinArray[d][m] && dayStart < 0) {
|
|
910
|
+
dayStart = d;
|
|
911
|
+
minStart = m;
|
|
912
|
+
}
|
|
913
|
+
//Ending interval
|
|
914
|
+
else if(!myMinArray[d][m] && dayStart >= 0) {
|
|
915
|
+
if(m == 0) {
|
|
916
|
+
intervals.open.push(new Interval(
|
|
917
|
+
dayStart,
|
|
918
|
+
d-1,
|
|
919
|
+
minStart,
|
|
920
|
+
MINUTES_MAX
|
|
921
|
+
));
|
|
922
|
+
}
|
|
923
|
+
else {
|
|
924
|
+
intervals.open.push(new Interval(
|
|
925
|
+
dayStart,
|
|
926
|
+
d,
|
|
927
|
+
minStart,
|
|
928
|
+
m-1
|
|
929
|
+
));
|
|
930
|
+
}
|
|
931
|
+
dayStart = -1;
|
|
932
|
+
minStart = -1;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
m++;
|
|
936
|
+
}
|
|
937
|
+
//Check for diff
|
|
938
|
+
else {
|
|
939
|
+
diffDay = myMinArray[d][m] ? !wMinArray[d][m] : wMinArray[d][m];
|
|
940
|
+
|
|
941
|
+
//If there is a difference, start to copy full day
|
|
942
|
+
if(diffDay) {
|
|
943
|
+
m = 0;
|
|
944
|
+
}
|
|
945
|
+
//Else, continue checking
|
|
946
|
+
else {
|
|
947
|
+
m++;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
//Close intervals if day is identical
|
|
953
|
+
if(!diffDay && dayStart > -1) {
|
|
954
|
+
intervals.open.push(new Interval(
|
|
955
|
+
dayStart,
|
|
956
|
+
d-1,
|
|
957
|
+
minStart,
|
|
958
|
+
MINUTES_MAX
|
|
959
|
+
));
|
|
960
|
+
dayStart = -1;
|
|
961
|
+
minStart = -1;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
//Create closed intervals if closed all day
|
|
965
|
+
if(diffDay && dayStart == -1 && intervalsLength == intervals.open.length) {
|
|
966
|
+
//Merge with previous interval if possible
|
|
967
|
+
if(intervals.closed.length > 0 && intervals.closed[intervals.closed.length-1].getEndDay() == d - 1) {
|
|
968
|
+
intervals.closed[intervals.closed.length-1] = new Interval(
|
|
969
|
+
intervals.closed[intervals.closed.length-1].getStartDay(),
|
|
970
|
+
d,
|
|
971
|
+
0,
|
|
972
|
+
MINUTES_MAX
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
intervals.closed.push(new Interval(d, d, 0, MINUTES_MAX));
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return intervals;
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
//MODIFIERS
|
|
985
|
+
/**
|
|
986
|
+
* Add a new interval to this week
|
|
987
|
+
* @param interval The new interval
|
|
988
|
+
* @return The ID of the added interval
|
|
989
|
+
*/
|
|
990
|
+
Week.prototype.addInterval = function(interval) {
|
|
991
|
+
this._intervals[this._intervals.length] = interval;
|
|
992
|
+
return this._intervals.length-1;
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* Edits the given interval
|
|
997
|
+
* @param id The interval ID
|
|
998
|
+
* @param interval The new interval
|
|
999
|
+
*/
|
|
1000
|
+
Week.prototype.editInterval = function(id, interval) {
|
|
1001
|
+
this._intervals[id] = interval;
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Remove the given interval
|
|
1006
|
+
* @param id the interval ID
|
|
1007
|
+
*/
|
|
1008
|
+
Week.prototype.removeInterval = function(id) {
|
|
1009
|
+
this._intervals[id] = undefined;
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Removes all intervals during a given day
|
|
1014
|
+
*/
|
|
1015
|
+
Week.prototype.removeIntervalsDuringDay = function(day) {
|
|
1016
|
+
var interval, itLength = this._intervals.length, dayDiff;
|
|
1017
|
+
for(var i=0; i < itLength; i++) {
|
|
1018
|
+
interval = this._intervals[i];
|
|
1019
|
+
if(interval != undefined) {
|
|
1020
|
+
//If interval over given day
|
|
1021
|
+
if(interval.getStartDay() <= day && interval.getEndDay() >= day) {
|
|
1022
|
+
dayDiff = interval.getEndDay() - interval.getStartDay();
|
|
1023
|
+
|
|
1024
|
+
//Avoid deletion if over night interval
|
|
1025
|
+
if(dayDiff > 1 || dayDiff == 0 || interval.getStartDay() == day || interval.getFrom() <= interval.getTo()) {
|
|
1026
|
+
//Create new interval if several day
|
|
1027
|
+
if(interval.getEndDay() - interval.getStartDay() >= 1 && interval.getFrom() <= interval.getTo()) {
|
|
1028
|
+
if(interval.getStartDay() < day) {
|
|
1029
|
+
this.addInterval(new Interval(interval.getStartDay(), day-1, interval.getFrom(), 24*60));
|
|
1030
|
+
}
|
|
1031
|
+
if(interval.getEndDay() > day) {
|
|
1032
|
+
this.addInterval(new Interval(day+1, interval.getEndDay(), 0, interval.getTo()));
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
//Delete
|
|
1037
|
+
this.removeInterval(i);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Redefines this date range intervals with a copy of the given ones
|
|
1046
|
+
*/
|
|
1047
|
+
Week.prototype.copyIntervals = function(intervals) {
|
|
1048
|
+
this._intervals = [];
|
|
1049
|
+
for(var i=0; i < intervals.length; i++) {
|
|
1050
|
+
if(intervals[i] != undefined) {
|
|
1051
|
+
this._intervals.push(structuredClone(intervals[i]));
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
//OTHER METHODS
|
|
1057
|
+
/**
|
|
1058
|
+
* Is this week defining the same intervals as the given one ?
|
|
1059
|
+
*/
|
|
1060
|
+
Week.prototype.sameAs = function(w) {
|
|
1061
|
+
return w.getAsMinutesArray().equals(this.getAsMinutesArray());
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* Class DateRange, defines a range of months, weeks or days.
|
|
1068
|
+
* A typical week or day will be associated.
|
|
1069
|
+
*/
|
|
1070
|
+
var DateRange = function(w) {
|
|
1071
|
+
//ATTRIBUTES
|
|
1072
|
+
/** The wide interval of this date range **/
|
|
1073
|
+
this._wideInterval = null;
|
|
1074
|
+
|
|
1075
|
+
/** The typical week or day associated **/
|
|
1076
|
+
this._typical = undefined;
|
|
1077
|
+
|
|
1078
|
+
//CONSTRUCTOR
|
|
1079
|
+
this.updateRange(w);
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
//ACCESSORS
|
|
1083
|
+
/**
|
|
1084
|
+
* Is this interval defining a typical day ?
|
|
1085
|
+
*/
|
|
1086
|
+
DateRange.prototype.definesTypicalDay = function() {
|
|
1087
|
+
return this._typical instanceof Day;
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Is this interval defining a typical week ?
|
|
1092
|
+
*/
|
|
1093
|
+
DateRange.prototype.definesTypicalWeek = function() {
|
|
1094
|
+
return this._typical instanceof Week;
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* @return The typical day or week
|
|
1099
|
+
*/
|
|
1100
|
+
DateRange.prototype.getTypical = function() {
|
|
1101
|
+
return this._typical;
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* @return The wide interval this date range concerns
|
|
1106
|
+
*/
|
|
1107
|
+
DateRange.prototype.getInterval = function() {
|
|
1108
|
+
return this._wideInterval;
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
//MODIFIERS
|
|
1112
|
+
/**
|
|
1113
|
+
* Changes the date range
|
|
1114
|
+
*/
|
|
1115
|
+
DateRange.prototype.updateRange = function(wide) {
|
|
1116
|
+
this._wideInterval = (wide != null) ? wide : new WideInterval().always();
|
|
1117
|
+
|
|
1118
|
+
//Create typical week/day
|
|
1119
|
+
if(this._typical == undefined) {
|
|
1120
|
+
switch(this._wideInterval.getType()) {
|
|
1121
|
+
case "day":
|
|
1122
|
+
if(this._wideInterval.getEnd() == null) {
|
|
1123
|
+
this._typical = new Day();
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
this._typical = new Week();
|
|
1127
|
+
}
|
|
1128
|
+
break;
|
|
1129
|
+
case "week":
|
|
1130
|
+
this._typical = new Week();
|
|
1131
|
+
break;
|
|
1132
|
+
case "month":
|
|
1133
|
+
this._typical = new Week();
|
|
1134
|
+
break;
|
|
1135
|
+
case "holiday":
|
|
1136
|
+
if(this._wideInterval.getStart().holiday == "SH") {
|
|
1137
|
+
this._typical = new Week();
|
|
1138
|
+
}
|
|
1139
|
+
else {
|
|
1140
|
+
this._typical = new Day();
|
|
1141
|
+
}
|
|
1142
|
+
break;
|
|
1143
|
+
case "always":
|
|
1144
|
+
this._typical = new Week();
|
|
1145
|
+
break;
|
|
1146
|
+
default:
|
|
1147
|
+
throw Error("Invalid interval type: "+this._wideInterval.getType());
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
//OTHER METHODS
|
|
1153
|
+
/**
|
|
1154
|
+
* Check if the typical day/week of this date range is the same as in the given date range
|
|
1155
|
+
* @param dr The other DateRange
|
|
1156
|
+
* @return True if same typical day/week
|
|
1157
|
+
*/
|
|
1158
|
+
DateRange.prototype.hasSameTypical = function(dr) {
|
|
1159
|
+
return this.definesTypicalDay() == dr.definesTypicalDay() && this._typical.sameAs(dr.getTypical());
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Does this date range contains the given date range (ie the second is a refinement of the first)
|
|
1164
|
+
* @param start The start of the date range
|
|
1165
|
+
* @param end The end of the date range
|
|
1166
|
+
* @return True if this date contains the given one (and is not strictly equal to)
|
|
1167
|
+
*/
|
|
1168
|
+
DateRange.prototype.isGeneralFor = function(dr) {
|
|
1169
|
+
return dr.definesTypicalDay() == this.definesTypicalDay() && this._wideInterval.contains(dr.getInterval());
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* An opening_hours time, such as "08:00" or "08:00-10:00" or "off" (if no start and end)
|
|
1176
|
+
* @param start The start minute (from midnight), can be null
|
|
1177
|
+
* @param end The end minute (from midnight), can be null
|
|
1178
|
+
*/
|
|
1179
|
+
var OhTime = function(start, end) {
|
|
1180
|
+
//ATTRIBUTES
|
|
1181
|
+
/** The start minute **/
|
|
1182
|
+
this._start = (start >= 0) ? start : null;
|
|
1183
|
+
|
|
1184
|
+
/** The end minute **/
|
|
1185
|
+
this._end = (end >= 0 && end != start) ? end : null;
|
|
1186
|
+
};
|
|
1187
|
+
|
|
1188
|
+
//ACCESSORS
|
|
1189
|
+
/**
|
|
1190
|
+
* @return The time in opening_hours format
|
|
1191
|
+
*/
|
|
1192
|
+
OhTime.prototype.get = function() {
|
|
1193
|
+
if(this._start === null && this._end === null) {
|
|
1194
|
+
return "off";
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
return this._timeString(this._start) + ((this._end == null) ? "" : "-" + this._timeString(this._end));
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* @return The start minutes
|
|
1203
|
+
*/
|
|
1204
|
+
OhTime.prototype.getStart = function() {
|
|
1205
|
+
return this._start;
|
|
1206
|
+
};
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* @return The end minutes
|
|
1210
|
+
*/
|
|
1211
|
+
OhTime.prototype.getEnd = function() {
|
|
1212
|
+
return this._end;
|
|
1213
|
+
};
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* @return True if same time
|
|
1217
|
+
*/
|
|
1218
|
+
OhTime.prototype.equals = function(t) {
|
|
1219
|
+
return this._start == t.getStart() && this._end == t.getEnd();
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
//OTHER METHODS
|
|
1223
|
+
/**
|
|
1224
|
+
* @return The hour in HH:MM format
|
|
1225
|
+
*/
|
|
1226
|
+
OhTime.prototype._timeString = function(minutes) {
|
|
1227
|
+
var h = Math.floor(minutes / 60);
|
|
1228
|
+
var period = "";
|
|
1229
|
+
var m = minutes % 60;
|
|
1230
|
+
return (h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + period;
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* An opening_hours date, such as "Apr 21", "week 1-15 Mo,Tu", "Apr-Dec Mo-Fr", "SH Su", ...
|
|
1237
|
+
* @param w The wide selector, as string
|
|
1238
|
+
* @param wt The wide selector type (month, week, day, holiday, always)
|
|
1239
|
+
* @param wd The weekdays, as integer array (0 to 6 = Monday to Sunday, -1 = single day date, -2 = PH)
|
|
1240
|
+
*/
|
|
1241
|
+
var OhDate = function(w, wt, wd) {
|
|
1242
|
+
//ATTRIBUTES
|
|
1243
|
+
/** Kind of wide date (month, week, day, holiday, always) **/
|
|
1244
|
+
this._wideType = wt;
|
|
1245
|
+
|
|
1246
|
+
/** Wide date **/
|
|
1247
|
+
this._wide = w;
|
|
1248
|
+
|
|
1249
|
+
/** Weekdays + PH **/
|
|
1250
|
+
this._weekdays = wd.sort();
|
|
1251
|
+
|
|
1252
|
+
/** Overwritten days (to allow create simpler rules) **/
|
|
1253
|
+
this._wdOver = [];
|
|
1254
|
+
|
|
1255
|
+
//CONSTRUCTOR
|
|
1256
|
+
if(w == null || wt == null || wd == null) {
|
|
1257
|
+
throw Error("Missing parameter");
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1261
|
+
//ACCESSORS
|
|
1262
|
+
/**
|
|
1263
|
+
* @return The wide type
|
|
1264
|
+
*/
|
|
1265
|
+
OhDate.prototype.getWideType = function() {
|
|
1266
|
+
return this._wideType;
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
/**
|
|
1270
|
+
* @return The monthday, month, week, SH (depends of type)
|
|
1271
|
+
*/
|
|
1272
|
+
OhDate.prototype.getWideValue = function() {
|
|
1273
|
+
return this._wide;
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
/**
|
|
1277
|
+
* @return The weekdays array
|
|
1278
|
+
*/
|
|
1279
|
+
OhDate.prototype.getWd = function() {
|
|
1280
|
+
return this._weekdays;
|
|
1281
|
+
};
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* @return The overwrittent weekdays array
|
|
1285
|
+
*/
|
|
1286
|
+
OhDate.prototype.getWdOver = function() {
|
|
1287
|
+
return this._wdOver;
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* @param a The other weekdays array
|
|
1292
|
+
* @return True if same weekdays as other object
|
|
1293
|
+
*/
|
|
1294
|
+
OhDate.prototype.sameWd = function(a) {
|
|
1295
|
+
return a.equals(this._weekdays);
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* @return The weekdays in opening_hours syntax
|
|
1300
|
+
*/
|
|
1301
|
+
OhDate.prototype.getWeekdays = function() {
|
|
1302
|
+
var result = "";
|
|
1303
|
+
var wd = this._weekdays.concat(this._wdOver).sort();
|
|
1304
|
+
|
|
1305
|
+
//PH as weekday
|
|
1306
|
+
if(wd.length > 0 && wd[0] == PH_WEEKDAY) {
|
|
1307
|
+
result = "PH";
|
|
1308
|
+
wd.shift();
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
//Check if we should create a continuous interval for week-end
|
|
1312
|
+
if(wd.length > 0 && wd.contains(6) && wd.contains(0) && (wd.contains(5) || wd.contains(1))) {
|
|
1313
|
+
//Find when the week-end starts
|
|
1314
|
+
var startWE = 6;
|
|
1315
|
+
var i=wd.length-2, stopLooking = false;
|
|
1316
|
+
while(!stopLooking && i >= 0) {
|
|
1317
|
+
if(wd[i] == wd[i+1] - 1) {
|
|
1318
|
+
startWE = wd[i];
|
|
1319
|
+
i--;
|
|
1320
|
+
}
|
|
1321
|
+
else {
|
|
1322
|
+
stopLooking = true;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
//Find when it stops
|
|
1327
|
+
i=1;
|
|
1328
|
+
stopLooking = false;
|
|
1329
|
+
var endWE = 0;
|
|
1330
|
+
|
|
1331
|
+
while(!stopLooking && i < wd.length) {
|
|
1332
|
+
if(wd[i-1] == wd[i] - 1) {
|
|
1333
|
+
endWE = wd[i];
|
|
1334
|
+
i++;
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
stopLooking = true;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
//If long enough, add it as first weekday interval
|
|
1342
|
+
var length = 7 - startWE + endWE + 1;
|
|
1343
|
+
|
|
1344
|
+
if(length >= 3 && startWE > endWE) {
|
|
1345
|
+
if(result.length > 0) { result += ","; }
|
|
1346
|
+
result += OSM_DAYS[startWE]+"-"+OSM_DAYS[endWE];
|
|
1347
|
+
|
|
1348
|
+
//Remove processed days
|
|
1349
|
+
var j=0;
|
|
1350
|
+
while(j < wd.length) {
|
|
1351
|
+
if(wd[j] <= endWE || wd[j] >= startWE) {
|
|
1352
|
+
wd.splice(j, 1);
|
|
1353
|
+
}
|
|
1354
|
+
else {
|
|
1355
|
+
j++;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
//Process only if not empty weekday list
|
|
1362
|
+
if(wd.length > 1 || (wd.length == 1 && wd[0] != -1)) {
|
|
1363
|
+
result += (result.length > 0) ? ","+OSM_DAYS[wd[0]] : OSM_DAYS[wd[0]];
|
|
1364
|
+
var firstInRow = wd[0];
|
|
1365
|
+
|
|
1366
|
+
for(var i=1; i < wd.length; i++) {
|
|
1367
|
+
//When days aren't following
|
|
1368
|
+
if(wd[i-1] != wd[i] - 1) {
|
|
1369
|
+
//Previous day range length > 1
|
|
1370
|
+
if(firstInRow != wd[i-1]) {
|
|
1371
|
+
//Two days
|
|
1372
|
+
if(wd[i-1] - firstInRow == 1) {
|
|
1373
|
+
result += ","+OSM_DAYS[wd[i-1]];
|
|
1374
|
+
}
|
|
1375
|
+
else {
|
|
1376
|
+
result += "-"+OSM_DAYS[wd[i-1]];
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
//Add the current day
|
|
1381
|
+
result += ","+OSM_DAYS[wd[i]];
|
|
1382
|
+
firstInRow = wd[i];
|
|
1383
|
+
}
|
|
1384
|
+
else if(i==wd.length-1) {
|
|
1385
|
+
if(wd[i] - firstInRow == 1) {
|
|
1386
|
+
result += ","+OSM_DAYS[wd[i]];
|
|
1387
|
+
}
|
|
1388
|
+
else {
|
|
1389
|
+
result += "-"+OSM_DAYS[wd[i]];
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
if(result == "Mo-Su") { result = ""; }
|
|
1396
|
+
|
|
1397
|
+
return result;
|
|
1398
|
+
};
|
|
1399
|
+
|
|
1400
|
+
/**
|
|
1401
|
+
* Is the given object of the same kind as this one
|
|
1402
|
+
* @return True if same weekdays and same wide type
|
|
1403
|
+
*/
|
|
1404
|
+
OhDate.prototype.sameKindAs = function(d) {
|
|
1405
|
+
return this._wideType == d.getWideType() && d.sameWd(this._weekdays);
|
|
1406
|
+
};
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* @return True if this object is equal to the given one
|
|
1410
|
+
*/
|
|
1411
|
+
OhDate.prototype.equals = function(o) {
|
|
1412
|
+
return o instanceof OhDate && this._wideType == o.getWideType() && this._wide == o.getWideValue() && o.sameWd(this._weekdays);
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
//MODIFIERS
|
|
1416
|
+
/**
|
|
1417
|
+
* Adds a new weekday in this date
|
|
1418
|
+
*/
|
|
1419
|
+
OhDate.prototype.addWeekday = function(wd) {
|
|
1420
|
+
if(!this._weekdays.contains(wd) && !this._wdOver.contains(wd)) {
|
|
1421
|
+
this._weekdays.push(wd);
|
|
1422
|
+
this._weekdays = this._weekdays.sort();
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
/**
|
|
1427
|
+
* Adds public holiday as a weekday of this date
|
|
1428
|
+
*/
|
|
1429
|
+
OhDate.prototype.addPhWeekday = function() {
|
|
1430
|
+
this.addWeekday(PH_WEEKDAY);
|
|
1431
|
+
};
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Adds an overwritten weekday, which can be included in this date and that will be overwritten in a following rule
|
|
1435
|
+
*/
|
|
1436
|
+
OhDate.prototype.addOverwrittenWeekday = function(wd) {
|
|
1437
|
+
if(!this._wdOver.contains(wd) && !this._weekdays.contains(wd)) {
|
|
1438
|
+
this._wdOver.push(wd);
|
|
1439
|
+
this._wdOver = this._wdOver.sort();
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
/**
|
|
1446
|
+
* An opening_hours rule, such as "Mo,Tu 08:00-18:00"
|
|
1447
|
+
*/
|
|
1448
|
+
var OhRule = function() {
|
|
1449
|
+
//ATTRIBUTES
|
|
1450
|
+
/** The date selectors **/
|
|
1451
|
+
this._date = [];
|
|
1452
|
+
|
|
1453
|
+
/** The time selectors **/
|
|
1454
|
+
this._time = [];
|
|
1455
|
+
};
|
|
1456
|
+
|
|
1457
|
+
//ACCESSORS
|
|
1458
|
+
/**
|
|
1459
|
+
* @return The date selectors, as an array
|
|
1460
|
+
*/
|
|
1461
|
+
OhRule.prototype.getDate = function() {
|
|
1462
|
+
return this._date;
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* @return The time selectors, as an array
|
|
1467
|
+
*/
|
|
1468
|
+
OhRule.prototype.getTime = function() {
|
|
1469
|
+
return this._time;
|
|
1470
|
+
};
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* @return The opening_hours value
|
|
1474
|
+
*/
|
|
1475
|
+
OhRule.prototype.get = function() {
|
|
1476
|
+
var result = "";
|
|
1477
|
+
|
|
1478
|
+
//Create date part
|
|
1479
|
+
if(this._date.length > 1 || this._date[0].getWideValue() != "") {
|
|
1480
|
+
//Add wide selectors
|
|
1481
|
+
for(var i=0, l=this._date.length; i < l; i++) {
|
|
1482
|
+
if(i > 0) {
|
|
1483
|
+
result += ",";
|
|
1484
|
+
}
|
|
1485
|
+
result += this._date[i].getWideValue();
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
//Add weekdays
|
|
1490
|
+
if(this._date.length > 0) {
|
|
1491
|
+
var wd = this._date[0].getWeekdays();
|
|
1492
|
+
if(wd.length > 0) {
|
|
1493
|
+
result += " "+wd;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
//Create time part
|
|
1498
|
+
if(this._time.length > 0) {
|
|
1499
|
+
result += " ";
|
|
1500
|
+
for(var i=0, l=this._time.length; i < l; i++) {
|
|
1501
|
+
if(i > 0) {
|
|
1502
|
+
result += ",";
|
|
1503
|
+
}
|
|
1504
|
+
result += this._time[i].get();
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
result += " off";
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
if(result.trim() == "00:00-24:00") { result = "24/7"; }
|
|
1512
|
+
|
|
1513
|
+
return result.trim();
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
/**
|
|
1517
|
+
* @return True if the given rule has the same time as this one
|
|
1518
|
+
*/
|
|
1519
|
+
OhRule.prototype.sameTime = function(o) {
|
|
1520
|
+
if(o == undefined || o == null || o.getTime().length != this._time.length) {
|
|
1521
|
+
return false;
|
|
1522
|
+
}
|
|
1523
|
+
else {
|
|
1524
|
+
for(var i=0, l=this._time.length; i < l; i++) {
|
|
1525
|
+
if(!this._time[i].equals(o.getTime()[i])) {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
|
|
1533
|
+
/**
|
|
1534
|
+
* Is this rule concerning off time ?
|
|
1535
|
+
*/
|
|
1536
|
+
OhRule.prototype.isOff = function() {
|
|
1537
|
+
return this._time.length == 0 || (this._time.length == 1 && this._time[0].getStart() == null);
|
|
1538
|
+
};
|
|
1539
|
+
|
|
1540
|
+
/**
|
|
1541
|
+
* Does the rule have any overwritten weekday ?
|
|
1542
|
+
*/
|
|
1543
|
+
OhRule.prototype.hasOverwrittenWeekday = function() {
|
|
1544
|
+
return this._date.length > 0 && this._date[0]._wdOver.length > 0;
|
|
1545
|
+
};
|
|
1546
|
+
|
|
1547
|
+
//MODIFIERS
|
|
1548
|
+
/**
|
|
1549
|
+
* Adds a weekday to all the dates
|
|
1550
|
+
*/
|
|
1551
|
+
OhRule.prototype.addWeekday = function(wd) {
|
|
1552
|
+
for(var i=0; i < this._date.length; i++) {
|
|
1553
|
+
this._date[i].addWeekday(wd);
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
|
|
1557
|
+
/**
|
|
1558
|
+
* Adds public holidays as weekday to all dates
|
|
1559
|
+
*/
|
|
1560
|
+
OhRule.prototype.addPhWeekday = function() {
|
|
1561
|
+
for(var i=0; i < this._date.length; i++) {
|
|
1562
|
+
this._date[i].addPhWeekday();
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
/**
|
|
1567
|
+
* Adds an overwritten weekday to all the dates
|
|
1568
|
+
*/
|
|
1569
|
+
OhRule.prototype.addOverwrittenWeekday = function(wd) {
|
|
1570
|
+
for(var i=0; i < this._date.length; i++) {
|
|
1571
|
+
this._date[i].addOverwrittenWeekday(wd);
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
/**
|
|
1576
|
+
* @param d A new date selector
|
|
1577
|
+
*/
|
|
1578
|
+
OhRule.prototype.addDate = function(d) {
|
|
1579
|
+
//Check param
|
|
1580
|
+
if(d == null || d == undefined || !d instanceof OhDate) {
|
|
1581
|
+
throw Error("Invalid parameter");
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
//Check if date can be added
|
|
1585
|
+
if(this._date.length == 0 || (this._date[0].getWideType() != "always" && this._date[0].sameKindAs(d))) {
|
|
1586
|
+
this._date.push(d);
|
|
1587
|
+
}
|
|
1588
|
+
else {
|
|
1589
|
+
if(this._date.length != 1 || this._date[0].getWideType() != "always" || !this._date[0].sameWd(d.getWd())) {
|
|
1590
|
+
throw Error("This date can't be added to this rule");
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1595
|
+
/**
|
|
1596
|
+
* @param t A new time selector
|
|
1597
|
+
*/
|
|
1598
|
+
OhRule.prototype.addTime = function(t) {
|
|
1599
|
+
if((this._time.length == 0 || this._time[0].get() != "off") && !this._time.contains(t)) {
|
|
1600
|
+
this._time.push(t);
|
|
1601
|
+
}
|
|
1602
|
+
else {
|
|
1603
|
+
throw Error("This time can't be added to this rule");
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
/**
|
|
1610
|
+
* Class OpeningHoursBuilder, creates opening_hours value from date range object
|
|
1611
|
+
*/
|
|
1612
|
+
var OpeningHoursBuilder = function() {};
|
|
1613
|
+
|
|
1614
|
+
//OTHER METHODS
|
|
1615
|
+
/**
|
|
1616
|
+
* Parses several date ranges to create an opening_hours string
|
|
1617
|
+
* @param dateRanges The date ranges to parse
|
|
1618
|
+
* @return The opening_hours string
|
|
1619
|
+
*/
|
|
1620
|
+
OpeningHoursBuilder.prototype.build = function(dateRanges) {
|
|
1621
|
+
var rules = [];
|
|
1622
|
+
var dateRange, ohrules, ohrule, ohruleAdded, ruleId, rangeGeneral, rangeGeneralFor;
|
|
1623
|
+
|
|
1624
|
+
//Read each date range
|
|
1625
|
+
for(var rangeId=0, l=dateRanges.length; rangeId < l; rangeId++) {
|
|
1626
|
+
dateRange = dateRanges[rangeId];
|
|
1627
|
+
|
|
1628
|
+
if(dateRange != undefined) {
|
|
1629
|
+
//Check if the defined typical week/day is not strictly equal to a previous wider rule
|
|
1630
|
+
rangeGeneral = null;
|
|
1631
|
+
rangeGeneralFor = null;
|
|
1632
|
+
var rangeGenId=rangeId-1;
|
|
1633
|
+
while(rangeGenId >= 0 && rangeGeneral == null) {
|
|
1634
|
+
if(dateRanges[rangeGenId] != undefined) {
|
|
1635
|
+
generalFor = dateRanges[rangeGenId].isGeneralFor(dateRange);
|
|
1636
|
+
if(
|
|
1637
|
+
dateRanges[rangeGenId].hasSameTypical(dateRange)
|
|
1638
|
+
&& (
|
|
1639
|
+
dateRanges[rangeGenId].getInterval().equals(dateRange.getInterval())
|
|
1640
|
+
|| generalFor
|
|
1641
|
+
)
|
|
1642
|
+
) {
|
|
1643
|
+
rangeGeneral = rangeGenId;
|
|
1644
|
+
}
|
|
1645
|
+
else if(generalFor && dateRanges[rangeGenId].definesTypicalWeek() && dateRange.definesTypicalWeek()) {
|
|
1646
|
+
rangeGeneralFor = rangeGenId; //Keep this ID to make differences in order to simplify result
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
rangeGenId--;
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
if(rangeId == 0 || rangeGeneral == null) {
|
|
1653
|
+
//Get rules for this date range
|
|
1654
|
+
if(dateRange.definesTypicalWeek()) {
|
|
1655
|
+
if(rangeGeneralFor != null) {
|
|
1656
|
+
ohrules = this._buildWeekDiff(dateRange, dateRanges[rangeGeneralFor]);
|
|
1657
|
+
}
|
|
1658
|
+
else {
|
|
1659
|
+
ohrules = this._buildWeek(dateRange);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
else {
|
|
1663
|
+
ohrules = this._buildDay(dateRange);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
//Process each rule
|
|
1667
|
+
for(var ohruleId=0, orl=ohrules.length; ohruleId < orl; ohruleId++) {
|
|
1668
|
+
ohrule = ohrules[ohruleId];
|
|
1669
|
+
ohruleAdded = false;
|
|
1670
|
+
ruleId = 0;
|
|
1671
|
+
|
|
1672
|
+
//Try to add them to previously defined ones
|
|
1673
|
+
while(!ohruleAdded && ruleId < rules.length) {
|
|
1674
|
+
//Identical one
|
|
1675
|
+
if(rules[ruleId].sameTime(ohrule)) {
|
|
1676
|
+
try {
|
|
1677
|
+
for(var dateId=0, dl=ohrule.getDate().length; dateId < dl; dateId++) {
|
|
1678
|
+
rules[ruleId].addDate(ohrule.getDate()[dateId]);
|
|
1679
|
+
}
|
|
1680
|
+
ohruleAdded = true;
|
|
1681
|
+
}
|
|
1682
|
+
//If first date not same kind as in found rule, continue
|
|
1683
|
+
catch(e) {
|
|
1684
|
+
//But before, try to merge PH with always weekdays
|
|
1685
|
+
if(
|
|
1686
|
+
ohrule.getDate()[0].getWideType() == "holiday"
|
|
1687
|
+
&& ohrule.getDate()[0].getWideValue() == "PH"
|
|
1688
|
+
&& rules[ruleId].getDate()[0].getWideType() == "always"
|
|
1689
|
+
) {
|
|
1690
|
+
rules[ruleId].addPhWeekday();
|
|
1691
|
+
ohruleAdded = true;
|
|
1692
|
+
}
|
|
1693
|
+
else if(
|
|
1694
|
+
rules[ruleId].getDate()[0].getWideType() == "holiday"
|
|
1695
|
+
&& rules[ruleId].getDate()[0].getWideValue() == "PH"
|
|
1696
|
+
&& ohrule.getDate()[0].getWideType() == "always"
|
|
1697
|
+
) {
|
|
1698
|
+
ohrule.addPhWeekday();
|
|
1699
|
+
rules[ruleId] = ohrule;
|
|
1700
|
+
ohruleAdded = true;
|
|
1701
|
+
}
|
|
1702
|
+
else {
|
|
1703
|
+
ruleId++;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
else {
|
|
1708
|
+
ruleId++;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
//If not, add as new rule
|
|
1713
|
+
if(!ohruleAdded) {
|
|
1714
|
+
rules.push(ohrule);
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
//If some overwritten weekdays are still in last rule
|
|
1718
|
+
if(ohruleId == orl - 1 && ohrule.hasOverwrittenWeekday()) {
|
|
1719
|
+
var ohruleOWD = new OhRule();
|
|
1720
|
+
for(var ohruleDateId = 0; ohruleDateId < ohrule.getDate().length; ohruleDateId++) {
|
|
1721
|
+
ohruleOWD.addDate(
|
|
1722
|
+
new OhDate(
|
|
1723
|
+
ohrule.getDate()[ohruleDateId].getWideValue(),
|
|
1724
|
+
ohrule.getDate()[ohruleDateId].getWideType(),
|
|
1725
|
+
ohrule.getDate()[ohruleDateId].getWdOver()
|
|
1726
|
+
)
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
ohruleOWD.addTime(new OhTime());
|
|
1730
|
+
ohrules.push(ohruleOWD);
|
|
1731
|
+
orl++;
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
//Create result string
|
|
1739
|
+
var result = "";
|
|
1740
|
+
for(var ruleId=0, l=rules.length; ruleId < l; ruleId++) {
|
|
1741
|
+
if(ruleId > 0) { result += "; "; }
|
|
1742
|
+
result += rules[ruleId].get();
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
return result;
|
|
1746
|
+
};
|
|
1747
|
+
|
|
1748
|
+
|
|
1749
|
+
/***********************
|
|
1750
|
+
* Top level functions *
|
|
1751
|
+
***********************/
|
|
1752
|
+
|
|
1753
|
+
/**
|
|
1754
|
+
* Creates rules for a given typical day
|
|
1755
|
+
* @param dateRange The date range defining a typical day
|
|
1756
|
+
* @return An array of OhRules
|
|
1757
|
+
*/
|
|
1758
|
+
OpeningHoursBuilder.prototype._buildDay = function(dateRange) {
|
|
1759
|
+
var intervals = dateRange.getTypical().getIntervals(true);
|
|
1760
|
+
var interval;
|
|
1761
|
+
|
|
1762
|
+
//Create rule
|
|
1763
|
+
var rule = new OhRule();
|
|
1764
|
+
var date = new OhDate(dateRange.getInterval().getTimeSelector(), dateRange.getInterval().getType(), [ -1 ]);
|
|
1765
|
+
rule.addDate(date);
|
|
1766
|
+
|
|
1767
|
+
//Read time
|
|
1768
|
+
for(var i=0, l=intervals.length; i < l; i++) {
|
|
1769
|
+
interval = intervals[i];
|
|
1770
|
+
|
|
1771
|
+
if(interval != undefined) {
|
|
1772
|
+
rule.addTime(new OhTime(interval.getFrom(), interval.getTo()));
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
return [ rule ];
|
|
1777
|
+
};
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Create rules for a date range defining a typical week
|
|
1781
|
+
* Algorithm inspired by OpeningHoursEdit plugin for JOSM
|
|
1782
|
+
* @param dateRange The date range defining a typical day
|
|
1783
|
+
* @return An array of OhRules
|
|
1784
|
+
*/
|
|
1785
|
+
OpeningHoursBuilder.prototype._buildWeek = function(dateRange) {
|
|
1786
|
+
var result = [];
|
|
1787
|
+
var intervals = dateRange.getTypical().getIntervals(true);
|
|
1788
|
+
var interval, rule, date;
|
|
1789
|
+
|
|
1790
|
+
/*
|
|
1791
|
+
* Create time intervals per day
|
|
1792
|
+
*/
|
|
1793
|
+
var timeIntervals = this._createTimeIntervals(dateRange.getInterval().getTimeSelector(), dateRange.getInterval().getType(), intervals);
|
|
1794
|
+
var monday0 = timeIntervals[0];
|
|
1795
|
+
var sunday24 = timeIntervals[1];
|
|
1796
|
+
var days = timeIntervals[2];
|
|
1797
|
+
|
|
1798
|
+
//Create continuous night for monday-sunday
|
|
1799
|
+
days = this._nightMonSun(days, monday0, sunday24);
|
|
1800
|
+
|
|
1801
|
+
/*
|
|
1802
|
+
* Group rules with same time
|
|
1803
|
+
*/
|
|
1804
|
+
// 0 means nothing done with this day yet
|
|
1805
|
+
// 8 means the day is off
|
|
1806
|
+
// -8 means the day is off and should be shown
|
|
1807
|
+
// 0<x<8 means the day have the openinghours of day x
|
|
1808
|
+
// -8<x<0 means nothing done with this day yet, but it intersects a
|
|
1809
|
+
// range of days with same opening_hours
|
|
1810
|
+
var daysStatus = [];
|
|
1811
|
+
|
|
1812
|
+
//Init status
|
|
1813
|
+
for(var i=0; i < OSM_DAYS.length; i++) {
|
|
1814
|
+
daysStatus[i] = 0;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
//Read status
|
|
1818
|
+
for(var i=0; i < days.length; i++) {
|
|
1819
|
+
if(days[i].isOff() && daysStatus[i] == 0) {
|
|
1820
|
+
daysStatus[i] = 8;
|
|
1821
|
+
}
|
|
1822
|
+
else if(days[i].isOff() && daysStatus[i] < 0 && daysStatus[i] > -8) {
|
|
1823
|
+
daysStatus[i] = -8;
|
|
1824
|
+
|
|
1825
|
+
//Try to merge with another off day
|
|
1826
|
+
var merged = false, mdOff = 0;
|
|
1827
|
+
while(!merged && mdOff < i) {
|
|
1828
|
+
if(days[mdOff].isOff()) {
|
|
1829
|
+
days[mdOff].addWeekday(i);
|
|
1830
|
+
merged = true;
|
|
1831
|
+
}
|
|
1832
|
+
else {
|
|
1833
|
+
mdOff++;
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
//If not merged, add it
|
|
1838
|
+
if(!merged) {
|
|
1839
|
+
result.push(days[i]);
|
|
1840
|
+
}
|
|
1841
|
+
} else if (daysStatus[i] <= 0 && daysStatus[i] > -8) {
|
|
1842
|
+
daysStatus[i] = i + 1;
|
|
1843
|
+
var lastSameDay = i;
|
|
1844
|
+
var sameDayCount = 1;
|
|
1845
|
+
|
|
1846
|
+
for(let j = i + 1; j < days.length; j++) {
|
|
1847
|
+
if (days[i].sameTime(days[j])) {
|
|
1848
|
+
daysStatus[j] = i + 1;
|
|
1849
|
+
days[i].addWeekday(j);
|
|
1850
|
+
lastSameDay = j;
|
|
1851
|
+
sameDayCount++;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
if (sameDayCount == 1) {
|
|
1855
|
+
// a single Day with this special opening_hours
|
|
1856
|
+
result.push(days[i]);
|
|
1857
|
+
} else if (sameDayCount == 2) {
|
|
1858
|
+
// exactly two Days with this special opening_hours
|
|
1859
|
+
days[i].addWeekday(lastSameDay);
|
|
1860
|
+
result.push(days[i]);
|
|
1861
|
+
} else if (sameDayCount > 2) {
|
|
1862
|
+
// more than two Days with this special opening_hours
|
|
1863
|
+
for (let j = i + 1; j < lastSameDay; j++) {
|
|
1864
|
+
if (daysStatus[j] == 0) {
|
|
1865
|
+
daysStatus[j] = -i - 1;
|
|
1866
|
+
days[i].addOverwrittenWeekday(j);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
days[i].addWeekday(lastSameDay);
|
|
1870
|
+
result.push(days[i]);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
result = this._mergeDays(result);
|
|
1876
|
+
|
|
1877
|
+
return result;
|
|
1878
|
+
};
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* Reads a week to create an opening_hours string for weeks which are overwriting a previous one
|
|
1882
|
+
* @param dateRange The date range defining a typical day
|
|
1883
|
+
* @param generalDateRange The date range which is wider than this one
|
|
1884
|
+
* @return An array of OhRules
|
|
1885
|
+
*/
|
|
1886
|
+
OpeningHoursBuilder.prototype._buildWeekDiff = function(dateRange, generalDateRange) {
|
|
1887
|
+
var intervals = dateRange.getTypical().getIntervalsDiff(generalDateRange.getTypical());
|
|
1888
|
+
|
|
1889
|
+
/*
|
|
1890
|
+
* Create time intervals per day
|
|
1891
|
+
*/
|
|
1892
|
+
//Open
|
|
1893
|
+
var timeIntervals = this._createTimeIntervals(dateRange.getInterval().getTimeSelector(), dateRange.getInterval().getType(), intervals.open);
|
|
1894
|
+
var monday0 = timeIntervals[0];
|
|
1895
|
+
var sunday24 = timeIntervals[1];
|
|
1896
|
+
var days = timeIntervals[2];
|
|
1897
|
+
|
|
1898
|
+
//Closed
|
|
1899
|
+
for(var i=0, l=intervals.closed.length; i < l; i++) {
|
|
1900
|
+
interval = intervals.closed[i];
|
|
1901
|
+
|
|
1902
|
+
for(var j=interval.getStartDay(); j <= interval.getEndDay(); j++) {
|
|
1903
|
+
days[j].addTime(new OhTime());
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
//Create continuous night for monday-sunday
|
|
1908
|
+
days = this._nightMonSun(days, monday0, sunday24);
|
|
1909
|
+
|
|
1910
|
+
/*
|
|
1911
|
+
* Group rules with same time
|
|
1912
|
+
*/
|
|
1913
|
+
// 0 means nothing done with this day yet
|
|
1914
|
+
// 8 means the day is off
|
|
1915
|
+
// -8 means the day is off and should be shown
|
|
1916
|
+
// 0<x<8 means the day have the openinghours of day x
|
|
1917
|
+
// -8<x<0 means nothing done with this day yet, but it intersects a
|
|
1918
|
+
// range of days with same opening_hours
|
|
1919
|
+
var daysStatus = [];
|
|
1920
|
+
|
|
1921
|
+
//Init status
|
|
1922
|
+
for(var i=0; i < OSM_DAYS.length; i++) {
|
|
1923
|
+
daysStatus[i] = 0;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
//Read rules
|
|
1927
|
+
var result = [];
|
|
1928
|
+
for(var i=0; i < days.length; i++) {
|
|
1929
|
+
//Off day which must be shown
|
|
1930
|
+
if(days[i].isOff() && days[i].getTime().length == 1) {
|
|
1931
|
+
daysStatus[i] = -8;
|
|
1932
|
+
|
|
1933
|
+
//Try to merge with another off day
|
|
1934
|
+
var merged = false, mdOff = 0;
|
|
1935
|
+
while(!merged && mdOff < i) {
|
|
1936
|
+
if(days[mdOff].isOff() && days[mdOff].getTime().length == 1) {
|
|
1937
|
+
days[mdOff].addWeekday(i);
|
|
1938
|
+
merged = true;
|
|
1939
|
+
}
|
|
1940
|
+
else {
|
|
1941
|
+
mdOff++;
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
//If not merged, add it
|
|
1946
|
+
if(!merged) {
|
|
1947
|
+
result.push(days[i]);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
//Off day which must be hidden
|
|
1951
|
+
else if(days[i].isOff() && days[i].getTime().length == 0) {
|
|
1952
|
+
daysStatus[i] = 8;
|
|
1953
|
+
}
|
|
1954
|
+
//Non-processed day
|
|
1955
|
+
else if(daysStatus[i] <= 0 && daysStatus[i] > -8) {
|
|
1956
|
+
daysStatus[i] = i+1;
|
|
1957
|
+
var sameDayCount = 1;
|
|
1958
|
+
var lastSameDay = i;
|
|
1959
|
+
|
|
1960
|
+
result.push(days[i]);
|
|
1961
|
+
|
|
1962
|
+
for(let j = i + 1; j < days.length; j++) {
|
|
1963
|
+
if (days[i].sameTime(days[j])) {
|
|
1964
|
+
daysStatus[j] = i + 1;
|
|
1965
|
+
days[i].addWeekday(j);
|
|
1966
|
+
lastSameDay = j;
|
|
1967
|
+
sameDayCount++;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
if (sameDayCount == 1) {
|
|
1971
|
+
// a single Day with this special opening_hours
|
|
1972
|
+
result.push(days[i]);
|
|
1973
|
+
} else if (sameDayCount == 2) {
|
|
1974
|
+
// exactly two Days with this special opening_hours
|
|
1975
|
+
days[i].addWeekday(lastSameDay);
|
|
1976
|
+
result.push(days[i]);
|
|
1977
|
+
} else if (sameDayCount > 2) {
|
|
1978
|
+
// more than two Days with this special opening_hours
|
|
1979
|
+
for (let j = i + 1; j < lastSameDay; j++) {
|
|
1980
|
+
if (daysStatus[j] == 0) {
|
|
1981
|
+
daysStatus[j] = -i - 1;
|
|
1982
|
+
if(days[j].getTime().length > 0) {
|
|
1983
|
+
days[i].addOverwrittenWeekday(j);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
days[i].addWeekday(lastSameDay);
|
|
1988
|
+
result.push(days[i]);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
result = this._mergeDays(result);
|
|
1994
|
+
|
|
1995
|
+
return result;
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
|
|
1999
|
+
/****************************************
|
|
2000
|
+
* Utility functions for top-level ones *
|
|
2001
|
+
****************************************/
|
|
2002
|
+
|
|
2003
|
+
/**
|
|
2004
|
+
* Merge days with same opening time
|
|
2005
|
+
*/
|
|
2006
|
+
OpeningHoursBuilder.prototype._mergeDays = function(rules) {
|
|
2007
|
+
if(rules.length == 0) { return rules; }
|
|
2008
|
+
|
|
2009
|
+
var result = [];
|
|
2010
|
+
var dateMerged;
|
|
2011
|
+
|
|
2012
|
+
result.push(rules[0]);
|
|
2013
|
+
var dm=0, wds;
|
|
2014
|
+
for(var d=1; d < rules.length; d++) {
|
|
2015
|
+
dateMerged = false;
|
|
2016
|
+
dm = 0;
|
|
2017
|
+
while(!dateMerged && dm < d) {
|
|
2018
|
+
if(rules[dm].sameTime(rules[d])) {
|
|
2019
|
+
wds = rules[d].getDate()[0].getWd();
|
|
2020
|
+
for(var wd=0; wd < wds.length; wd++) {
|
|
2021
|
+
rules[dm].addWeekday(wds[wd]);
|
|
2022
|
+
}
|
|
2023
|
+
dateMerged = true;
|
|
2024
|
+
}
|
|
2025
|
+
dm++;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
if(!dateMerged) {
|
|
2029
|
+
result.push(rules[d]);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
return result;
|
|
2034
|
+
};
|
|
2035
|
+
|
|
2036
|
+
/**
|
|
2037
|
+
* Creates time intervals for each day
|
|
2038
|
+
* @return [ monday0, sunday24, days ]
|
|
2039
|
+
*/
|
|
2040
|
+
OpeningHoursBuilder.prototype._createTimeIntervals = function(timeSelector, type, intervals) {
|
|
2041
|
+
var monday0 = -1;
|
|
2042
|
+
var sunday24 = -1;
|
|
2043
|
+
var days = [];
|
|
2044
|
+
var interval;
|
|
2045
|
+
|
|
2046
|
+
//Create rule for each day of the week
|
|
2047
|
+
for(var i=0; i < 7; i++) {
|
|
2048
|
+
days.push(new OhRule());
|
|
2049
|
+
days[i].addDate(new OhDate(timeSelector, type, [ i ]));
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
for(var i=0, l=intervals.length; i < l; i++) {
|
|
2053
|
+
interval = intervals[i];
|
|
2054
|
+
|
|
2055
|
+
if(interval != undefined) {
|
|
2056
|
+
//Handle sunday 24:00 with monday 00:00
|
|
2057
|
+
if(interval.getStartDay() == DAYS_MAX && interval.getEndDay() == DAYS_MAX && interval.getTo() == MINUTES_MAX) {
|
|
2058
|
+
sunday24 = interval.getFrom();
|
|
2059
|
+
}
|
|
2060
|
+
if(interval.getStartDay() == 0 && interval.getEndDay() == 0 && interval.getFrom() == 0) {
|
|
2061
|
+
monday0 = interval.getTo();
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
try {
|
|
2065
|
+
//Interval in a single day
|
|
2066
|
+
if(interval.getStartDay() == interval.getEndDay()) {
|
|
2067
|
+
days[interval.getStartDay()].addTime(
|
|
2068
|
+
new OhTime(interval.getFrom(), interval.getTo())
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
//Interval on two days
|
|
2072
|
+
else if(interval.getEndDay() - interval.getStartDay() == 1) {
|
|
2073
|
+
//Continuous night
|
|
2074
|
+
if(interval.getFrom() > interval.getTo()) {
|
|
2075
|
+
days[interval.getStartDay()].addTime(
|
|
2076
|
+
new OhTime(interval.getFrom(), interval.getTo())
|
|
2077
|
+
);
|
|
2078
|
+
}
|
|
2079
|
+
//Separated days
|
|
2080
|
+
else {
|
|
2081
|
+
days[interval.getStartDay()].addTime(
|
|
2082
|
+
new OhTime(interval.getFrom(), MINUTES_MAX)
|
|
2083
|
+
);
|
|
2084
|
+
days[interval.getEndDay()].addTime(
|
|
2085
|
+
new OhTime(0, interval.getTo())
|
|
2086
|
+
);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
//Interval on more than two days
|
|
2090
|
+
else {
|
|
2091
|
+
for(var j=interval.getStartDay(), end=interval.getEndDay(); j <= end; j++) {
|
|
2092
|
+
if(j == interval.getStartDay()) {
|
|
2093
|
+
days[j].addTime(
|
|
2094
|
+
new OhTime(interval.getFrom(), MINUTES_MAX)
|
|
2095
|
+
);
|
|
2096
|
+
}
|
|
2097
|
+
else if(j == interval.getEndDay()) {
|
|
2098
|
+
days[j].addTime(
|
|
2099
|
+
new OhTime(0, interval.getTo())
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
else {
|
|
2103
|
+
days[j].addTime(
|
|
2104
|
+
new OhTime(0, MINUTES_MAX)
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
catch(e) {
|
|
2111
|
+
console.warn(e);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
return [ monday0, sunday24, days ];
|
|
2117
|
+
};
|
|
2118
|
+
|
|
2119
|
+
/**
|
|
2120
|
+
* Changes days array to make sunday - monday night continuous if needed
|
|
2121
|
+
*/
|
|
2122
|
+
OpeningHoursBuilder.prototype._nightMonSun = function(days, monday0, sunday24) {
|
|
2123
|
+
if(monday0 >= 0 && sunday24 >= 0 && monday0 < sunday24) {
|
|
2124
|
+
days[0].getTime().sort(this._sortOhTime);
|
|
2125
|
+
days[6].getTime().sort(this._sortOhTime);
|
|
2126
|
+
|
|
2127
|
+
//Change sunday interval
|
|
2128
|
+
days[6].getTime()[days[6].getTime().length-1] = new OhTime(sunday24, monday0);
|
|
2129
|
+
|
|
2130
|
+
//Remove monday interval
|
|
2131
|
+
days[0].getTime().shift();
|
|
2132
|
+
}
|
|
2133
|
+
return days;
|
|
2134
|
+
};
|
|
2135
|
+
|
|
2136
|
+
/**
|
|
2137
|
+
* Sort OhTime objects by start hour
|
|
2138
|
+
*/
|
|
2139
|
+
OpeningHoursBuilder.prototype._sortOhTime = function(a, b) {
|
|
2140
|
+
return a.getStart() - b.getStart();
|
|
2141
|
+
};
|
|
2142
|
+
|
|
2143
|
+
|
|
2144
|
+
|
|
2145
|
+
/**
|
|
2146
|
+
* Class OpeningHoursParser, creates DateRange/Week/Day objects from opening_hours string
|
|
2147
|
+
* Based on a subpart of grammar defined at https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification
|
|
2148
|
+
*/
|
|
2149
|
+
var OpeningHoursParser = function() {
|
|
2150
|
+
//CONSTANTS
|
|
2151
|
+
this.RGX_RULE_MODIFIER = /^(open|closed|off)$/i;
|
|
2152
|
+
this.RGX_WEEK_KEY = /^week$/;
|
|
2153
|
+
this.RGX_WEEK_VAL = /^([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(,([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*\:?$/;
|
|
2154
|
+
this.RGX_MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))?\:?$/;
|
|
2155
|
+
this.RGX_MONTHDAY = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([012]?[0-9]|3[01])(\-((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) )?([012]?[0-9]|3[01]))?\:?$/;
|
|
2156
|
+
this.RGX_TIME = /^((([01]?[0-9]|2[01234])\:[012345][0-9](\-([01]?[0-9]|2[01234])\:[012345][0-9])?(,([01]?[0-9]|2[01234])\:[012345][0-9](\-([01]?[0-9]|2[01234])\:[012345][0-9])?)*)|(24\/7))$/;
|
|
2157
|
+
this.RGX_WEEKDAY = /^(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH|SH|easter))(,(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH|SH|easter)))*$/;
|
|
2158
|
+
this.RGX_HOLIDAY = /^(PH|SH|easter)$/;
|
|
2159
|
+
this.RGX_WD = /^(Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?$/;
|
|
2160
|
+
};
|
|
2161
|
+
|
|
2162
|
+
//OTHER METHODS
|
|
2163
|
+
/**
|
|
2164
|
+
* Parses the given opening_hours string
|
|
2165
|
+
* @param oh The opening_hours string
|
|
2166
|
+
* @return An array of date ranges
|
|
2167
|
+
*/
|
|
2168
|
+
OpeningHoursParser.prototype.parse = function(oh) {
|
|
2169
|
+
var result = [];
|
|
2170
|
+
|
|
2171
|
+
//Separate each block
|
|
2172
|
+
var blocks = oh.split(';');
|
|
2173
|
+
|
|
2174
|
+
/*
|
|
2175
|
+
* Blocks parsing
|
|
2176
|
+
* Each block can be divided in three parts: wide range selector, small range selector, rule modifier.
|
|
2177
|
+
* The last two are simpler to parse, so we start to read rule modifier, then small range selector.
|
|
2178
|
+
* All the lasting tokens are part of wide range selector.
|
|
2179
|
+
*/
|
|
2180
|
+
|
|
2181
|
+
var block, tokens, currentToken, ruleModifier, timeSelector, weekdaySelector, wideRangeSelector;
|
|
2182
|
+
var singleTime, from, to, times;
|
|
2183
|
+
var singleWeekday, wdStart, wdEnd, wdFrom, wdTo, holidays, weekdays;
|
|
2184
|
+
var monthSelector, weekSelector, weeks, singleWeek, weekFrom, weekTo, singleMonth, months, monthFrom, monthTo;
|
|
2185
|
+
var dateRanges, dateRange, drObj, foundDateRange, resDrId;
|
|
2186
|
+
|
|
2187
|
+
//Read each block
|
|
2188
|
+
for(var i=0, li=blocks.length; i < li; i++) {
|
|
2189
|
+
block = blocks[i].trim();
|
|
2190
|
+
|
|
2191
|
+
if(block.length == 0) { continue; } //Don't parse empty blocks
|
|
2192
|
+
|
|
2193
|
+
tokens = this._tokenize(block);
|
|
2194
|
+
currentToken = tokens.length - 1;
|
|
2195
|
+
ruleModifier = null;
|
|
2196
|
+
timeSelector = null;
|
|
2197
|
+
weekdaySelector = null;
|
|
2198
|
+
wideRangeSelector = null;
|
|
2199
|
+
|
|
2200
|
+
//console.log(tokens);
|
|
2201
|
+
|
|
2202
|
+
/*
|
|
2203
|
+
* Rule modifier (open, closed, off)
|
|
2204
|
+
*/
|
|
2205
|
+
if(currentToken >= 0 && this._isRuleModifier(tokens[currentToken])) {
|
|
2206
|
+
//console.log("rule modifier",tokens[currentToken]);
|
|
2207
|
+
ruleModifier = tokens[currentToken].toLowerCase();
|
|
2208
|
+
currentToken--;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
/*
|
|
2212
|
+
* Small range selectors
|
|
2213
|
+
*/
|
|
2214
|
+
from = null;
|
|
2215
|
+
to = null;
|
|
2216
|
+
times = []; //Time intervals in minutes
|
|
2217
|
+
|
|
2218
|
+
//Time selector
|
|
2219
|
+
if(currentToken >= 0 && this._isTime(tokens[currentToken])) {
|
|
2220
|
+
timeSelector = tokens[currentToken];
|
|
2221
|
+
|
|
2222
|
+
if(timeSelector == "24/7") {
|
|
2223
|
+
times.push({from: 0, to: 24*60});
|
|
2224
|
+
}
|
|
2225
|
+
else {
|
|
2226
|
+
//Divide each time interval
|
|
2227
|
+
timeSelector = timeSelector.split(',');
|
|
2228
|
+
for(var ts=0, tsl = timeSelector.length; ts < tsl; ts++) {
|
|
2229
|
+
//Separate start and end values
|
|
2230
|
+
singleTime = timeSelector[ts].split('-');
|
|
2231
|
+
from = this._asMinutes(singleTime[0]);
|
|
2232
|
+
if(singleTime.length > 1) {
|
|
2233
|
+
to = this._asMinutes(singleTime[1]);
|
|
2234
|
+
}
|
|
2235
|
+
else {
|
|
2236
|
+
to = from;
|
|
2237
|
+
}
|
|
2238
|
+
times.push({from: from, to: to});
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
currentToken--;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
holidays = [];
|
|
2246
|
+
weekdays = [];
|
|
2247
|
+
|
|
2248
|
+
//Weekday selector
|
|
2249
|
+
if(timeSelector == "24/7") {
|
|
2250
|
+
weekdays.push({from: 0, to: 6});
|
|
2251
|
+
}
|
|
2252
|
+
else if(currentToken >= 0 && this._isWeekday(tokens[currentToken])) {
|
|
2253
|
+
weekdaySelector = tokens[currentToken];
|
|
2254
|
+
|
|
2255
|
+
//Divide each weekday
|
|
2256
|
+
weekdaySelector = weekdaySelector.split(',');
|
|
2257
|
+
|
|
2258
|
+
for(var wds=0, wdsl = weekdaySelector.length; wds < wdsl; wds++) {
|
|
2259
|
+
singleWeekday = weekdaySelector[wds];
|
|
2260
|
+
|
|
2261
|
+
//Holiday
|
|
2262
|
+
if(this.RGX_HOLIDAY.test(singleWeekday)) {
|
|
2263
|
+
holidays.push(singleWeekday);
|
|
2264
|
+
}
|
|
2265
|
+
//Weekday interval
|
|
2266
|
+
else if(this.RGX_WD.test(singleWeekday)) {
|
|
2267
|
+
singleWeekday = singleWeekday.split('-');
|
|
2268
|
+
wdFrom = OSM_DAYS.indexOf(singleWeekday[0]);
|
|
2269
|
+
if(singleWeekday.length > 1) {
|
|
2270
|
+
wdTo = OSM_DAYS.indexOf(singleWeekday[1]);
|
|
2271
|
+
}
|
|
2272
|
+
else {
|
|
2273
|
+
wdTo = wdFrom;
|
|
2274
|
+
}
|
|
2275
|
+
weekdays.push({from: wdFrom, to: wdTo});
|
|
2276
|
+
}
|
|
2277
|
+
else {
|
|
2278
|
+
throw new Error("Invalid weekday interval: "+singleWeekday);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
currentToken--;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
/*
|
|
2286
|
+
* Wide range selector
|
|
2287
|
+
*/
|
|
2288
|
+
weeks = [];
|
|
2289
|
+
months = [];
|
|
2290
|
+
|
|
2291
|
+
if(currentToken >= 0) {
|
|
2292
|
+
wideRangeSelector = tokens[0];
|
|
2293
|
+
for(var ct=1; ct <= currentToken; ct++) {
|
|
2294
|
+
wideRangeSelector += " "+tokens[ct];
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
if(wideRangeSelector.length > 0) {
|
|
2298
|
+
wideRangeSelector = wideRangeSelector.replace(/\:$/g, '').split('week'); //0 = Month or SH, 1 = weeks
|
|
2299
|
+
|
|
2300
|
+
//Month or SH
|
|
2301
|
+
monthSelector = wideRangeSelector[0].trim();
|
|
2302
|
+
if(monthSelector.length == 0) { monthSelector = null; }
|
|
2303
|
+
|
|
2304
|
+
//Weeks
|
|
2305
|
+
if(wideRangeSelector.length > 1) {
|
|
2306
|
+
weekSelector = wideRangeSelector[1].trim();
|
|
2307
|
+
if(weekSelector.length == 0) { weekSelector = null; }
|
|
2308
|
+
}
|
|
2309
|
+
else { weekSelector = null; }
|
|
2310
|
+
|
|
2311
|
+
if(monthSelector != null && weekSelector != null) {
|
|
2312
|
+
throw new Error("Unsupported simultaneous month and week selector");
|
|
2313
|
+
}
|
|
2314
|
+
else if(monthSelector != null) {
|
|
2315
|
+
monthSelector = monthSelector.split(',');
|
|
2316
|
+
|
|
2317
|
+
for(var ms=0, msl = monthSelector.length; ms < msl; ms++) {
|
|
2318
|
+
singleMonth = monthSelector[ms];
|
|
2319
|
+
|
|
2320
|
+
//School holidays
|
|
2321
|
+
if(singleMonth == "SH") {
|
|
2322
|
+
months.push({holiday: "SH"});
|
|
2323
|
+
}
|
|
2324
|
+
//Month intervals
|
|
2325
|
+
else if(this.RGX_MONTH.test(singleMonth)) {
|
|
2326
|
+
singleMonth = singleMonth.split('-');
|
|
2327
|
+
monthFrom = OSM_MONTHS.indexOf(singleMonth[0])+1;
|
|
2328
|
+
if(monthFrom < 1) {
|
|
2329
|
+
throw new Error("Invalid month: "+singleMonth[0]);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
if(singleMonth.length > 1) {
|
|
2333
|
+
monthTo = OSM_MONTHS.indexOf(singleMonth[1])+1;
|
|
2334
|
+
if(monthTo < 1) {
|
|
2335
|
+
throw new Error("Invalid month: "+singleMonth[1]);
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
else {
|
|
2339
|
+
monthTo = null;
|
|
2340
|
+
}
|
|
2341
|
+
months.push({from: monthFrom, to: monthTo});
|
|
2342
|
+
}
|
|
2343
|
+
//Monthday intervals
|
|
2344
|
+
else if(this.RGX_MONTHDAY.test(singleMonth)) {
|
|
2345
|
+
singleMonth = singleMonth.replace(/\:/g, '').split('-');
|
|
2346
|
+
|
|
2347
|
+
//Read monthday start
|
|
2348
|
+
monthFrom = singleMonth[0].split(' ');
|
|
2349
|
+
monthFrom = { day: parseInt(monthFrom[1],10), month: OSM_MONTHS.indexOf(monthFrom[0])+1 };
|
|
2350
|
+
if(monthFrom.month < 1) {
|
|
2351
|
+
throw new Error("Invalid month: "+monthFrom[0]);
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
if(singleMonth.length > 1) {
|
|
2355
|
+
monthTo = singleMonth[1].split(' ');
|
|
2356
|
+
|
|
2357
|
+
//Same month as start
|
|
2358
|
+
if(monthTo.length == 1) {
|
|
2359
|
+
monthTo = { day: parseInt(monthTo[0],10), month: monthFrom.month };
|
|
2360
|
+
}
|
|
2361
|
+
//Another month
|
|
2362
|
+
else {
|
|
2363
|
+
monthTo = { day: parseInt(monthTo[1],10), month: OSM_MONTHS.indexOf(monthTo[0])+1 };
|
|
2364
|
+
if(monthTo.month < 1) {
|
|
2365
|
+
throw new Error("Invalid month: "+monthTo[0]);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
else {
|
|
2370
|
+
monthTo = null;
|
|
2371
|
+
}
|
|
2372
|
+
months.push({fromDay: monthFrom, toDay: monthTo});
|
|
2373
|
+
}
|
|
2374
|
+
//Unsupported
|
|
2375
|
+
else {
|
|
2376
|
+
throw new Error("Unsupported month selector: "+singleMonth);
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
else if(weekSelector != null) {
|
|
2381
|
+
//Divide each week interval
|
|
2382
|
+
weekSelector = weekSelector.split(',');
|
|
2383
|
+
|
|
2384
|
+
for(var ws=0, wsl = weekSelector.length; ws < wsl; ws++) {
|
|
2385
|
+
singleWeek = weekSelector[ws].split('-');
|
|
2386
|
+
weekFrom = parseInt(singleWeek[0],10);
|
|
2387
|
+
if(singleWeek.length > 1) {
|
|
2388
|
+
weekTo = parseInt(singleWeek[1],10);
|
|
2389
|
+
}
|
|
2390
|
+
else {
|
|
2391
|
+
weekTo = null;
|
|
2392
|
+
}
|
|
2393
|
+
weeks.push({from: weekFrom, to: weekTo});
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
else {
|
|
2397
|
+
throw Error("Invalid date selector");
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
//If no read token, throw error
|
|
2403
|
+
if(currentToken == tokens.length - 1) {
|
|
2404
|
+
throw Error("Unreadable string");
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
// console.log("months",months);
|
|
2408
|
+
// console.log("weeks",weeks);
|
|
2409
|
+
// console.log("holidays",holidays);
|
|
2410
|
+
// console.log("weekdays",weekdays);
|
|
2411
|
+
// console.log("times",times);
|
|
2412
|
+
// console.log("rule",ruleModifier);
|
|
2413
|
+
|
|
2414
|
+
/*
|
|
2415
|
+
* Create date ranges
|
|
2416
|
+
*/
|
|
2417
|
+
dateRanges = [];
|
|
2418
|
+
|
|
2419
|
+
//Month range
|
|
2420
|
+
if(months.length > 0) {
|
|
2421
|
+
for(var mId=0, ml = months.length; mId < ml; mId++) {
|
|
2422
|
+
singleMonth = months[mId];
|
|
2423
|
+
|
|
2424
|
+
if(singleMonth.holiday != undefined) {
|
|
2425
|
+
dateRanges.push(new WideInterval().holiday(singleMonth.holiday));
|
|
2426
|
+
}
|
|
2427
|
+
else if(singleMonth.fromDay != undefined) {
|
|
2428
|
+
if(singleMonth.toDay != null) {
|
|
2429
|
+
dateRange = new WideInterval().day(singleMonth.fromDay.day, singleMonth.fromDay.month, singleMonth.toDay.day, singleMonth.toDay.month);
|
|
2430
|
+
}
|
|
2431
|
+
else {
|
|
2432
|
+
dateRange = new WideInterval().day(singleMonth.fromDay.day, singleMonth.fromDay.month);
|
|
2433
|
+
}
|
|
2434
|
+
dateRanges.push(dateRange);
|
|
2435
|
+
}
|
|
2436
|
+
else {
|
|
2437
|
+
if(singleMonth.to != null) {
|
|
2438
|
+
dateRange = new WideInterval().month(singleMonth.from, singleMonth.to);
|
|
2439
|
+
}
|
|
2440
|
+
else {
|
|
2441
|
+
dateRange = new WideInterval().month(singleMonth.from);
|
|
2442
|
+
}
|
|
2443
|
+
dateRanges.push(dateRange);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
//Week range
|
|
2448
|
+
else if(weeks.length > 0) {
|
|
2449
|
+
for(var wId=0, wl = weeks.length; wId < wl; wId++) {
|
|
2450
|
+
if(weeks[wId].to != null) {
|
|
2451
|
+
dateRange = new WideInterval().week(weeks[wId].from, weeks[wId].to);
|
|
2452
|
+
}
|
|
2453
|
+
else {
|
|
2454
|
+
dateRange = new WideInterval().week(weeks[wId].from);
|
|
2455
|
+
}
|
|
2456
|
+
dateRanges.push(dateRange);
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
//Holiday range
|
|
2460
|
+
else if(holidays.length > 0) {
|
|
2461
|
+
for(var hId=0, hl = holidays.length; hId < hl; hId++) {
|
|
2462
|
+
dateRanges.push(new WideInterval().holiday(holidays[hId]));
|
|
2463
|
+
if(holidays[hId] == "PH" && weekdays.length > 0 && months.length == 0 && weeks.length == 0) {
|
|
2464
|
+
dateRanges.push(new WideInterval().always());
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
//Full year range
|
|
2469
|
+
else {
|
|
2470
|
+
dateRanges.push(new WideInterval().always());
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
//Case of no weekday defined = all week
|
|
2474
|
+
if(weekdays.length == 0) {
|
|
2475
|
+
if(holidays.length == 0 || (holidays.length == 1 && holidays[0] == "SH")) {
|
|
2476
|
+
weekdays.push({from: 0, to: OSM_DAYS.length -1 });
|
|
2477
|
+
}
|
|
2478
|
+
else {
|
|
2479
|
+
weekdays.push({from: 0, to: 0 });
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
//Case of no time defined = all day
|
|
2484
|
+
if(times.length == 0) {
|
|
2485
|
+
times.push({from: 0, to: 24*60});
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
/*
|
|
2489
|
+
* Create date range objects
|
|
2490
|
+
*/
|
|
2491
|
+
for(var drId = 0, drl=dateRanges.length; drId < drl; drId++) {
|
|
2492
|
+
/*
|
|
2493
|
+
* Find an already defined date range or create new one
|
|
2494
|
+
*/
|
|
2495
|
+
foundDateRange = false;
|
|
2496
|
+
resDrId=0;
|
|
2497
|
+
while(resDrId < result.length && !foundDateRange) {
|
|
2498
|
+
if(result[resDrId].getInterval().equals(dateRanges[drId])) {
|
|
2499
|
+
foundDateRange = true;
|
|
2500
|
+
}
|
|
2501
|
+
else {
|
|
2502
|
+
resDrId++;
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
if(foundDateRange) {
|
|
2507
|
+
drObj = result[resDrId];
|
|
2508
|
+
}
|
|
2509
|
+
else {
|
|
2510
|
+
drObj = new DateRange(dateRanges[drId]);
|
|
2511
|
+
|
|
2512
|
+
//Find general date range that may be refined by this one
|
|
2513
|
+
var general = -1;
|
|
2514
|
+
for(resDrId=0; resDrId < result.length; resDrId++) {
|
|
2515
|
+
if(result[resDrId].isGeneralFor(new DateRange(dateRanges[drId]))) {
|
|
2516
|
+
general = resDrId;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
//Copy general date range intervals
|
|
2521
|
+
if(general >= 0 && drObj.definesTypicalWeek()) {
|
|
2522
|
+
drObj.getTypical().copyIntervals(result[general].getTypical().getIntervals());
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
result.push(drObj);
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
/*
|
|
2529
|
+
* Add time intervals
|
|
2530
|
+
*/
|
|
2531
|
+
//For each weekday
|
|
2532
|
+
for(var wdId=0, wdl=weekdays.length; wdId < wdl; wdId++) {
|
|
2533
|
+
//Remove overlapping days
|
|
2534
|
+
if(weekdays[wdId].from <= weekdays[wdId].to) {
|
|
2535
|
+
for(var wdRm=weekdays[wdId].from; wdRm <= weekdays[wdId].to; wdRm++) {
|
|
2536
|
+
if(drObj.definesTypicalWeek()) {
|
|
2537
|
+
drObj.getTypical().removeIntervalsDuringDay(wdRm);
|
|
2538
|
+
}
|
|
2539
|
+
else {
|
|
2540
|
+
drObj.getTypical().clearIntervals();
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
else {
|
|
2545
|
+
for(var wdRm=weekdays[wdId].from; wdRm <= 6; wdRm++) {
|
|
2546
|
+
if(drObj.definesTypicalWeek()) {
|
|
2547
|
+
drObj.getTypical().removeIntervalsDuringDay(wdRm);
|
|
2548
|
+
}
|
|
2549
|
+
else {
|
|
2550
|
+
drObj.getTypical().clearIntervals();
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
for(var wdRm=0; wdRm <= weekdays[wdId].to; wdRm++) {
|
|
2554
|
+
if(drObj.definesTypicalWeek()) {
|
|
2555
|
+
drObj.getTypical().removeIntervalsDuringDay(wdRm);
|
|
2556
|
+
}
|
|
2557
|
+
else {
|
|
2558
|
+
drObj.getTypical().clearIntervals();
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
//For each time interval
|
|
2564
|
+
for(var tId=0, tl=times.length; tId < tl; tId++) {
|
|
2565
|
+
if(ruleModifier == "closed" || ruleModifier == "off") {
|
|
2566
|
+
this._removeInterval(drObj.getTypical(), weekdays[wdId], times[tId]);
|
|
2567
|
+
}
|
|
2568
|
+
else {
|
|
2569
|
+
this._addInterval(drObj.getTypical(), weekdays[wdId], times[tId]);
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
|
|
2576
|
+
return result;
|
|
2577
|
+
};
|
|
2578
|
+
|
|
2579
|
+
/**
|
|
2580
|
+
* Remove intervals from given typical day/week
|
|
2581
|
+
* @param typical The typical day or week
|
|
2582
|
+
* @param weekdays The concerned weekdays
|
|
2583
|
+
* @param times The concerned times
|
|
2584
|
+
*/
|
|
2585
|
+
OpeningHoursParser.prototype._removeInterval = function(typical, weekdays, times) {
|
|
2586
|
+
if(weekdays.from <= weekdays.to) {
|
|
2587
|
+
for(var wd=weekdays.from; wd <= weekdays.to; wd++) {
|
|
2588
|
+
this._removeIntervalWd(typical, times, wd);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
else {
|
|
2592
|
+
for(var wd=weekdays.from; wd <= 6; wd++) {
|
|
2593
|
+
this._removeIntervalWd(typical, times, wd);
|
|
2594
|
+
}
|
|
2595
|
+
for(var wd=0; wd <= weekdays.to; wd++) {
|
|
2596
|
+
this._removeIntervalWd(typical, times, wd);
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
};
|
|
2600
|
+
|
|
2601
|
+
/**
|
|
2602
|
+
* Remove intervals from given typical day/week for a given weekday
|
|
2603
|
+
* @param typical The typical day or week
|
|
2604
|
+
* @param times The concerned times
|
|
2605
|
+
* @param wd The concerned weekday
|
|
2606
|
+
*/
|
|
2607
|
+
OpeningHoursParser.prototype._removeIntervalWd = function(typical, times, wd) {
|
|
2608
|
+
//Interval during day
|
|
2609
|
+
if(times.to >= times.from) {
|
|
2610
|
+
typical.removeInterval(
|
|
2611
|
+
new Interval(wd, wd, times.from, times.to)
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
//Interval during night
|
|
2615
|
+
else {
|
|
2616
|
+
//Everyday except sunday
|
|
2617
|
+
if(wd < 6) {
|
|
2618
|
+
typical.removeInterval(
|
|
2619
|
+
new Interval(wd, wd+1, times.from, times.to)
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
//Sunday
|
|
2623
|
+
else {
|
|
2624
|
+
typical.removeInterval(
|
|
2625
|
+
new Interval(wd, wd, times.from, 24*60)
|
|
2626
|
+
);
|
|
2627
|
+
typical.removeInterval(
|
|
2628
|
+
new Interval(0, 0, 0, times.to)
|
|
2629
|
+
);
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
};
|
|
2633
|
+
|
|
2634
|
+
/**
|
|
2635
|
+
* Adds intervals from given typical day/week
|
|
2636
|
+
* @param typical The typical day or week
|
|
2637
|
+
* @param weekdays The concerned weekdays
|
|
2638
|
+
* @param times The concerned times
|
|
2639
|
+
*/
|
|
2640
|
+
OpeningHoursParser.prototype._addInterval = function(typical, weekdays, times) {
|
|
2641
|
+
//Check added interval are OK for days
|
|
2642
|
+
if(typical instanceof Day) {
|
|
2643
|
+
if(weekdays.from != 0 || (weekdays.to != 0 && times.from <= times.to)) {
|
|
2644
|
+
weekdays = Object.assign({}, weekdays);
|
|
2645
|
+
weekdays.from = 0;
|
|
2646
|
+
weekdays.to = (times.from <= times.to) ? 0 : 1;
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
if(weekdays.from <= weekdays.to) {
|
|
2651
|
+
for(var wd=weekdays.from; wd <= weekdays.to; wd++) {
|
|
2652
|
+
this._addIntervalWd(typical, times, wd);
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
else {
|
|
2656
|
+
for(var wd=weekdays.from; wd <= 6; wd++) {
|
|
2657
|
+
this._addIntervalWd(typical, times, wd);
|
|
2658
|
+
}
|
|
2659
|
+
for(var wd=0; wd <= weekdays.to; wd++) {
|
|
2660
|
+
this._addIntervalWd(typical, times, wd);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
};
|
|
2664
|
+
|
|
2665
|
+
/**
|
|
2666
|
+
* Adds intervals from given typical day/week for a given weekday
|
|
2667
|
+
* @param typical The typical day or week
|
|
2668
|
+
* @param times The concerned times
|
|
2669
|
+
* @param wd The concerned weekday
|
|
2670
|
+
*/
|
|
2671
|
+
OpeningHoursParser.prototype._addIntervalWd = function(typical, times, wd) {
|
|
2672
|
+
//Interval during day
|
|
2673
|
+
if(times.to >= times.from) {
|
|
2674
|
+
typical.addInterval(
|
|
2675
|
+
new Interval(wd, wd, times.from, times.to)
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
//Interval during night
|
|
2679
|
+
else {
|
|
2680
|
+
//Everyday except sunday
|
|
2681
|
+
if(wd < 6) {
|
|
2682
|
+
typical.addInterval(
|
|
2683
|
+
new Interval(wd, wd+1, times.from, times.to)
|
|
2684
|
+
);
|
|
2685
|
+
}
|
|
2686
|
+
//Sunday
|
|
2687
|
+
else {
|
|
2688
|
+
typical.addInterval(
|
|
2689
|
+
new Interval(wd, wd, times.from, 24*60)
|
|
2690
|
+
);
|
|
2691
|
+
typical.addInterval(
|
|
2692
|
+
new Interval(0, 0, 0, times.to)
|
|
2693
|
+
);
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
};
|
|
2697
|
+
|
|
2698
|
+
/**
|
|
2699
|
+
* Converts a time string "12:45" into minutes integer
|
|
2700
|
+
* @param time The time string
|
|
2701
|
+
* @return The amount of minutes since midnight
|
|
2702
|
+
*/
|
|
2703
|
+
OpeningHoursParser.prototype._asMinutes = function(time) {
|
|
2704
|
+
var values = time.split(':');
|
|
2705
|
+
return parseInt(values[0],10) * 60 + parseInt(values[1],10);
|
|
2706
|
+
};
|
|
2707
|
+
|
|
2708
|
+
/**
|
|
2709
|
+
* Is the given token a weekday selector ?
|
|
2710
|
+
*/
|
|
2711
|
+
OpeningHoursParser.prototype._isWeekday = function(token) {
|
|
2712
|
+
return this.RGX_WEEKDAY.test(token);
|
|
2713
|
+
};
|
|
2714
|
+
|
|
2715
|
+
/**
|
|
2716
|
+
* Is the given token a time selector ?
|
|
2717
|
+
*/
|
|
2718
|
+
OpeningHoursParser.prototype._isTime = function(token) {
|
|
2719
|
+
return this.RGX_TIME.test(token);
|
|
2720
|
+
};
|
|
2721
|
+
|
|
2722
|
+
/**
|
|
2723
|
+
* Is the given token a rule modifier ?
|
|
2724
|
+
*/
|
|
2725
|
+
OpeningHoursParser.prototype._isRuleModifier = function(token) {
|
|
2726
|
+
return this.RGX_RULE_MODIFIER.test(token);
|
|
2727
|
+
};
|
|
2728
|
+
|
|
2729
|
+
/**
|
|
2730
|
+
* Create tokens for a given block
|
|
2731
|
+
*/
|
|
2732
|
+
OpeningHoursParser.prototype._tokenize = function(block) {
|
|
2733
|
+
var result = block.trim().split(' ');
|
|
2734
|
+
var position = result.indexOf("");
|
|
2735
|
+
while( ~position ) {
|
|
2736
|
+
result.splice(position, 1);
|
|
2737
|
+
position = result.indexOf("");
|
|
2738
|
+
}
|
|
2739
|
+
return result;
|
|
2740
|
+
};
|
|
2741
|
+
|
|
2742
|
+
OpeningHoursParser.prototype._printIntervals = function(from, intervals) {
|
|
2743
|
+
console.log("From: "+from);
|
|
2744
|
+
if(intervals.length > 0) {
|
|
2745
|
+
console.log("-------------------------");
|
|
2746
|
+
for(var i=0; i < intervals.length; i++) {
|
|
2747
|
+
if(intervals[i] == undefined) {
|
|
2748
|
+
console.log(i+": "+undefined);
|
|
2749
|
+
}
|
|
2750
|
+
else {
|
|
2751
|
+
console.log(i+": "+intervals[i].getStartDay()+", "+intervals[i].getEndDay()+", "+intervals[i].getFrom()+", "+intervals[i].getTo());
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
console.log("-------------------------");
|
|
2755
|
+
}
|
|
2756
|
+
else {
|
|
2757
|
+
console.log("Empty intervals");
|
|
2758
|
+
}
|
|
2759
|
+
};
|
|
2760
|
+
|
|
2761
|
+
|
|
2762
|
+
/**
|
|
2763
|
+
* Check compatibility of opening_hours string with YoHours
|
|
2764
|
+
*/
|
|
2765
|
+
var YoHoursChecker = function() {
|
|
2766
|
+
//ATTRIBUTES
|
|
2767
|
+
/** The OpeningHoursParser **/
|
|
2768
|
+
this._parser = new OpeningHoursParser();
|
|
2769
|
+
};
|
|
2770
|
+
|
|
2771
|
+
//OTHER METHODS
|
|
2772
|
+
/**
|
|
2773
|
+
* Check if the opening_hours is readable by YoHours
|
|
2774
|
+
* @param oh The opening_hours string
|
|
2775
|
+
* @return True if YoHours can read it and display it
|
|
2776
|
+
*/
|
|
2777
|
+
YoHoursChecker.prototype.canRead = function(oh) {
|
|
2778
|
+
var result = false;
|
|
2779
|
+
|
|
2780
|
+
try {
|
|
2781
|
+
var parsed = this._parser.parse(oh);
|
|
2782
|
+
if(parsed != null) {
|
|
2783
|
+
result = true;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
catch(e) {;}
|
|
2787
|
+
|
|
2788
|
+
return result;
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
export { OpeningHoursBuilder, OpeningHoursParser, YoHoursChecker };
|