diff --git a/later.js b/later.js index 2cdbb58..20fb4f8 100644 --- a/later.js +++ b/later.js @@ -1023,10 +1023,12 @@ later = function() { return parseExpr(hasSeconds ? e : "0 " + e); }; later.parse.recur = function() { - var schedules = [], exceptions = [], cur, curArr = schedules, curName, values, every, modifier, applyMin, applyMax, i, last; + var schedules = [], exceptions = [], newException = {}, settingException = false, cur, curArr = schedules, curName, values, every, modifier, applyMin, applyMax, i, last; function add(name, min, max) { name = modifier ? name + "_" + modifier : name; - if (!cur) { + if (settingException && !cur) { + cur = curArr[curArr.push(newException) - 1]; + } else if (!cur) { curArr.push({}); cur = curArr[0]; } @@ -1175,14 +1177,37 @@ later = function() { add(last.n, start, end); return this; }, - and: function() { - cur = curArr[curArr.push({}) - 1]; + and: function(exceptionTag) { + if (exceptionTag && settingException) { + cur = curArr[curArr.push({ + tag: exceptionTag + }) - 1]; + } else { + cur = curArr[curArr.push({}) - 1]; + } + if (curArr !== exceptions) { + newException = {}; + settingException = false; + } return this; }, - except: function() { + except: function(tag) { + if (tag) { + newException.tag = tag; + } + settingException = true; curArr = exceptions; cur = null; return this; + }, + removeException: function(tag) { + for (var i = 0; i < exceptions.length; i++) { + if (exceptions[i].tag === tag) { + exceptions.splice(i, 1); + break; + } + } + return this; } }; }; diff --git a/src/parse/recur.js b/src/parse/recur.js index 0c1b01d..fe5fa2c 100644 --- a/src/parse/recur.js +++ b/src/parse/recur.js @@ -14,6 +14,8 @@ later.parse.recur = function () { var schedules = [], exceptions = [], + newException = {}, + settingException = false, cur, curArr = schedules, curName, @@ -29,7 +31,9 @@ later.parse.recur = function () { function add(name, min, max) { name = modifier ? name + '_' + modifier : name; - if (!cur) { + if (settingException && !cur) { + cur = curArr[curArr.push(newException) - 1]; + } else if (!cur) { curArr.push({}); cur = curArr[0]; } @@ -484,10 +488,19 @@ later.parse.recur = function () { * recur().every(5).minutes().on(1).dayOfWeek().and().every(10) * .minutes().on(2).dayOfWeek(); * + * @param {String} exceptionTag: An optional tag used to cancel an exception in a composite exception schedule * @api public */ - and: function () { - cur = curArr[curArr.push({}) - 1]; + and: function (exceptionTag) { + if (exceptionTag && settingException) { + cur = curArr[curArr.push({tag: exceptionTag}) - 1]; + } else { + cur = curArr[curArr.push({}) - 1]; + } + if (curArr !== exceptions) { + newException = {}; + settingException = false; + } return this; }, @@ -502,12 +515,40 @@ later.parse.recur = function () { * recur().at('08:00:00').on(2).dayOfWeek().except() * .dayOfWeekCount(1); * + * @param {String} tag: An optional tag used to cancel an exception * @api public */ - except: function () { + except: function (tag) { + if (tag) { + newException.tag = tag; + } + settingException = true; curArr = exceptions; cur = null; return this; + }, + + /** + * Removes exceptions from a schedule. The given tag will be checked + * against the exceptions' tags in the array and will be removed + * based on a matching String tag. To remove an + * exception: + * + * var schedule = recur().at('08:00:00').on(2).dayOfWeek().except('Monday') + * .dayOfWeekCount(1); + * schedule.removeException('Monday'); + * + * @param {String} tag: An optional tag used to cancel an exception + * @api public + */ + removeException: function (tag) { + for (var i = 0; i < exceptions.length; i++) { + if (exceptions[i].tag === tag) { + exceptions.splice(i, 1); + break; + } + } + return this; } }; -}; \ No newline at end of file +}; diff --git a/test/parse/recur-test.js b/test/parse/recur-test.js index 3c8c258..cef209d 100644 --- a/test/parse/recur-test.js +++ b/test/parse/recur-test.js @@ -219,6 +219,36 @@ describe('Parse Recur', function() { r.exceptions[1].M.should.eql([0]); }); + it('should tag exception schedules', function() { + var r = recur().except('Sunday').on(0).dayOfWeek(); + r.exceptions[0].should.eql({tag: 'Sunday', d: [0]}); + r.exceptions[0].tag.should.eql('Sunday'); + }); + + it('should tag both exception schedules when using .and()', function() { + var r = recur().except('Start time').on(5).minute().and('Skip month').on(0).month(); + r.exceptions[0].should.eql({tag: 'Start time', m: [5]}); + r.exceptions[1].should.eql({tag: 'Skip month', M: [0]}); + r.exceptions[0].tag.should.eql('Start time'); + r.exceptions[1].tag.should.eql('Skip month'); + }); + + it('should remove an exception from the exception schedule', function() { + var r = recur().except('Sunday').on(0).dayOfWeek(); + r.removeException('Sunday'); + r.exceptions.should.eql([]); + }); + + it('should remove an exception from a composite exception schedule', function() { + var r = recur().except('Start time').on(5).minute().and('Skip month').on(0).month(); + r.exceptions[0].tag.should.eql('Start time'); + r.exceptions[1].tag.should.eql('Skip month'); + r.removeException('Start time'); + r.exceptions[0].tag.should.eql('Skip month'); + r.removeException('Skip month'); + r.exceptions.should.eql([]); + }); + }); -}); \ No newline at end of file +});