diff --git a/__tests__/LevelStore.spec.js b/__tests__/LevelStore.spec.js index efcd8ac9a..74e3e39ca 100644 --- a/__tests__/LevelStore.spec.js +++ b/__tests__/LevelStore.spec.js @@ -23,7 +23,7 @@ describe('this store', function() { expect(LevelStore.isLevelSolved(firstLevel.id)) .toEqual(false); - LevelActions.setLevelSolved(firstLevel.id); + LevelActions.setLevelSolved(firstLevel.id, false); expect(LevelStore.isLevelSolved(firstLevel.id)) .toEqual(true); LevelActions.resetLevelsSolved(); @@ -31,4 +31,21 @@ describe('this store', function() { .toEqual(false); }); + it('can solve a level with best status and then reset', function() { + var sequenceMap = LevelStore.getSequenceToLevels(); + var firstLevel = sequenceMap[ + Object.keys(sequenceMap)[0] + ][0]; + + expect(LevelStore.isLevelBest(firstLevel.id)) + .toEqual(false); + LevelActions.setLevelSolved(firstLevel.id, true); + expect(LevelStore.isLevelBest(firstLevel.id)) + .toEqual(true); + LevelActions.resetLevelsSolved(); + expect(LevelStore.isLevelBest(firstLevel.id)) + .toEqual(false); + }); + + }); diff --git a/src/js/actions/LevelActions.js b/src/js/actions/LevelActions.js index 5aebff8f2..01e52d313 100644 --- a/src/js/actions/LevelActions.js +++ b/src/js/actions/LevelActions.js @@ -7,10 +7,11 @@ var ActionTypes = AppConstants.ActionTypes; var LevelActions = { - setLevelSolved: function(levelID) { + setLevelSolved: function(levelID, best) { AppDispatcher.handleViewAction({ type: ActionTypes.SET_LEVEL_SOLVED, - levelID: levelID + levelID: levelID, + best: best }); }, @@ -29,4 +30,4 @@ var LevelActions = { }; -module.exports = LevelActions; +module.exports = LevelActions; \ No newline at end of file diff --git a/src/js/level/index.js b/src/js/level/index.js index 17fd65b52..d56f027b7 100644 --- a/src/js/level/index.js +++ b/src/js/level/index.js @@ -477,11 +477,15 @@ var Level = Sandbox.extend({ levelSolved: function(defer) { this.solved = true; + if (!this.isShowingSolution) { - LevelActions.setLevelSolved(this.level.id); + var numCommands = this.gitCommandsIssued.length; + var best = this.getNumSolutionCommands(); + var isBest = numCommands <= best; + + LevelActions.setLevelSolved(this.level.id, isBest); log.levelSolved(this.getEnglishName()); } - this.hideGoal(); var nextLevel = LevelStore.getNextLevel(this.level.id); diff --git a/src/js/stores/LevelStore.js b/src/js/stores/LevelStore.js index a39ef74c6..91e209cae 100644 --- a/src/js/stores/LevelStore.js +++ b/src/js/stores/LevelStore.js @@ -186,11 +186,17 @@ AppConstants.StoreSubscribePrototype, }, isLevelSolved: function(levelID) { - if (!_levelMap[levelID]) { - throw new Error('that level doesn\'t exist!'); - } - return !!_solvedMap[levelID]; + var levelData = _solvedMap[levelID]; + return levelData ? levelData.solved === true : false; + }, + + + isLevelBest: function(levelID) { + var levelData = _solvedMap[levelID]; + return levelData ? levelData.best === true : false; }, + + dispatchToken: AppDispatcher.register(function(payload) { var action = payload.action; @@ -202,8 +208,8 @@ AppConstants.StoreSubscribePrototype, _syncToStorage(); shouldInform = true; break; - case ActionTypes.SET_LEVEL_SOLVED: - _solvedMap[action.levelID] = true; + case ActionTypes.SET_LEVEL_SOLVED: + _solvedMap[action.levelID] = { solved: true, best: action.best || false }; _syncToStorage(); shouldInform = true; break; diff --git a/src/js/views/levelDropdownView.js b/src/js/views/levelDropdownView.js index 7b798b0d9..820d2a154 100644 --- a/src/js/views/levelDropdownView.js +++ b/src/js/views/levelDropdownView.js @@ -402,12 +402,16 @@ var SeriesView = BaseView.extend({ updateSolvedStatus: function() { // this is a bit hacky, it really should be some nice model // property changing but it's the 11th hour... - var toLoop = this.$('a.levelIcon').each(function(index, el) { - var id = $(el).attr('data-id'); - $(el).toggleClass('solved', LevelStore.isLevelSolved(id)); + this.$('a.levelIcon').each(function() { + var $el = $(this); + var id = $el.attr('data-id'); + var isSolved = LevelStore.isLevelSolved(id); + var isBest = LevelStore.isLevelBest(id); + $el.toggleClass('solved', isSolved); + $el.toggleClass('best', isBest); }); }, - + getEventID: function(ev) { var element = ev.target; return $(element).attr('data-id'); diff --git a/src/style/main.css b/src/style/main.css index b9508fef6..b4fbaed49 100644 --- a/src/style/main.css +++ b/src/style/main.css @@ -1010,6 +1010,11 @@ a.levelIcon.solved:active { background: #5edb15; } +a.levelIcon.best { + border-color: gold; + background: gold; +} + a.levelIcon div.index { font-weight: 400; text-shadow: 1px 1px 2px #CCC, 0 2px 0 #C9C9C9;