Ignore:
Timestamp:
2014-05-02T01:40:37+02:00 (10 years ago)
Author:
Don-vip
Message:

see #9923 - update opening_hours.js + translate/shorten a bit error messages

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/data/validator/opening_hours.js

    r6489 r7046  
    11(function (root, factory) {
    2         //======================================================================
    3         // Constants
    4         //======================================================================
     2        // constants (holidays, error correction) {{{
     3        // holidays {{{
    54        var holidays = {
    65                'fr': {
     
    11041103                        },
    11051104                },
     1105                'ca': {
     1106                        'PH': { // https://en.wikipedia.org/wiki/Public_holidays_in_Canada
     1107                                "New Year's Day"            : [  1,  1 ],
     1108                                "Good Friday"               : [  'easter', -2 ],
     1109                                "Canada Day"                : [  'canadaDay', 0 ],
     1110                                "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1111                                "Christmas Day"             : [ 12, 25 ]
     1112                        },
     1113                        'Alberta': {
     1114                                'PH': {
     1115                                        "New Year's Day"            : [  1,  1 ],
     1116                                        "Alberta Family Day"        : [  'firstFebruaryMonday', 14 ],
     1117                                        "Good Friday"               : [  'easter', -2 ],
     1118                                        "Easter Monday"             : [  'easter', 1 ],
     1119                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1120                                        "Canada Day"                : [  'canadaDay', 0 ],
     1121                                        "Heritage Day"              : [  'firstAugustMonday', 0 ],
     1122                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1123                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1124                                        "Remembrance Day"           : [ 11, 11 ],
     1125                                        "Christmas Day"             : [ 12, 25 ],
     1126                                        "Boxing Day"                : [ 12, 26 ]
     1127                                },
     1128                        },
     1129                        'British Columbia': {
     1130                                'PH': {
     1131                                        "New Year's Day"            : [  1,  1 ],
     1132                                        "Family Day"                : [  'firstFebruaryMonday', 7 ],
     1133                                        "Good Friday"               : [  'easter', -2 ],
     1134                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1135                                        "Canada Day"                : [  'canadaDay', 0 ],
     1136                                        "British Columbia Day"      : [  'firstAugustMonday', 0 ],
     1137                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1138                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1139                                        "Remembrance Day"           : [ 11, 11 ],
     1140                                        "Christmas Day"             : [ 12, 25 ]
     1141                                },
     1142                        },
     1143                        'Manitoba': {
     1144                                'PH': {
     1145                                        "New Year's Day"            : [  1,  1 ],
     1146                                        "Louis Riel Day"            : [  'firstFebruaryMonday', 14 ],
     1147                                        "Good Friday"               : [  'easter', -2 ],
     1148                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1149                                        "Canada Day"                : [  'canadaDay', 0 ],
     1150                                        "Civic Holiday"             : [  'firstAugustMonday', 0 ],
     1151                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1152                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1153                                        "Remembrance Day"           : [ 11, 11 ],
     1154                                        "Christmas Day"             : [ 12, 25 ]
     1155                                },
     1156                        },
     1157                        'New Brunswick': {
     1158                                'PH': {
     1159                                        "New Year's Day"            : [  1,  1 ],
     1160                                        "Good Friday"               : [  'easter', -2 ],
     1161                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1162                                        "Canada Day"                : [  'canadaDay', 0 ],
     1163                                        "New Brunswick Day"         : [  'firstAugustMonday', 0 ],
     1164                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1165                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1166                                        "Remembrance Day"           : [ 11, 11 ],
     1167                                        "Christmas Day"             : [ 12, 25 ],
     1168                                        "Boxing Day"                : [ 12, 26 ]
     1169                                },
     1170                        },
     1171                        'Newfoundland and Labrador': {
     1172                                'PH': {
     1173                                        "New Year's Day"            : [  1,  1 ],
     1174                                        "Saint Patrick's Day"       : [  3, 17 ],
     1175                                        "Good Friday"               : [  'easter', -2 ],
     1176                                        "Saint George's Day"        : [  4, 23 ],
     1177                                        "Discovery Day"             : [  6, 24 ],
     1178                                        "Memorial Day"              : [  7, 1 ],
     1179                                        "Orangemen's Day"           : [  7, 12 ],
     1180                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1181                                        "Armistice Day"             : [ 11, 11 ],
     1182                                        "Christmas Day"             : [ 12, 25 ]
     1183                                },
     1184                        },
     1185                        'Northwest Territories': {
     1186                                'PH': {
     1187                                        "New Year's Day"            : [  1,  1 ],
     1188                                        "Good Friday"               : [  'easter', -2 ],
     1189                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1190                                        "National Aboriginal Day"   : [  6, 21 ],
     1191                                        "Canada Day"                : [  'canadaDay', 0 ],
     1192                                        "Civic Holiday"             : [  'firstAugustMonday', 0 ],
     1193                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1194                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1195                                        "Remembrance Day"           : [ 11, 11 ],
     1196                                        "Christmas Day"             : [ 12, 25 ]
     1197                                },
     1198                        },
     1199                        'Nova Scotia': {
     1200                                'PH': {
     1201                                        "New Year's Day"            : [  1,  1 ],
     1202                                        "Good Friday"               : [  'easter', -2 ],
     1203                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1204                                        "Canada Day"                : [  'canadaDay', 0 ],
     1205                                        "Natal Day"                 : [  'firstAugustMonday', 0 ],
     1206                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1207                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1208                                        "Remembrance Day"           : [ 11, 11 ],
     1209                                        "Christmas Day"             : [ 12, 25 ],
     1210                                        "Boxing Day"                : [ 12, 26 ]
     1211                                },
     1212                        },
     1213                        'Nunavut': {
     1214                                'PH': {
     1215                                        "New Year's Day"            : [  1,  1 ],
     1216                                        "Good Friday"               : [  'easter', -2 ],
     1217                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1218                                        "Canada Day"                : [  'canadaDay', 0 ],
     1219                                        "Nunavut Day"               : [  7, 9 ],
     1220                                        "Civic Holiday"             : [  'firstAugustMonday', 0 ],
     1221                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1222                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1223                                        "Remembrance Day"           : [ 11, 11 ],
     1224                                        "Christmas Day"             : [ 12, 25 ]
     1225                                },
     1226                        },
     1227                        'Ontario': {
     1228                                'PH': {
     1229                                        "New Year's Day"              : [  1,  1 ],
     1230                                        "Family Day"                  : [  'firstFebruaryMonday', 14 ],
     1231                                        "Good Friday"                 : [  'easter', -2 ],
     1232                                        "Victoria Day"                : [  'victoriaDay', 0 ],
     1233                                        "Canada Day"                  : [  'canadaDay', 0 ],
     1234                                        "August Civic Public Holiday" : [  'firstAugustMonday', 0 ],
     1235                                        "Labour Day"                  : [  'firstSeptemberMonday', 0 ],
     1236                                        "Thanksgiving"                : [  'firstOctoberMonday', 7 ],
     1237                                        "Remembrance Day"             : [ 11, 11 ],
     1238                                        "Christmas Day"               : [ 12, 25 ],
     1239                                        "Boxing Day"                  : [ 12, 26 ]
     1240                                },
     1241                        },
     1242                        'Prince Edward Island': {
     1243                                'PH': {
     1244                                        "New Year's Day"            : [  1,  1 ],
     1245                                        "Islander Day"              : [  'firstFebruaryMonday', 14 ],
     1246                                        "Good Friday"               : [  'easter', -2 ],
     1247                                        "Easter Monday"             : [  'easter', 1 ],
     1248                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1249                                        "Canada Day"                : [  'canadaDay', 0 ],
     1250                                        "Civic Holiday"             : [  'firstAugustMonday', 0 ],
     1251                                        "Gold Cup Parade Day"       : [  'firstAugustMonday', 18 ],
     1252                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1253                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1254                                        "Remembrance Day"           : [ 11, 11 ],
     1255                                        "Christmas Day"             : [ 12, 25 ],
     1256                                        "Boxing Day"                : [ 12, 26 ]
     1257                                },
     1258                        },
     1259                        'Quebec': {
     1260                                'PH': {
     1261                                        "Jour de l'an"                    : [  1,  1 ],
     1262                                        "Vendredi saint"                  : [  'easter', -2 ],
     1263                                        "Lundi de Pâques"                 : [  'easter', 1 ],
     1264                                        "Journée nationale des patriotes" : [  'victoriaDay', 0 ],
     1265                                        "Fête nationale du Québec"        : [  6, 24 ],
     1266                                        "Fête du Canada"                  : [  'canadaDay', 0 ],
     1267                                        "Fête du Travail"                 : [  'firstSeptemberMonday', 0 ],
     1268                                        "Jour de l'Action de grâce"       : [  'firstOctoberMonday', 7 ],
     1269                                        "Noël"                            : [ 12, 25 ]
     1270                                },
     1271                        },
     1272                        'Saskatchewan': {
     1273                                'PH': {
     1274                                        "New Year's Day"            : [  1,  1 ],
     1275                                        "Family Day"                : [  'firstFebruaryMonday', 14 ],
     1276                                        "Good Friday"               : [  'easter', -2 ],
     1277                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1278                                        "Canada Day"                : [  'canadaDay', 0 ],
     1279                                        "Saskatchewan Day"          : [  'firstAugustMonday', 0 ],
     1280                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1281                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1282                                        "Remembrance Day"           : [ 11, 11 ],
     1283                                        "Christmas Day"             : [ 12, 25 ]
     1284                                },
     1285                        },
     1286                        'Yukon': {
     1287                                'PH': {
     1288                                        "New Year's Day"            : [  1,  1 ],
     1289                                        "Heritage Day"              : [  'lastFebruarySunday',  -2 ],
     1290                                        "Good Friday"               : [  'easter', -2 ],
     1291                                        "Easter Monday"             : [  'easter', 1 ],
     1292                                        "Victoria Day"              : [  'victoriaDay', 0 ],
     1293                                        "Canada Day"                : [  'canadaDay', 0 ],
     1294                                        "Discovery Day"             : [  'firstAugustMonday', 14 ],
     1295                                        "Labour Day"                : [  'firstSeptemberMonday', 0 ],
     1296                                        "Thanksgiving"              : [  'firstOctoberMonday', 7 ],
     1297                                        "Remembrance Day"           : [ 11, 11 ],
     1298                                        "Christmas Day"             : [ 12, 25 ],
     1299                                        "Boxing Day"                : [ 12, 26 ]
     1300                                },
     1301                        },
     1302                },
     1303                'ua': {
     1304                        'PH': { // http://uk.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D1%82%D0%B0_%D1%82%D0%B0_%D0%BF%D0%B0%D0%BC%27%D1%8F%D1%82%D0%BD%D1%96_%D0%B4%D0%BD%D1%96_%D0%B2_%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D1%96
     1305                                "Новий рік"                  : [  1,  1 ],
     1306                                "Різдво"                     : [  1,  7 ],
     1307                                "Міжнародний жіночий день"   : [  3,  8 ],
     1308                                "Великдень"                  : [ 'orthodox easter',  1 ],
     1309                                "День Праці 1"               : [  5,  1 ],
     1310                                "День Праці 2"               : [  5,  2 ],
     1311                                "День Перемоги"              : [  5,  9 ],
     1312                                "День Конституції України"   : [  6, 28 ],
     1313                                "День Незалежності України"  : [  8, 24 ],
     1314                        }
     1315                },
     1316                'si': {
     1317                        'PH': { // http://www.vlada.si/o_sloveniji/politicni_sistem/prazniki/
     1318                                'novo leto'                                  : [  1,  1 ],
     1319                                'Prešernov dan, slovenski kulturni praznik'  : [  2,  8 ],
     1320                                'velikonočna nedelja'                        : [ 'easter',  0 ],
     1321                                'velikonočni ponedeljek'                     : [ 'easter',  1 ],
     1322                                'dan upora proti okupatorju'                 : [  4,  27 ],
     1323                                'praznik dela 1'                               : [  5, 1 ],
     1324                                'praznik dela 2'                               : [  5, 2 ],
     1325                                'binkoštna nedelja - binkošti'               : [ 'easter',  49 ],
     1326                                'dan državnosti'                             : [  6, 25 ],
     1327                                'Marijino vnebovzetje'                       : [  8, 15 ],
     1328                                'dan reformacije'                            : [ 10, 31 ],
     1329                                'dan spomina na mrtve'                       : [ 11,  1 ],
     1330                                'božič'                                      : [ 12, 25 ],
     1331                                'dan samostojnosti in enotnosti'             : [ 12, 26 ],
     1332                        },
     1333                },
    11061334        };
    1107 
    1108         //----------------------------------------------------------------------------
    1109         //  error correction
    1110         //  Taken form http://www.netzwolf.info/j/osm/time_domain.js
    1111         //  Credits go to Netzwolf
     1335        // }}}
     1336
     1337        // error correction {{{
     1338        // Taken form http://www.netzwolf.info/j/osm/time_domain.js
     1339        // Credits go to Netzwolf
    11121340        //
    1113         //  Key to word_error_correction is the token name except wrong_words
    1114         //----------------------------------------------------------------------------
     1341        // Key to word_error_correction is the token name except wrong_words
    11151342        var word_error_correction = {
    11161343                wrong_words: {
    11171344                        'Assuming "<ok>" for "<ko>"': {
    1118                                 spring: 'Mar-May',
    1119                                 summer: 'Jun-Aug',
    1120                                 autumn: 'Sep-Nov',
    1121                                 winter: 'Dec-Feb',
     1345                                spring:  'Mar-May',
     1346                                summer:  'Jun-Aug',
     1347                                autumn:  'Sep-Nov',
     1348                                winter:  'Dec-Feb',
     1349                                // morning: '08:00-12:00',
     1350                                // evening: '13:00-18:00',
     1351                                '_':  '-',
     1352                                'daytime': 'sunrise-sunset',
    11221353                        }, 'Bitte benutze die englische Schreibweise "<ok>" für "<ko>".': {
    11231354                                sommer: 'summer',
     1355                                'werktag':  'Mo-Fr',
     1356                                'werktags': 'Mo-Fr',
    11241357                        }, 'Bitte benutze "<ok>" für "<ko>". Beispiel: "Mo-Fr 08:00-12:00; Tu off"': {
    11251358                                ruhetag:     'off',
    11261359                                ruhetage:    'off',
    11271360                                geschlossen: 'off',
     1361                                ausser:      'off',
     1362                                außer:       'off',
     1363                        }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
     1364                                'gesloten':  'off',
     1365                                'feestdag':  'PH',
    11281366                        }, 'Assuming "<ok>" for "<ko>". Please avoid using "workday": http://wiki.openstreetmap.org/wiki/Talk:Key:opening_hours#need_syntax_for_holidays_and_workingdays': {
    11291367                                //      // Used around 260 times but the problem is, that work day might be different in other countries.
    1130                                 wd:       'Mo-Fr',
    1131                                 weekday:  'Mo-Fr',
    1132                                 weekdays: 'Mo-Fr',
     1368                                'wd':       'Mo-Fr',
     1369                                'weekday':  'Mo-Fr',
     1370                                'weekdays': 'Mo-Fr',
     1371                                'vardagar': 'Mo-Fr',
     1372                        }, 'Please use notation something like "Mo off" instead "<ko>".': {
     1373                                except: 'off',
    11331374                        }, 'Please ommit "<ko>" or use a colon instead: "12:00-14:00".': {
    11341375                                h: '',
     
    11381379                                hrs:    '',
    11391380                                hours:  '',
    1140                         }, 'Please ommit "<ko>". You might want to express open end which can be specified as "12:00+" for example': {
     1381                        }, 'Please ommit "<ko>". The key must not be in the value.': {
     1382                                'opening_hours=': '',
     1383                        }, 'Please ommit "<ko>". You might want to express open end which can be specified as "12:00+" for example.': {
    11411384                                from: '',
     1385                        }, 'You can use notation "<ok>" for "<ko>". You might want to express open end which can be specified as "12:00+" for example.': {
     1386                                '-late': '+',
    11421387                        }, 'Please use notation "<ok>" for "<ko>". If the times are unsure or vary consider a comment e.g. 12:00-14:00 "only on sunshine".': {
    11431388                                '~':  '-',
    11441389                                '~': '-',
     1390                        }, 'Please use notation "<ok>" for "<ko>". Fallback rule: 12:00-14:00 || "call us"': {
     1391                                'otherwise':  '||',
     1392                        }, 'You can use notation "<ok>" for "<ko>" temporally if the syntax will still be valid.': {
     1393                                '?':  'unknown "please add this if known"',
    11451394                        }, 'Please use notation "<ok>" for "<ko>".': {
     1395                                '→':  '-',
    11461396                                '–':  '-',
    1147                                 'ー':  '-',
     1397                                '−':  '-',
     1398                                '=':  '-',
     1399                                'ー': '-',
    11481400                                to:   '-',
    1149                                 till: '-',
     1401                                'до': '-',
     1402                                a:    '-', // language unknown
     1403                                as:   '-', // language unknown
     1404                                'á':  '-', // language unknown
     1405                                'ás': '-', // language unknown
     1406                                'à':  '-', // language unknown
     1407                                'às': '-', // language unknown
     1408                                'ate':  '-', // language unknown
     1409                                'till': '-',
     1410                                'til':  '-',
     1411                                'until': '-',
     1412                                'through': '-',
    11501413                                and:  ',',
    11511414                                '&':  ',',
    11521415                                ':':  ':',
    1153                                 daily:     'Mo-Su',
    1154                                 everyday:  'Mo-Su',
     1416                                '°°':  ':00',
     1417                                'daily':     'Mo-Su',
     1418                                'everyday':  'Mo-Su',
     1419                                'every day': 'Mo-Su',
    11551420                                always:    '24/7',
    11561421                                nonstop:   '24/7',
    1157                                 midnight: '00:00',
     1422                                '24x7':    '24/7',
     1423                                'anytime': '24/7',
     1424                                'all day': '24/7',
     1425                                'all days': 'Mo-Su',
     1426                                'every day': 'Mo-Su',
     1427                                '7days':   'Mo-Su',
     1428                                '7j/7':    'Mo-Su', // I guess that it means that
     1429                                '7/7':     'Mo-Su', // I guess that it means that
     1430                                '7 days':  'Mo-Su',
     1431                                '7 days a week': 'Mo-Su',
     1432                                'midnight': '00:00',
    11581433                                holiday:  'PH',
    11591434                                holidays: 'PH',
     1435                                'public holidays': 'PH',
     1436                                'public holiday': 'PH',
    11601437                                // summerholiday:  'SH',
    11611438                                // summerholidays: 'SH',
    1162                         }, 'Please use time format in 24 hours notation ("<ko>").': {
    1163                                 pm: '',
    1164                                 am: '',
     1439                                weekend:  'Sa,Su',
     1440                                weekends: 'Sa,Su',
     1441                                'daylight': 'sunrise-sunset',
     1442                                'оff': 'off', // Russian o
     1443                        }, 'Please use time format in 24 hours notation ("<ko>"). If PM is used you might have to convert the hours to the 24 hours notation.': {
     1444                                'pm': '',
     1445                                'рм': '',
     1446                                'am': '',
     1447                                'ам': '',
    11651448                        }, 'Bitte verzichte auf "<ko>".': {
    1166                                 uhr: '',
     1449                                'uhr': '',
     1450                                'geöffnet': '',
    11671451                        }, 'Bitte verzichte auf "<ko>". Sie möchten eventuell eine Öffnungszeit ohne vorgegebenes Ende angeben. Beispiel: "12:00+"': {
    11681452                                ab:  '',
     
    11831467                                'et':    ',',
    11841468                                'à':     '-',
     1469                                'jours fériés': 'PH',
    11851470                        }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
    11861471                                feestdag:   'PH',
     
    12041489                                dec: 11,
    12051490                        }, 'Please use the English abbreviation "<ok>" for "<ko>".': {
     1491                                'jänner':   0, // Austria
    12061492                                january:    0,
    12071493                                february:   1,
     
    12811567                                wednesdays: 3,
    12821568                                thu:        4,
     1569                                thur:       4,
    12831570                                thursday:   4,
    12841571                                thursdays:  4,
     
    12941581                                son:         0,
    12951582                                sonntag:     0,
     1583                                'sonn-':     0,
    12961584                                sonntags:    0,
    12971585                                montag:      1,
     
    13341622                                zo:        0,
    13351623                                zon:       0,
    1336                                 zontag:    0,
     1624                                zontag:    0, // correct?
     1625                                zondag:    0,
    13371626                                maandag:   1,
    13381627                                din:       2,
     
    13801669                                'senin':  6,
    13811670                                // Swedish
    1382                                 'söndag':  0,
    1383                                 'måndag':  1,
    1384                                 ma:        1,
    1385                                 'tisdag':  2,
    1386                                 'onsdag':  3,
    1387                                 'torsdag': 4,
    1388                                 'fredag':  5,
    1389                                 'lördag':  6,
     1671                                'söndag':   0,
     1672                                'söndagar': 0,
     1673                                'måndag':   1,
     1674                                'ma':       1,
     1675                                'tisdag':   2,
     1676                                'onsdag':   3,
     1677                                'torsdag':  4,
     1678                                'fredag':   5,
     1679                                'lördag':   6,
     1680                                'lördagar': 6,
    13901681                                // Polish
    13911682                                'niedziela': 0, 'niedz': 0, 'n': 0, 'ndz': 0,
     
    13961687                                'piątek': 5, 'piatek': 5, 'pt': 5,
    13971688                                'sobota': 6, 'sob': 6, // 'so': 6 // abbreviation also used in German
     1689                                // Russian
     1690                                'воскресенье' : 0,
     1691                                'Вс'          : 0,
     1692                                "voskresen'ye": 0,
     1693                                'понедельник' : 1,
     1694                                'Пн'          : 1,
     1695                                "ponedel'nik" : 1,
     1696                                'вторник'     : 2,
     1697                                'vtornik'     : 2,
     1698                                'среда'       : 3,
     1699                                'sreda'       : 3,
     1700                                'четверг'     : 4,
     1701                                'chetverk'    : 4,
     1702                                'пятница'     : 5,
     1703                                'pyatnitsa'   : 5,
     1704                                'суббота'     : 6,
     1705                                'subbota'     : 6,
     1706                                // Danish
     1707                                'søndag' : 0,
     1708                                'mandag' : 1,
     1709                                'tirsdag': 2,
     1710                                'onsdag' : 3,
     1711                                'torsdag': 4,
     1712                                'fredag' : 5,
     1713                                'lørdag' : 6,
    13981714                        },
    13991715                },
     
    14011717                timevar: { // Special time variables which actual value depends on the date and the position of the facility.
    14021718                        'default': {
    1403                                 sunrise: 'sunrise',
    1404                                 sunset:  'sunset',
    1405                                 dawn:    'dawn',
    1406                                 dusk:    'dusk',
     1719                                'sunrise': 'sunrise',
     1720                                'sunset':  'sunset',
     1721                                'dawn':    'dawn',
     1722                                'dusk':    'dusk',
    14071723                        }, 'Please use notation "<ok>" for "<ko>".': {
    1408                                 sundown: 'sunset',
     1724                                'sundown': 'sunset',
    14091725                        }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
    14101726                                'morgendämmerung': 'dawn',
    14111727                                'abenddämmerung':  'dusk',
    1412                                 sonnenaufgang: 'sunrise',
    1413                                 sonnenuntergang: ',',
     1728                                'sonnenaufgang':  'sunrise',
     1729                                'sonnenuntergang': 'sunset',
    14141730                        },
    14151731                },
     
    14171733                'event': { // variable events
    14181734                        'default': {
    1419                                 easter: 'easter',
     1735                                'easter': 'easter',
    14201736                        }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
    1421                                 ostern: 'easter',
     1737                                'ostern': 'easter',
    14221738                        },
    14231739                },
    14241740        };
    1425 
     1741        // }}}
     1742        // }}}
     1743
     1744        // make the library accessible for the outside world {{{
    14261745        if (typeof exports === 'object') {
    14271746                // For nodejs
     
    14321751                root.opening_hours = factory(root.SunCalc, holidays, word_error_correction);
    14331752        }
     1753        /// }}}
    14341754}(this, function (SunCalc, holidays, word_error_correction) {
    14351755        return function(value, nominatiomJSON, oh_mode) {
     1756                // short constants {{{
    14361757                var word_value_replacement = { // if the correct values can not be calculated
    14371758                        dawn    : 60 * 5 + 30,
     
    14561777                var msec_in_day    = 1000 * 60 * minutes_in_day;
    14571778                var msec_in_week   = msec_in_day * 7;
    1458 
     1779                // }}}
     1780
     1781                // The big picture -- How does this library work? {{{
    14591782                //======================================================================
    14601783                // Constructor - entry to parsing code
     
    14761799                // - Tokenize
    14771800                // Foreach block:
    1478                 //   - Run toplevel (block) parser
    1479                 //     - Which calls subparser for specific selector types
     1801                //   - Run top-level (block) parser
     1802                //     - Which calls sub parser for specific selector types
    14801803                //       - Which produce selector functions
    1481 
    1482 
     1804                // }}}
     1805
     1806                // constructor parameters {{{
    14831807                // Evaluate additional information which can be given. They are
    1484                 // required to reasonably calculate 'sunrise' and so on and to use the
    1485                 // correct holidays.
     1808                // required to reasonably calculate 'sunrise' and to use the correct
     1809                // holidays.
    14861810                var location_cc, location_state, lat, lon;
    14871811                if (typeof nominatiomJSON != 'undefined') {
     
    14981822                }
    14991823
    1500                 // 0: time ranges (opening_hours, lit, …) default
    1501                 // 1: points in time (collection_times, service_times, …)
    1502                 // 2: both (time ranges and points in time)
     1824                // 0: time ranges (default), tags: opening_hours, lit, …
     1825                // 1: points in time
     1826                // 2: both (time ranges and points in time), tags: collection_times, service_times
    15031827                if (typeof oh_mode == 'undefined') {
    15041828                        oh_mode = 0;
     
    15061830                        throw 'The third constructor parameter is oh_mode and must be a number (0, 1 or 2)'
    15071831                }
    1508 
     1832                // }}}
     1833
     1834                // put tokenized blocks into list {{{
    15091835                if (value.match(/^(\s*;?\s*)+$/))
    15101836                        throw 'Value contains nothing meaningful which can be parsed';
     
    15161842                // console.log(JSON.stringify(tokens, null, '\t'));
    15171843                var prettified_value = '';
    1518                 var used_subparsers = {}; // Used sub parsers for one block, will be asdreset for each block. Declared as global, because it is manipulation inside much sub parsers.
     1844                var used_subparsers = {}; // Used sub parsers for one block, will be reset for each block. Declared as global, because it is manipulation inside various sub parsers.
    15191845                var week_stable = true;
    15201846
     
    15761902                                        selectors.date.push(selectors.weekday);
    15771903
     1904                                // console.log('weekday: ' + JSON.stringify(selectors.weekday, null, '\t'));
    15781905                                blocks.push(selectors);
    15791906
     
    16051932                        } while (continue_at)
    16061933                }
    1607 
    1608                 // Tokenization function: Splits string into parts.
     1934                // }}}
     1935
     1936                // Tokenization function: Splits string into parts. {{{
    16091937                // output: array of arrays of pairs [content, type]
    16101938                function tokenize(value) {
     
    16161944                        while (value != '') {
    16171945                                var tmp;
    1618                                 if (tmp = value.match(/^(?:week\b|open|unknown)/i)) {
     1946                                if (tmp = value.match(/^(?:week\b|open\b|unknown)/i)) {
    16191947                                        // reserved word
    16201948                                        curr_block_tokens.push([tmp[0].toLowerCase(), tmp[0].toLowerCase(), value.length ]);
     
    16361964                                        curr_block_tokens.push([tmp[0].toLowerCase(), 'calcday', value.length ]);
    16371965                                        value = value.substr(tmp[0].length);
    1638                                 } else if (tmp = value.match(/^(&|–|ー|~|~|:|[a-zA-ZäÄàÀéÉ]+\b)\.?/i)) {
     1966                                } else if (tmp = value.match(/^(&|_|→|–|−|=|opening_hours=|ー|\?|~|~|:|°°|25x7|7[ ]?days( a week|)|all days?|every day|-late|public holidays?|7j?\/7|every day|до|рм|ам|jours fériés|sonn-|[a-zäößàáéøčěíúýřПнВсо]+\b)\.?/i)) {
    16391967                                        // Handle all remaining words with error tolerance
    16401968                                        var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length);
     
    17022030                        return all_tokens;
    17032031                }
    1704 
    1705                 // error correction/tolerance
     2032                // }}}
     2033
     2034                // error correction/tolerance function {{{
     2035                // Go through word_error_correction hash and get correct value back.
    17062036                function returnCorrectWordOrToken(word, value_length) {
    17072037                        for (var token_name in word_error_correction) {
     
    17182048                                                                for (correct_abbr in word_error_correction[token_name]['default']) {
    17192049                                                                        if (word_error_correction[token_name]['default'][correct_abbr] == val)
    1720                                                                                 break;
     2050                                                                                break; // FIXME
    17212051                                                                }
     2052                                                                // FIXME
    17222053                                                                if (token_name != 'timevar') { // normally written in lower case
    17232054                                                                        correct_abbr = correct_abbr.charAt(0).toUpperCase() + correct_abbr.slice(1);
     
    17332064                        }
    17342065                }
    1735 
     2066                // }}}
     2067
     2068                // return warnings as list {{{
    17362069                function getWarnings(it) {
    1737 
    17382070                        if (typeof it == 'object') { // getWarnings was called in a state without critical errors. We can do extended tests.
    17392071
    1740                                 // Check if 24/7 is used and it does not mean 24/7 because there are other rules. This can be avoided.
     2072                                // Check if 24/7 is used and it does not mean 24/7 because there are other blocks.
    17412073                                var has_advanced = it.advance();
    17422074
     
    17562088                        return warnings;
    17572089                }
    1758 
    1759                 // Function to check token array for specific pattern
     2090                // }}}
     2091
     2092                // Function to check token array for specific pattern {{{
    17602093                function matchTokens(tokens, at /*, matches... */) {
    17612094                        if (at + arguments.length - 2 > tokens.length)
     
    17682101                        return true;
    17692102                }
    1770 
     2103                // }}}
     2104
     2105                // Generate selector wrapper with time offset {{{
    17712106                function generateDateShifter(func, shift) {
    17722107                        return function(date) {
     
    17782113                        }
    17792114                }
    1780 
    1781                 //======================================================================
    1782                 // Top-level parser
    1783                 //======================================================================
     2115                // }}}
     2116
     2117                // Top-level parser {{{
    17842118                function parseGroup(tokens, at, selectors, nblock, conf) {
    17852119                        var prettified_group_value = '';
     
    17932127                                        at = parseWeekdayRange(tokens, at, selectors);
    17942128                                } else if (matchTokens(tokens, at, '24/7')) {
    1795                                         // selectors.time.push(function(date) { return [true]; });
     2129                                        selectors.time.push(function(date) { return [true]; });
    17962130                                        // Not needed. If there is no selector it automatically matches everything.
     2131                                        // WRONG: This only works if there is no other selector in this selector group ...
    17972132                                        at++;
    17982133                                } else if (matchTokens(tokens, at, 'holiday')) {
     
    18262161                                        // This provides compatibility with the syntax proposed by Netzwolf:
    18272162                                        // http://wiki.openstreetmap.org/wiki/Key:opening_hours:specification
    1828                                         if (!done_with_warnings && matchTokens(tokens, at-1, 'weekday') || matchTokens(tokens, at-1, 'holiday'))
     2163                                        if (!done_with_warnings && (matchTokens(tokens, at-1, 'weekday') || matchTokens(tokens, at-1, 'holiday')))
    18292164                                                parsing_warnings.push([nblock, at, 'Please don’t use ":" after ' + tokens[at-1][1] + '.']);
    18302165
     
    18362171                                                || matchTokens(tokens, at, '(', 'timevar')
    18372172                                                || matchTokens(tokens, at, 'number', '-')) {
    1838                                         at = parseTimeRange(tokens, at, selectors);
     2173                                        at = parseTimeRange(tokens, at, selectors, false);
    18392174
    18402175                                        used_subparsers['time ranges'].push(at);
     
    18812216                                                }
    18822217                                        } else { // block starts with comment
    1883                                                 // selectors.time.push(function(date) { return [true]; });
     2218                                                selectors.time.push(function(date) { return [true]; });
    18842219                                                // Not needed. If there is no selector it automatically matches everything.
     2220                                                // WRONG: This only works if there is no other selector in this selector group ...
    18852221                                                selectors.meaning = false;
    18862222                                                selectors.unknown = true;
     
    19352271                                                                        + ' Equal selector types can (and should) always be written in conjunction separated by comma or something.'
    19362272                                                                        + ' Example for time ranges "12:00-13:00,15:00-18:00".'
     2273                                                                        + ' Example for weekdays "Mo-We,Fr".'
    19372274                                                         )
    19382275                                                        + ' Rules can be separated by ";".' ]
     
    19442281                        return at;
    19452282                }
    1946 
    1947                 //======================================================================
    1948                 // Time range parser (10:00-12:00,14:00-16:00)
    1949                 //======================================================================
    1950                 function parseTimeRange(tokens, at, selectors) {
     2283                // }}}
     2284
     2285                // helper functions for sub parser {{{
     2286                // for given date, returns date moved to the start of specified day minute
     2287                function dateAtDayMinutes(date, minutes) {
     2288                        return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes);
     2289                }
     2290
     2291                // for given date, returns date moved to the specific day of week
     2292                function dateAtNextWeekday(date, day) {
     2293                        var delta = day - date.getDay();
     2294                        return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0));
     2295                }
     2296
     2297                function indexOf(needle) {
     2298                        if(typeof Array.prototype.indexOf === 'function') {
     2299                                indexOf = Array.prototype.indexOf;
     2300                        } else {
     2301                                indexOf = function(needle) {
     2302                                        var i = -1, index = -1;
     2303                                        for(i = 0; i < this.length; i++) {
     2304                                                if(this[i] === needle) {
     2305                                                        index = i;
     2306                                                        break;
     2307                                                }
     2308                                        }
     2309                                        return index;
     2310                                };
     2311                        }
     2312                        return indexOf.call(this, needle);
     2313                }
     2314
     2315                // Numeric list parser (1,2,3-4,-1), used in weekday parser above
     2316                function parseNumRange(tokens, at, func) {
     2317                        for (; at < tokens.length; at++) {
     2318                                if (matchTokens(tokens, at, 'number', '-', 'number')) {
     2319                                        // Number range
     2320                                        func(tokens[at][0], tokens[at+2][0], at);
     2321                                        at += 3;
     2322                                } else if (matchTokens(tokens, at, '-', 'number')) {
     2323                                        // Negative number
     2324                                        func(-tokens[at+1][0], -tokens[at+1][0], at);
     2325                                        at += 2
     2326                                } else if (matchTokens(tokens, at, 'number')) {
     2327                                        // Single number
     2328                                        func(tokens[at][0], tokens[at][0], at);
     2329                                        at++;
     2330                                } else {
     2331                                        throw formatWarnErrorMessage(nblock, at + matchTokens(tokens, at, '-'),
     2332                                                'Unexpected token in number range: ' + tokens[at][1]);
     2333                                }
     2334
     2335                                if (!matchTokens(tokens, at, ','))
     2336                                        break;
     2337                        }
     2338
     2339                        return at;
     2340                }
     2341
     2342                function getConstrainedWeekday(tokens, at) {
     2343                        var number = 0;
     2344                        var endat = parseNumRange(tokens, at, function(from, to, at) {
     2345
     2346                                // bad number
     2347                                if (from == 0 || from < -5 || from > 5)
     2348                                        throw formatWarnErrorMessage(nblock, at,
     2349                                                'Number between -5 and 5 (except 0) expected');
     2350
     2351                                if (from == to) {
     2352                                        if (number != 0)
     2353                                                throw formatWarnErrorMessage(nblock, at,
     2354                                                        'You can not use a more than one constrained weekday in a month range');
     2355                                        number = from;
     2356                                } else {
     2357                                        throw formatWarnErrorMessage(nblock, at+2,
     2358                                                'You can not use a range of constrained weekdays in a month range');
     2359                                }
     2360                        });
     2361
     2362                        if (!matchTokens(tokens, endat, ']'))
     2363                                throw formatWarnErrorMessage(nblock, endat, '"]" expected.');
     2364
     2365                        return [ number, endat + 1 ];
     2366                }
     2367
     2368                // Check if period is ok. Period 0 or 1 don’t make much sense.
     2369                function checkPeriod(at, period, period_type, parm_string) {
     2370                        if (done_with_warnings)
     2371                                return;
     2372
     2373                        if (period === 0) {
     2374                                throw formatWarnErrorMessage(nblock, at,
     2375                                        'You can not use '+ period_type +' ranges with period equals zero.');
     2376                        } else if (period === 1) {
     2377                                if (typeof parm_string == 'string' && parm_string == 'no_end_year')
     2378                                        parsing_warnings.push([nblock, at,
     2379                                                'Please don’t use '+ period_type +' ranges with period equals one.'
     2380                                                + ' If you want to express that a facility is open starting from a year without limit use "<year>+".']);
     2381                                else
     2382                                        parsing_warnings.push([nblock, at,
     2383                                                'Please don’t use '+ period_type +' ranges with period equals one.']);
     2384                        }
     2385                }
     2386
     2387                function getDateForConstrainedWeekday(year, month, weekday, constrained_weekday, add_days) {
     2388                        var tmp_date = dateAtNextWeekday(
     2389                                new Date(year, month + (constrained_weekday[0] > 0 ? 0 : 1), 1), weekday);
     2390
     2391                        tmp_date.setDate(tmp_date.getDate() + (constrained_weekday[0] + (constrained_weekday[0] > 0 ? -1 : 0)) * 7);
     2392
     2393                        if (typeof add_days != 'undefined' && add_days[1])
     2394                                tmp_date.setDate(tmp_date.getDate() + add_days[0]);
     2395
     2396                        return tmp_date;
     2397                }
     2398
     2399                function formatWarnErrorMessage(nblock, at, message) {
     2400                        var pos = 0;
     2401                        if (nblock == -1) { // Usage of block index not required because we do have access to value.length.
     2402                                pos = value.length - at;
     2403                        } else { // Issue accrued at a later time, position in string needs to be reconstructed.
     2404                                if (typeof tokens[nblock][0][at] == 'undefined') {
     2405                                        pos = value.length;
     2406                                        if (typeof tokens[nblock][0][tokens[nblock][0].length-1] != 'undefined') {
     2407                                                // pos -= tokens[nblock][0][tokens[nblock][0].length-1][2];
     2408                                                console.warn("FIXME");
     2409                                        }
     2410                                } else {
     2411                                        pos = value.length;
     2412                                        if (typeof tokens[nblock][0][at+1] != 'undefined') {
     2413                                                pos -= tokens[nblock][0][at+1][2];
     2414                                        } else if (typeof tokens[nblock][2] != 'undefined') {
     2415                                                pos -= tokens[nblock][2];
     2416                                        } else {
     2417                                        }
     2418                                }
     2419                        }
     2420                        return value.substring(0, pos) + ' <--- (' + message + ')';
     2421                }
     2422
     2423                // check if date is valid
     2424                function isValidDate(month, day, nblock, at) {
     2425                        // month == 0 is Jan
     2426
     2427                        // May use this instead. Does not say, what is wrong as good was implementation below.
     2428                        // var testDate = new Date(year, month, day);
     2429                        // if (testDate.getDate() != day || testDate.getMonth() != month || testDate.getFullYear() != year) {
     2430                        //      console.error('date not valid');
     2431                        // }
     2432
     2433                        // https://en.wikipedia.org/wiki/Month#Julian_and_Gregorian_calendars
     2434                        if (day < 1 || day > 31)
     2435                                throw formatWarnErrorMessage(nblock, at, 'Day must be between 1 and 31.');
     2436                        if ((month==3 || month==5 || month==8 || month==10) && day==31)
     2437                                throw formatWarnErrorMessage(nblock, at, 'Month ' + months[month] + " doesn't have 31 days.!");
     2438                        if (month == 1 && day == 30)
     2439                                throw formatWarnErrorMessage(nblock, at, 'Month ' + months[1]+ " either has 28 or 29 days (leap years).");
     2440                }
     2441                // }}}
     2442
     2443                // Time range parser (10:00-12:00,14:00-16:00) {{{
     2444                //
     2445                // extended_open_end: <time> - <time> +
     2446                //                 at is here A (if extended_open_end is true)
     2447                function parseTimeRange(tokens, at, selectors, extended_open_end) {
    19512448                        for (; at < tokens.length; at++) {
    19522449                                var has_time_var_calc = [], has_normal_time = []; // element 0: start time, 1: end time
     
    19592456                                        var has_open_end     = false; // default no open end
    19602457                                        var timevar_add      = [ 0, 0 ];
    1961                                         var timevar_string  = [];     // capture timevar string like 'sunrise' to calculate it for the current date.
     2458                                        var timevar_string   = [];    // capture timevar string like 'sunrise' to calculate it for the current date.
    19622459
    19632460                                        // minutes_from
     
    19802477                                                } else {
    19812478                                                        if (oh_mode == 0) {
    1982                                                                 throw formatWarnErrorMessage(nblock, at+(has_normal_time[0] ? 3 : (has_time_var_calc[0] ? 2 : 1)),
     2479                                                                throw formatWarnErrorMessage(nblock, at+(
     2480                                                                                has_normal_time[0] ? (
     2481                                                                                                typeof tokens[at+3] == 'object' ? 3 : 2
     2482                                                                                        ) : (
     2483                                                                                                has_time_var_calc[0] ? 2 : 1
     2484                                                                                        )
     2485                                                                                ),
    19832486                                                                        'hyphen (-) or open end (+) in time range '
    19842487                                                                        + (has_time_var_calc[0] ? 'calculation ' : '') + 'expected.'
     
    20412544
    20422545                                                is_point_in_time = true;
     2546                                        } else if (matchTokens(tokens, at, '+')) {
     2547                                                parseTimeRange(tokens, at_end_time, selectors, true);
     2548                                                at++;
    20432549                                        } else if (oh_mode == 1 && !is_point_in_time) {
    20442550                                                throw formatWarnErrorMessage(nblock, at_end_time,
     
    20542560
    20552561                                        // normalize minutes into range
    2056                                         if (minutes_from >= minutes_in_day)
     2562                                        if (!extended_open_end && minutes_from >= minutes_in_day)
    20572563                                                throw formatWarnErrorMessage(nblock, at_end_time - 1,
    20582564                                                        'Time range starts outside of the current day');
     
    20602566                                                minutes_to += minutes_in_day;
    20612567                                        if (minutes_to > minutes_in_day * 2)
    2062                                                 throw formatWarnErrorMessage(nblock, at_end_time + (has_normal_time[1] ? 3 : (has_time_var_calc[1] ? 7 : 1)) - 1,
     2568                                                throw formatWarnErrorMessage(nblock, at_end_time + (has_normal_time[1] ? 4 : (has_time_var_calc[1] ? 7 : 1)) - 2,
    20632569                                                        'Time spanning more than two midnights not supported');
    20642570
     
    21762682                                                        }}(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period));
    21772683                                                }
     2684                                        } else {
     2685                                                selectors.time.push(function(date) { return [true]; });
    21782686                                        }
    2179                                 } else if (matchTokens(tokens, at, 'number', '-', 'number')) { // "Mo 09-18" -> "Mo 09:00-18:00". Please don’t use this
     2687
     2688                                } else if (matchTokens(tokens, at, 'number', '-', 'number')) { // "Mo 09-18" (Please don’t use this) -> "Mo 09:00-18:00".
    21802689                                        var minutes_from = tokens[at][0]   * 60;
    21812690                                        var minutes_to   = tokens[at+2][0] * 60;
     
    22272736                                } else { // additional block
    22282737                                        if (matchTokens(tokens, at, '('))
    2229                                                 throw formatWarnErrorMessage(nblock, at+1, 'Missing variable time (e.g. sunrise) after: "' + tokens[at][1] + '"');
     2738                                                throw formatWarnErrorMessage(nblock, at, 'Missing variable time (e.g. sunrise) after: "' + tokens[at][1] + '"');
    22302739                                        if (matchTokens(tokens, at, 'number', 'timesep'))
    22312740                                                throw formatWarnErrorMessage(nblock, at+2, 'Missing minutes in time range after: "' + tokens[at+1][1] + '"');
     
    22422751                }
    22432752
    2244                 // for given date, returns date moved to the start of specified day minute
    2245                 function dateAtDayMinutes(date, minutes) {
    2246                         return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes);
    2247                 }
    2248 
    2249                 // extract the added or subtracted time of "(sunrise-01:30)"
    2250                 // returns in minutes e.g. -90
     2753                // get time in minutes from <hour>:<minute> {{{
     2754                // Only used if throwing an error is wanted.
     2755                function getMinutesByHoursMinutes(tokens, nblock, at) {
     2756                        if (tokens[at+2][0] > 59)
     2757                                throw formatWarnErrorMessage(nblock, at+2,
     2758                                                'Minutes are greater than 59.');
     2759                        return tokens[at][0] * 60 + tokens[at+2][0];
     2760                }
     2761                // }}}
     2762
     2763                // get time in minutes from "(sunrise-01:30)" {{{
     2764                // Extract the added or subtracted time from "(sunrise-01:30)"
     2765                // returns time in minutes e.g. -90
    22512766                function parseTimevarCalc(tokens, at) {
    22522767                        if (matchTokens(tokens, at+2, '+') || matchTokens(tokens, at+2, '-')) {
     
    22542769                                        if (matchTokens(tokens, at+6, ')')) {
    22552770                                                var add_or_subtract = tokens[at+2][0] == '+' ? '1' : '-1';
    2256                                                 var minutes = (tokens[at+3][0] * 60 + tokens[at+5][0]) * add_or_subtract;
     2771                                                var minutes = getMinutesByHoursMinutes(tokens, nblock, at+3) * add_or_subtract;
    22572772                                                if (minutes == 0)
    22582773                                                        parsing_warnings.push([ nblock, at+5, 'Adding zero in a variable time calculation does not change the variable time.'
     
    22742789                                        'Calculcation with variable time is not in the right syntax' + error[1]);
    22752790                }
    2276 
    2277                 // Only used if throwing an error is wanted.
    2278                 function getMinutesByHoursMinutes(tokens, nblock, at) {
    2279                         if (tokens[at+2][0] > 59)
    2280                                 throw formatWarnErrorMessage(nblock, at+2,
    2281                                                 'Minutes are greater than 59.');
    2282                         return tokens[at][0] * 60 + tokens[at+2][0];
    2283                 }
    2284 
    2285                 //======================================================================
    2286                 // Weekday range parser (Mo,We-Fr,Sa[1-2,-1])
    2287                 //======================================================================
     2791                // }}}
     2792                // }}}
     2793
     2794                // Weekday range parser (Mo,We-Fr,Sa[1-2,-1],PH) {{{
    22882795                function parseWeekdayRange(tokens, at, selectors) {
    22892796                        for (; at < tokens.length; at++) {
     
    24222929
    24232930                                        if (weekday_to < weekday_from) { // handle full range
    2424                                                 // selectors.weekday.push(function(date) { return [true]; });
     2931                                                selectors.weekday.push(function(date) { return [true]; });
    24252932                                                // Not needed. If there is no selector it automatically matches everything.
     2933                                                // WRONG: This only works if there is no other selector in this selector group ...
    24262934                                        } else {
    24272935                                                selectors.weekday.push(function(weekday_from, weekday_to, inside) { return function(date) {
     
    24522960                        else
    24532961                                used_subparsers['weekdays'].push(at);
    2454 
    2455                         return at;
    2456                 }
    2457 
    2458                 // Numeric list parser (1,2,3-4,-1), used in weekday parser above
    2459                 function parseNumRange(tokens, at, func) {
    2460                         for (; at < tokens.length; at++) {
    2461                                 if (matchTokens(tokens, at, 'number', '-', 'number')) {
    2462                                         // Number range
    2463                                         func(tokens[at][0], tokens[at+2][0], at);
    2464                                         at += 3;
    2465                                 } else if (matchTokens(tokens, at, '-', 'number')) {
    2466                                         // Negative number
    2467                                         func(-tokens[at+1][0], -tokens[at+1][0], at);
    2468                                         at += 2
    2469                                 } else if (matchTokens(tokens, at, 'number')) {
    2470                                         // Single number
    2471                                         func(tokens[at][0], tokens[at][0], at);
    2472                                         at++;
    2473                                 } else {
    2474                                         throw formatWarnErrorMessage(nblock, at + matchTokens(tokens, at, '-'),
    2475                                                 'Unexpected token in number range: ' + tokens[at][1]);
    2476                                 }
    2477 
    2478                                 if (!matchTokens(tokens, at, ','))
    2479                                         break;
    2480                         }
    24812962
    24822963                        return at;
     
    25002981                        return add_days;
    25012982                }
    2502 
    2503 
    2504                 // for given date, returns date moved to the specific day of week
    2505                 function dateAtNextWeekday(date, day) {
    2506                         var delta = day - date.getDay();
    2507                         return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0));
    2508                 }
    2509 
    2510                 //======================================================================
    2511                 // Holiday parser for public and school holidays (PH,SH)
     2983                // }}}
     2984
     2985                // Holiday parser for public and school holidays (PH,SH) {{{
    25122986                // push_to_weekday will push the selector into the weekday selector array which has the desired side effect of working in conjunction with the weekday selectors (either the holiday match or the weekday), which is the normal and expected behavior.
    2513                 //======================================================================
    25142987                function parseHoliday(tokens, at, selectors, push_to_weekday) {
    25152988                        for (; at < tokens.length; at++) {
     
    26613134                }
    26623135
     3136                // Helpers for holiday parsers {{{
    26633137                // Returns a number for a date which can then be used to compare just the dates (without the time).
    26643138                // This is necessary because a selector could be called for the middle of the day and we need to tell if it matches that day.
     
    27463220                        var D = L + 28 - 31*Math.floor(M/4);
    27473221
     3222                        // calculate orthodox easter
     3223                        var oA = Y % 4;
     3224                        var oB = Y % 7;
     3225                        var oC = Y % 19;
     3226                        var oD = (19*oC + 15) % 30;
     3227                        var oE = (2*oA+4*oB - oD + 34) % 7;
     3228                        var oF = oD+oE
     3229
     3230                        if (oF < 9) {oDate = new Date(Y, 4-1, oF+4);}
     3231                        else {if ((oF+4)<31) {oDate = new Date(Y, 4-1, oF+4);}
     3232                              else {oDate = new Date(Y, 5-1, oF-26);}}
     3233
     3234                        // calculate last Sunday in February
     3235                        var lastFebruaryDay = new Date(Y, 2, 0);
     3236                        var lastFebruarySunday = lastFebruaryDay.getDate() - lastFebruaryDay.getDay();
     3237
     3238                        // calculate Victoria Day. last Monday before or on May 24
     3239                        var may_24 = new Date(Y, 4, 24);
     3240                        var victoriaDay = 24  - ((6 + may_24.getDay()) % 7);
     3241
     3242                        // calculate Canada Day. July 1st unless 1st is on Sunday, then July 2.
     3243                        var july_1 = new Date(Y, 6, 1);
     3244                        var canadaDay = july_1.getDay() === 0 ? 2 : 1;
     3245
     3246                        // calculate first Monday for each month
     3247                        var firstMondays = {};
     3248                        for (var i = 0; i < 12; i++) {
     3249                                var first = new Date(Y, i, 1);
     3250                                var firstMonday = 1 + ((8 - first.getDay()) % 7);
     3251                                firstMondays[i] = firstMonday;
     3252                        };
     3253
    27483254                        return {
     3255                                'firstFebruaryMonday': new Date(Y, 1, firstMondays[1]),
     3256                                'lastFebruarySunday': new Date(Y, 1, lastFebruarySunday),
    27493257                                'easter': new Date(Y, M - 1, D),
     3258                                'victoriaDay': new Date(Y, 4, victoriaDay),
     3259                                'canadaDay': new Date(Y, 6, canadaDay),
     3260                                'firstAugustMonday': new Date(Y, 7, firstMondays[7]),
     3261                                'firstSeptemberMonday': new Date(Y, 8, firstMondays[8]),
     3262                                'firstOctoberMonday': new Date(Y, 9, firstMondays[9]),
     3263                                'orthodox easter' : oDate,
    27503264                        };
    2751                 }
    2752 
    2753                 function indexOf(needle) {
    2754                         if(typeof Array.prototype.indexOf === 'function') {
    2755                                 indexOf = Array.prototype.indexOf;
    2756                         } else {
    2757                                 indexOf = function(needle) {
    2758                                         var i = -1, index = -1;
    2759                                         for(i = 0; i < this.length; i++) {
    2760                                                 if(this[i] === needle) {
    2761                                                         index = i;
    2762                                                         break;
    2763                                                 }
    2764                                         }
    2765                                         return index;
    2766                                 };
    2767                         }
    2768                         return indexOf.call(this, needle);
    27693265                }
    27703266
     
    28093305                        return sorted_holidays;
    28103306                }
    2811 
    2812                 //======================================================================
    2813                 // Year range parser (2013,2016-2018,2020/2)
    2814                 //======================================================================
     3307                // }}}
     3308                // }}}
     3309
     3310                // Year range parser (2013,2016-2018,2020/2) {{{
    28153311                function parseYearRange(tokens, at) {
    28163312                        for (; at < tokens.length; at++) {
     
    28203316                                                var is_range   = true;
    28213317                                                var has_period = true;
    2822                                                 if (!done_with_warnings && tokens[at+4][0] == 1)
    2823                                                         parsing_warnings.push([nblock, at+1+3, 'Please don’t use year ranges with period equals one (see README)']);
     3318                                                var period = parseInt(tokens[at+4][0]);
     3319                                                checkPeriod(at+4, period, 'year');
    28243320                                        } else {
    28253321                                                var is_range   = matchTokens(tokens, at+1, '-', 'year');
    28263322                                                var has_period = matchTokens(tokens, at+1, '/', 'number');
     3323                                                if (has_period) {
     3324                                                        var period = parseInt(tokens[at+2][0]);
     3325                                                        checkPeriod(at+2, period, 'year', 'no_end_year');
     3326                                                } else if (matchTokens(tokens, at+1, '+')) {
     3327                                                        var period = 1;
     3328                                                        has_period = 2;
     3329                                                }
    28273330                                        }
    28283331
    2829                                         selectors.year.push(function(tokens, at, is_range, has_period) { return function(date) {
     3332                                        var year_from = parseInt(tokens[at][0]);
     3333                                        // error checking {{{
     3334                                                if (is_range && tokens[at+2][0] <= year_from) {
     3335                                                // handle reversed range
     3336                                                if (tokens[at+2][0] == year_from)
     3337                                                        throw formatWarnErrorMessage(nblock, at,
     3338                                                                'A year range in which the start year is equal to the end year does not make sense.'
     3339                                                                + ' Please remove the end year. E.g. "' + year_from + ' May 23"');
     3340                                                else
     3341                                                        throw formatWarnErrorMessage(nblock, at,
     3342                                                                'A year range in which the start year is greater than the end year does not make sense.'
     3343                                                                + ' Please turn it over.');
     3344                                                }
     3345                                        // }}}
     3346
     3347                                        selectors.year.push(function(tokens, at, year_from, is_range, has_period, period) { return function(date) {
    28303348                                                var ouryear = date.getFullYear();
    2831                                                 var year_from = tokens[at][0];
    2832                                                 var year_to = is_range ? tokens[at+2][0] : year_from;
    2833 
    2834                                                 // handle reversed range
    2835                                                 if (year_to < year_from) {
    2836                                                         var tmp = year_to;
    2837                                                         year_to = year_from;
    2838                                                         year_from = tmp;
    2839                                                 }
     3349                                                var year_to = is_range ? parseInt(tokens[at+2][0]) : year_from;
    28403350
    28413351                                                if (ouryear < year_from ){
     
    28433353                                                } else if (has_period) {
    28443354                                                        if (year_from <= ouryear) {
    2845                                                                 if (is_range) {
    2846                                                                         var period = tokens[at+4][0];
    2847 
    2848                                                                         if (year_to < ouryear)
    2849                                                                                 return [false];
    2850                                                                 } else {
    2851                                                                         var period = tokens[at+2][0];
    2852                                                                 }
     3355                                                                if (is_range && year_to < ouryear)
     3356                                                                        return [false];
    28533357                                                                if (period > 0) {
    28543358                                                                        if ((ouryear - year_from) % period == 0) {
     
    28603364                                                        }
    28613365                                                } else if (is_range) {
    2862                                                         if (year_from <= ouryear && ouryear <= year_to)
     3366                                                        if (ouryear <= year_to)
    28633367                                                                return [true, new Date(year_to + 1, 0, 1)];
    28643368                                                } else if (ouryear == year_from) {
     
    28683372                                                return [false];
    28693373
    2870                                         }}(tokens, at, is_range, has_period));
    2871 
    2872                                         at += 1 + (is_range ? 2 : 0) + (has_period ? 2 : 0);
     3374                                        }}(tokens, at, year_from, is_range, has_period, period));
     3375
     3376                                        at += 1 + (is_range ? 2 : 0) + (has_period ? (has_period == 2 ? 1 : 2) : 0);
    28733377                                } else {
    28743378                                        throw formatWarnErrorMessage(nblock, at, 'Unexpected token in year range: ' + tokens[at][1]);
     
    28863390                        return at;
    28873391                }
    2888 
    2889                 //======================================================================
    2890                 // Week range parser (week 11-20, week 1-53/2)
    2891                 //======================================================================
     3392                // }}}
     3393
     3394                // Week range parser (week 11-20, week 1-53/2) {{{
    28923395                function parseWeekRange(tokens, at) {
    28933396                        for (; at < tokens.length; at++) {
     
    29723475                        return date;
    29733476                }
    2974 
    2975                 //======================================================================
    2976                 // Month range parser (Jan,Feb-Mar)
    2977                 //======================================================================
    2978                 function parseMonthRange(tokens, at) {
     3477                // }}}
     3478
     3479                // Month range parser (Jan,Feb-Mar) {{{
     3480                // push_to_monthday will push the selector into the monthday selector array which has the desired side effect of working in conjunction with the monthday selectors (either the month match or the monthday).
     3481                function parseMonthRange(tokens, at, push_to_monthday) {
    29793482                        for (; at < tokens.length; at++) {
    2980                                 if (matchTokens(tokens, at, 'month')) {
     3483                                // Use parseMonthdayRange if '<month> <daynum>' and not '<month> <hour>:<minute>'
     3484                                if (matchTokens(tokens, at, 'month', 'number') && !matchTokens(tokens, at+2, 'timesep', 'number')) {
     3485                                        return parseMonthdayRange(tokens, at, nblock, true);
     3486                                } else if (matchTokens(tokens, at, 'month')) {
    29813487                                        // Single month (Jan) or month range (Feb-Mar)
    29823488                                        var is_range = matchTokens(tokens, at+1, '-', 'month');
     
    29933499                                        }
    29943500
    2995                                         selectors.month.push(function(tokens, at, is_range) { return function(date) {
     3501                                        var selector = function(tokens, at, is_range) { return function(date) {
    29963502                                                var ourmonth = date.getMonth();
    29973503                                                var month_from = tokens[at][0];
     
    30173523                                                        return [inside, dateAtNextMonth(date, month_to + 1)];
    30183524                                                }
    3019                                         }}(tokens, at, is_range));
     3525                                        }}(tokens, at, is_range);
     3526
     3527                                        if (push_to_monthday === true)
     3528                                                selectors.monthday.push(selector);
     3529                                        else
     3530                                                selectors.month.push(selector);
    30203531
    30213532                                        at += is_range ? 3 : 1;
     
    30393550                        return new Date(date.getFullYear(), month < date.getMonth() ? month + 12 : month);
    30403551                }
    3041 
    3042                 function getConstrainedWeekday(tokens, at) {
    3043                         var number = 0;
    3044                         var endat = parseNumRange(tokens, at, function(from, to, at) {
    3045 
    3046                                 // bad number
    3047                                 if (from == 0 || from < -5 || from > 5)
    3048                                         throw formatWarnErrorMessage(nblock, at,
    3049                                                 'Number between -5 and 5 (except 0) expected');
    3050 
    3051                                 if (from == to) {
    3052                                         if (number != 0)
    3053                                                 throw formatWarnErrorMessage(nblock, at,
    3054                                                         'You can not use a more than one constrained weekday in a month range');
    3055                                         number = from;
    3056                                 } else {
    3057                                         throw formatWarnErrorMessage(nblock, at+2,
    3058                                                 'You can not use a range of constrained weekdays in a month range');
    3059                                 }
    3060                         });
    3061 
    3062                         if (!matchTokens(tokens, endat, ']'))
    3063                                 throw formatWarnErrorMessage(nblock, endat, '"]" expected.');
    3064 
    3065                         return [ number, endat + 1 ];
    3066                 }
    3067 
    3068                 function getDateForConstrainedWeekday(year, month, weekday, constrained_weekday, add_days) {
    3069                         var tmp_date = dateAtNextWeekday(
    3070                                 new Date(year, month + (constrained_weekday[0] > 0 ? 0 : 1), 1), weekday);
    3071 
    3072                         tmp_date.setDate(tmp_date.getDate() + (constrained_weekday[0] + (constrained_weekday[0] > 0 ? -1 : 0)) * 7);
    3073 
    3074                         if (typeof add_days != 'undefined' && add_days[1])
    3075                                 tmp_date.setDate(tmp_date.getDate() + add_days[0]);
    3076 
    3077                         return tmp_date;
    3078                 }
    3079 
    3080                 //======================================================================
    3081                 // Month day range parser (Jan 26-31; Jan 26-Feb 26)
    3082                 //======================================================================
    3083                 function parseMonthdayRange(tokens, at, nblock) {
     3552                // }}}
     3553
     3554                // Month day range parser (Jan 26-31; Jan 26-Feb 26) {{{
     3555                // push_to_month will push the selector into the month selector array which has the desired side effect of working in conjunction with the month selectors (either the month match or the monthday).
     3556                function parseMonthdayRange(tokens, at, nblock, push_to_month) {
    30843557                        for (; at < tokens.length; at++) {
    30853558                                var has_year = [], has_month = [], has_event = [], has_calc = [], has_constrained_weekday = [], has_calc = [];
     
    31163589                                }
    31173590
     3591                                // monthday range like Jan 26-Feb 26 {{{
    31183592                                if (has_year[0] == has_year[1] && (has_month[1] || has_event[1] || has_constrained_weekday[1])) {
    31193593
    3120                                         selectors.monthday.push(function(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday) { return function(date) {
     3594                                        if (has_month[0])
     3595                                                isValidDate(tokens[at+has_year[0]][0], tokens[at+has_year[0]+1][0], nblock, at+has_year[0]+1);
     3596                                        if (has_month[1])
     3597                                                isValidDate(tokens[at_sec_event_or_month][0], tokens[at_sec_event_or_month+1][0], nblock, at+has_year[0]+1);
     3598
     3599                                        var selector = function(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday) { return function(date) {
    31213600                                                var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
    31223601
     
    32103689                                                        }
    32113690                                                }
    3212                                         }}(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday));
     3691                                        }}(tokens, at, nblock, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday);
     3692
     3693                                        if (push_to_month === true)
     3694                                                selectors.month.push(selector);
     3695                                        else
     3696                                                selectors.monthday.push(selector);
    32133697
    32143698                                        at = (has_constrained_weekday[1]
     
    32173701                                                + (typeof has_calc[1] != 'undefined' ? has_calc[1][1] : 0);
    32183702
     3703                                        // }}}
     3704                                        // Monthday range like Jan 26-31 {{{
    32193705                                } else if (has_month[0]) {
    32203706
    3221                                         var is_range = matchTokens(tokens, at+2+has_year[0], '-', 'number'), has_period = false;
    3222                                         if (is_range)
    3223                                                 has_period = matchTokens(tokens, at+4+has_year[0], '/', 'number');
    3224 
    3225                                         var at_timesep_if_monthRange = at + has_year[0] + 1 // at month number
    3226                                                 + (is_range ? 2 : 0) + (has_period ? 2 : 0)
    3227                                                 + !(is_range || has_period); // if not range nor has_period, add one
    3228 
    3229                                         if (matchTokens(tokens, at_timesep_if_monthRange, 'timesep', 'number')
    3230                                                         && (matchTokens(tokens, at_timesep_if_monthRange+2, '+')
    3231                                                                 || matchTokens(tokens, at_timesep_if_monthRange+2, '-')))
    3232                                                 return parseMonthRange(tokens, at);
    3233 
    3234                                         selectors.monthday.push(function(tokens, at, is_range, has_period, has_year) { return function(date) {
    3235                                                 var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
    3236 
    3237                                                 var from_date = new Date((has_year ? tokens[at][0] : date.getFullYear()),
    3238                                                         tokens[at+has_year][0], tokens[at+1 + has_year][0]);
    3239                                                 var to_date   = new Date(from_date.getFullYear(), from_date.getMonth(),
    3240                                                         tokens[at+(is_range ? 3 : 1)+has_year][0] + 1);
    3241 
    3242                                                 if (date.getTime() < from_date.getTime())
    3243                                                         return [false, from_date];
    3244                                                 else if (date.getTime() >= to_date.getTime())
    3245                                                         return [false, start_of_next_year];
    3246                                                 else if (!has_period)
    3247                                                         return [true, to_date];
    3248 
    3249                                                 var period = tokens[at+has_year+5][0];
    3250                                                 if (!done_with_warnings && period == 1)
    3251                                                         parsing_warnings.push([nblock, at+has_year+5, 'Please don’t use day ranges with period equals one (see README)']);
    3252                                                 var nday = Math.floor((date.getTime() - from_date.getTime()) / msec_in_day);
    3253                                                 var in_period = nday % period;
    3254 
    3255                                                 if (in_period == 0)
    3256                                                         return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
     3707                                        has_year = has_year[0];
     3708                                        var year = tokens[at][0]; // Could be month if has no year. Tested later.
     3709                                        var month = tokens[at+has_year][0];
     3710
     3711                                        var first_round = true;
     3712
     3713                                        do {
     3714                                                var range_from = tokens[at+1 + has_year][0];
     3715                                                var is_range = matchTokens(tokens, at+2+has_year, '-', 'number');
     3716                                                var period = undefined;
     3717                                                var range_to = tokens[at+has_year+(is_range ? 3 : 1)][0] + 1;
     3718                                                if (is_range && matchTokens(tokens, at+has_year+4, '/', 'number')) {
     3719                                                        period = tokens[at+has_year+5][0];
     3720                                                        checkPeriod(at+has_year+5, period, 'day');
     3721                                                }
     3722
     3723                                                if (first_round) {
     3724                                                        var at_timesep_if_monthRange = at + has_year + 1 // at month number
     3725                                                                + (is_range ? 2 : 0) + (period ? 2 : 0)
     3726                                                                + !(is_range || period); // if not range nor has period, add one
     3727
     3728                                                        // Check for '<month> <timespan>'
     3729                                                        if (matchTokens(tokens, at_timesep_if_monthRange, 'timesep', 'number')
     3730                                                                        && (matchTokens(tokens, at_timesep_if_monthRange+2, '+')
     3731                                                                                || matchTokens(tokens, at_timesep_if_monthRange+2, '-')
     3732                                                                                || oh_mode != 0))
     3733                                                                return parseMonthRange(tokens, at);
     3734                                                }
     3735
     3736                                                // error checking {{{
     3737                                                if (range_to < range_from)
     3738                                                        throw formatWarnErrorMessage(nblock, at+has_year+3,
     3739                                                                        'Range in wrong order. From day is greater than to day.');
     3740                                                isValidDate(month, range_from, nblock, at+1 + has_year);
     3741                                                isValidDate(month, range_to - 1 /* added previously */,
     3742                                                                nblock, at+has_year+(is_range ? 3 : 1));
     3743                                                // }}}
     3744
     3745                                                var selector = function(year, has_year, month, range_from, range_to, period) { return function(date) {
     3746                                                        var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
     3747
     3748                                                        var from_date = new Date(has_year ? year : date.getFullYear(),
     3749                                                                month, range_from);
     3750                                                        if (month == 1 && range_from != from_date.getDate()) // Only on leap years does this day exist.
     3751                                                                return [false]; // If day 29 does not exist,
     3752                                                                                                // then the date object adds one day to date
     3753                                                                                                // and this selector should not match.
     3754                                                        var to_date   = new Date(from_date.getFullYear(),
     3755                                                                month, range_to);
     3756                                                        if (month == 1 && is_range && range_to != to_date.getDate()) // Only on leap years does this day exist.
     3757                                                                return [false];
     3758
     3759                                                        if (date.getTime() < from_date.getTime())
     3760                                                                return [false, from_date];
     3761                                                        else if (date.getTime() >= to_date.getTime())
     3762                                                                return [false, start_of_next_year];
     3763                                                        else if (!period)
     3764                                                                return [true, to_date];
     3765
     3766                                                        var nday = Math.floor((date.getTime() - from_date.getTime()) / msec_in_day);
     3767                                                        var in_period = nday % period;
     3768
     3769                                                        if (in_period == 0)
     3770                                                                return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
     3771                                                        else
     3772                                                                return [false, new Date(date.getFullYear(), date.getMonth(), date.getDate() + period - in_period)];
     3773
     3774                                                }}(year, has_year, month, range_from, range_to, period);
     3775
     3776                                                if (push_to_month === true)
     3777                                                        selectors.month.push(selector);
    32573778                                                else
    3258                                                         return [false, new Date(date.getFullYear(), date.getMonth(), date.getDate() + period - in_period)];
    3259 
    3260                                         }}(tokens, at, is_range, has_period, has_year[0]));
    3261 
    3262                                         at += 2 + has_year[0] + (is_range ? 2 : 0) + (has_period ? 2 : 0);
    3263 
     3779                                                        selectors.monthday.push(selector);
     3780
     3781                                                at += 2 + has_year + (is_range ? 2 : 0) + (period ? 2 : 0);
     3782
     3783                                                first_round = false;
     3784                                        }
     3785                                        while (matchTokens(tokens, at, ',', 'number'))
     3786
     3787
     3788                                        // }}}
     3789                                        // Only event like easter {{{
    32643790                                } else if (has_event[0]) {
    32653791
    3266                                         selectors.monthday.push(function(tokens, at, nblock, has_event, has_year, add_days) { return function(date) {
     3792                                        var selector = function(tokens, at, nblock, has_year, add_days) { return function(date) {
    32673793
    32683794                                                // console.log('enter selector with date: ' + date);
     
    32893815                                                        return [false, new Date(date.getFullYear() + 1, 0, 1)];
    32903816
    3291                                         }}(tokens, at, nblock, has_event[0], has_year[0], has_calc[0]));
     3817                                        }}(tokens, at, nblock, has_year[0], has_calc[0]);
     3818
     3819                                        if (push_to_month === true)
     3820                                                selectors.month.push(selector);
     3821                                        else
     3822                                                selectors.monthday.push(selector);
    32923823
    32933824                                        at += has_year[0] + has_event[0] + (typeof has_calc[0][1] != 'undefined' && has_calc[0][1] ? 3 : 0);
     3825                                        // }}}
    32943826                                } else if (has_constrained_weekday[0]) {
    32953827                                        at = parseMonthRange(tokens, at);
    32963828                                } else if (matchTokens(tokens, at, 'month')) {
    3297                                         return parseMonthRange(tokens, at);
     3829                                        return parseMonthRange(tokens, at, true);
    32983830                                } else {
    32993831                                        // throw 'Unexpected token in monthday range: "' + tokens[at] + '"';
     
    33123844                        return at;
    33133845                }
    3314 
    3315                 //======================================================================
    3316                 // Main selector traversal function
    3317                 //======================================================================
     3846                // }}}
     3847
     3848                // Main selector traversal function (return state array for date) {{{
    33183849                this.getStatePair = function(date) {
    33193850                        var resultstate = false;
     
    34153946                                                        match_block = block;
    34163947
    3417                                                         if (typeof blocks[block].comment != 'undefined') // only use comment if one is specified
     3948                                                        if (typeof blocks[block].comment == 'string') // only use comment if one is specified
    34183949                                                                comment     = blocks[block].comment;
    34193950                                                        else if (typeof comment == 'object') // holiday name
     
    34343965                                                                        changedate = res[1];
    34353966
    3436                                                                 break block; // fallback block matched, no need for checking the rest
     3967                                                                // break block; // Fallback block matched, no need for checking the rest.
     3968                                                                // WRONG: What if 'off' is used after fallback block.
    34373969                                                        }
    34383970                                                }
     
    34463978                        return [ resultstate, changedate, unknown, comment, match_block ];
    34473979                }
    3448 
    3449                 function formatWarnErrorMessage(nblock, at, message) {
    3450                         var pos = 0;
    3451                         if (nblock == -1) { // usage of block index not required because we do have access to value.length
    3452                                 pos = value.length - at;
    3453                         } else { // Issue accrued at a later time, position in string needs to be reconstructed.
    3454                                 if (typeof tokens[nblock][0][at] == 'undefined') {
    3455                                         pos = value.length;
    3456                                 } else {
    3457                                         pos = value.length;
    3458                                         if (typeof tokens[nblock][0][at+1] != 'undefined')
    3459                                                 pos -= tokens[nblock][0][at+1][2];
    3460                                         else if (typeof tokens[nblock][2] != 'undefined')
    3461                                                 pos -= tokens[nblock][2];
    3462                                 }
    3463                         }
    3464                         return value.substring(0, pos) + ' <--- (' + message + ')';
    3465                 }
    3466 
     3980                // }}}
     3981
     3982                // generate prettified value based on tokens {{{
    34673983                function prettifySelector(tokens, at, last_at, conf, used_parseTimeRange) {
    34683984                        var value = '';
     
    35274043                        return value + ' ';
    35284044                }
     4045                // }}}
    35294046
    35304047                //======================================================================
    3531                 // Public interface
     4048                // Public interface {{{
    35324049                // All functions below are considered public.
    35334050                //======================================================================
    35344051
    35354052                //======================================================================
    3536                 // Iterator interface
     4053                // Iterator interface {{{
    35374054                //======================================================================
    35384055                this.getIterator = function(date) {
     
    36434160                        }(this);
    36444161                }
    3645 
    3646                 // get parse warnings
    3647                 // returns an empty string if there are no warnings
     4162                // }}}
     4163
     4164                // Simple API {{{
     4165
     4166                // Get parse warnings.
     4167                // Returns an empty string if there are no warnings.
    36484168                this.getWarnings = function() {
    36494169                        var it = this.getIterator();
     
    36514171                }
    36524172
    3653                 // get a nicely formated value.
     4173                // Get a nicely formated value.
    36544174                this.prettifyValue = function(user_conf) {
    36554175                        if (typeof user_conf != 'object')
     
    37064226                }
    37074227
    3708                 // check whether facility is `open' on the given date (or now)
     4228                // Check whether facility is `open' on the given date (or now).
    37094229                this.getState = function(date) {
    37104230                        var it = this.getIterator(date);
     
    37154235                // True will only be returned if the state is false as the getState only
    37164236                // returns true if the amenity is really open. So you may want to check
    3717                 // the resold of getUnknown if getState returned false.
     4237                // the result of getUnknown if getState returned false.
    37184238                this.getUnknown = function(date) {
    37194239                        var it = this.getIterator(date);
     
    37284248
    37294249                // Returns the comment.
    3730                 // Most often this will be an empty string as comments are not used that
    3731                 // often in OSM yet.
     4250                // If no comment is specified this function will return undefined.
    37324251                this.getComment = function(date) {
    37334252                        var it = this.getIterator(date);
     
    37354254                }
    37364255
     4256                // Return the block which matched thus deterrents the current state.
    37374257                this.getMatchingRule = function(date) {
    37384258                        var it = this.getIterator(date);
     
    37404260                }
    37414261
    3742                 // returns time of next status change
     4262                // Returns time of next status change.
    37434263                this.getNextChange = function(date, maxdate) {
    37444264                        var it = this.getIterator(date);
     
    37474267                        return it.getDate();
    37484268                }
     4269
     4270                // Checks whether open intervals are same for every week.
     4271                this.isWeekStable = function() {
     4272                        return week_stable;
     4273                }
     4274                // }}}
     4275
     4276                // High-level API {{{
    37494277
    37504278                // return array of open intervals between two dates
     
    38264354                        return [ open, unknown ];
    38274355                }
    3828 
    3829                 this.isWeekStable = function() {
    3830                         return week_stable;
    3831                 }
     4356                // }}}
     4357                // }}}
    38324358        }
    38334359}));
Note: See TracChangeset for help on using the changeset viewer.