Download src/js/views/levelDropdownView.js from merve/git-101: direct link, hf CLI and curl.
- Browser
- Download file 11.8 kB
-
https://huggingface.co/spaces/merve/git-101/resolve/main/src/js/views/levelDropdownView.js
- Command line
-
hf download hf://spaces/merve/git-101/src/js/views/levelDropdownView.js
-
curl -L -o levelDropdownView.js https://huggingface.co/spaces/merve/git-101/resolve/main/src/js/views/levelDropdownView.js
11.8 kB
| var _ = require('underscore'); | |
| var Q = require('q'); | |
| var Backbone = require('backbone'); | |
| var LocaleStore = require('../stores/LocaleStore'); | |
| var util = require('../util'); | |
| var debounce = require('../util/debounce'); | |
| var intl = require('../intl'); | |
| var log = require('../log'); | |
| var KeyboardListener = require('../util/keyboard').KeyboardListener; | |
| var Main = require('../app'); | |
| var LevelStore = require('../stores/LevelStore'); | |
| var ModalTerminal = require('../views').ModalTerminal; | |
| var ContainedBase = require('../views').ContainedBase; | |
| var BaseView = require('../views').BaseView; | |
| var LEVELS = require('../../levels'); | |
| var LevelDropdownView = ContainedBase.extend({ | |
| tagName: 'div', | |
| className: 'levelDropdownView box vertical', | |
| template: _.template($('#level-dropdown-view').html()), | |
| events: { | |
| 'click div.levelDropdownTab': 'onTabClick' | |
| }, | |
| initialize: function(options) { | |
| options = options || {}; | |
| var queryParams = util.parseQueryString( | |
| window.location.href | |
| ); | |
| this.JSON = { | |
| selectedTab: queryParams.defaultTab || 'main', | |
| tabs: [{ | |
| id: 'main', | |
| name: intl.str('main-levels-tab') | |
| }, { | |
| id: 'remote', | |
| name: intl.str('remote-levels-tab') | |
| }] | |
| }; | |
| this.navEvents = Object.assign({}, Backbone.Events); | |
| this.navEvents.on('clickedID', debounce( | |
| this.loadLevelID.bind(this), | |
| 300, | |
| true | |
| )); | |
| this.navEvents.on('negative', this.negative, this); | |
| this.navEvents.on('positive', this.positive, this); | |
| this.navEvents.on('left', this.left, this); | |
| this.navEvents.on('right', this.right, this); | |
| this.navEvents.on('up', this.up, this); | |
| this.navEvents.on('down', this.down, this); | |
| this.keyboardListener = new KeyboardListener({ | |
| events: this.navEvents, | |
| aliasMap: { | |
| esc: 'negative', | |
| enter: 'positive' | |
| }, | |
| wait: true | |
| }); | |
| this.sequences = LevelStore.getSequences(); | |
| this.sequenceToLevels = LevelStore.getSequenceToLevels(); | |
| this.container = new ModalTerminal({ | |
| title: intl.str('select-a-level') | |
| }); | |
| // Lol WTF. For some reason we cant use this.render.bind(this) so | |
| // instead setup a lame callback version. The CasperJS tests | |
| // fail otherwise. | |
| var that = this; | |
| LocaleStore.subscribe(function() { | |
| that.render.apply(that); | |
| }); | |
| LevelStore.subscribe(function() { | |
| that.render(); | |
| }); | |
| this.render(); | |
| if (!options.wait) { | |
| this.show(); | |
| } | |
| }, | |
| render: function() { | |
| this.container.updateTitle( | |
| intl.str('select-a-level') | |
| ); | |
| this.updateTabNames([ | |
| intl.str('main-levels-tab'), | |
| intl.str('remote-levels-tab') | |
| ]); | |
| LevelDropdownView.__super__.render.apply(this, arguments); | |
| this.buildSequences(); | |
| }, | |
| onTabClick: function(ev) { | |
| var srcElement = ev.target || ev.srcElement; | |
| var id = $(srcElement).attr('data-id'); | |
| if (id === this.JSON.selectedTab) { | |
| return; | |
| } | |
| this.selectedTab = id; | |
| this.updateTabTo(id); | |
| }, | |
| updateTabTo: function(id) { | |
| this.JSON.selectedTab = id; | |
| this.render(); | |
| if (this.selectedID) { | |
| this.selectedSequence = this.getSequencesOnTab()[0]; | |
| this.selectedIndex = 0; | |
| this.updateSelectedIcon(); | |
| } | |
| }, | |
| updateTabNames: function(names) { | |
| for(var index = 0; index < names.length; ++index) { | |
| this.JSON.tabs[index].name = names[index]; | |
| } | |
| }, | |
| positive: function() { | |
| if (!this.selectedID) { | |
| return; | |
| } | |
| this.loadLevelID(this.selectedID); | |
| }, | |
| left: function() { | |
| if (this.turnOnKeyboardSelection()) { | |
| return; | |
| } | |
| this.leftOrRight(-1); | |
| }, | |
| updateSelectedIcon: function() { | |
| this.selectedID = this.getSelectedID(); | |
| this.selectIconByID(this.selectedID); | |
| }, | |
| leftOrRight: function(delta) { | |
| this.deselectIconByID(this.selectedID); | |
| var index = this.selectedIndex + delta; | |
| var sequence = this.getCurrentSequence(); | |
| var tabs = this.JSON.tabs; | |
| // switch tabs now if needed / possible | |
| if (index >= sequence.length && | |
| this.getTabIndex() + 1 < tabs.length) { | |
| this.switchToTabIndex(this.getTabIndex() + 1); | |
| this.selectedIndex = 0; | |
| } else if (index < 0 && | |
| this.getTabIndex() - 1 >= 0) { | |
| this.switchToTabIndex(this.getTabIndex() - 1); | |
| this.selectedIndex = 0; | |
| } else { | |
| this.selectedIndex = this.wrapIndex( | |
| this.selectedIndex + delta, this.getCurrentSequence() | |
| ); | |
| } | |
| this.updateSelectedIcon(); | |
| }, | |
| right: function() { | |
| if (this.turnOnKeyboardSelection()) { | |
| return; | |
| } | |
| this.leftOrRight(1); | |
| }, | |
| up: function() { | |
| if (this.turnOnKeyboardSelection()) { | |
| return; | |
| } | |
| this.selectedSequence = this.getPreviousSequence(); | |
| this.downOrUp(); | |
| }, | |
| down: function() { | |
| if (this.turnOnKeyboardSelection()) { | |
| return; | |
| } | |
| this.selectedSequence = this.getNextSequence(); | |
| this.downOrUp(); | |
| }, | |
| downOrUp: function() { | |
| this.selectedIndex = this.boundIndex(this.selectedIndex, this.getCurrentSequence()); | |
| this.deselectIconByID(this.selectedID); | |
| this.updateSelectedIcon(); | |
| }, | |
| turnOnKeyboardSelection: function() { | |
| if (!this.selectedID) { | |
| this.selectFirst(); | |
| return true; | |
| } | |
| return false; | |
| }, | |
| turnOffKeyboardSelection: function() { | |
| if (!this.selectedID) { return; } | |
| this.deselectIconByID(this.selectedID); | |
| this.selectedID = undefined; | |
| this.selectedIndex = undefined; | |
| this.selectedSequence = undefined; | |
| }, | |
| getTabIndex: function() { | |
| var ids = this.JSON.tabs.map(function(tab) { | |
| return tab.id; | |
| }); | |
| return ids.indexOf(this.JSON.selectedTab); | |
| }, | |
| switchToTabIndex: function(index) { | |
| var tabID = this.JSON.tabs[index].id; | |
| this.updateTabTo(tabID); | |
| }, | |
| wrapIndex: function(index, arr) { | |
| index = (index >= arr.length) ? 0 : index; | |
| index = (index < 0) ? arr.length - 1 : index; | |
| return index; | |
| }, | |
| boundIndex: function(index, arr) { | |
| index = (index >= arr.length) ? arr.length - 1 : index; | |
| index = (index < 0) ? 0 : index; | |
| return index; | |
| }, | |
| getSequencesOnTab: function() { | |
| return this.sequences.filter(function(sequenceName) { | |
| var tab = LEVELS.getTabForSequence(sequenceName); | |
| return tab === this.JSON.selectedTab; | |
| }, this); | |
| }, | |
| getNextSequence: function() { | |
| var current = this.getSequenceIndex(this.selectedSequence); | |
| var desired = this.wrapIndex(current + 1, this.getSequencesOnTab()); | |
| return this.getSequencesOnTab()[desired]; | |
| }, | |
| getPreviousSequence: function() { | |
| var current = this.getSequenceIndex(this.selectedSequence); | |
| var desired = this.wrapIndex(current - 1, this.getSequencesOnTab()); | |
| return this.getSequencesOnTab()[desired]; | |
| }, | |
| getSequenceIndex: function(name) { | |
| var index = this.getSequencesOnTab().indexOf(name); | |
| if (index < 0) { throw new Error('didnt find'); } | |
| return index; | |
| }, | |
| getIndexForID: function(id) { | |
| return LevelStore.getLevel(id).index; | |
| }, | |
| selectFirst: function() { | |
| var firstID = this.sequenceToLevels[this.getSequencesOnTab()[0]][0].id; | |
| this.selectIconByID(firstID); | |
| this.selectedIndex = 0; | |
| this.selectedSequence = this.getSequencesOnTab()[0]; | |
| }, | |
| getCurrentSequence: function() { | |
| return this.sequenceToLevels[this.selectedSequence]; | |
| }, | |
| getSelectedID: function() { | |
| return this.sequenceToLevels[this.selectedSequence][this.selectedIndex].id; | |
| }, | |
| selectIconByID: function(id) { | |
| this.toggleIconSelect(id, true); | |
| }, | |
| deselectIconByID: function(id) { | |
| this.toggleIconSelect(id, false); | |
| }, | |
| toggleIconSelect: function(id, value) { | |
| this.selectedID = id; | |
| var selector = '#levelIcon-' + id; | |
| $(selector).toggleClass('selected', value); | |
| // also go find the series and update the about | |
| this.seriesViews.forEach(function(view) { | |
| if (view.levelIDs.indexOf(id) === -1) { | |
| return; | |
| } | |
| view.updateAboutForLevelID(id); | |
| }, this); | |
| }, | |
| negative: function() { | |
| this.hide(); | |
| }, | |
| testOption: function(str) { | |
| return this.currentCommand && new RegExp('--' + str).test(this.currentCommand.get('rawStr')); | |
| }, | |
| show: function(deferred, command) { | |
| this.currentCommand = command; | |
| // doing the update on show will allow us to fade which will be nice | |
| this.updateSolvedStatus(); | |
| this.showDeferred = deferred; | |
| this.keyboardListener.listen(); | |
| LevelDropdownView.__super__.show.apply(this); | |
| }, | |
| hide: function() { | |
| if (this.showDeferred) { | |
| this.showDeferred.resolve(); | |
| } | |
| this.showDeferred = undefined; | |
| this.keyboardListener.mute(); | |
| this.turnOffKeyboardSelection(); | |
| LevelDropdownView.__super__.hide.apply(this); | |
| }, | |
| loadLevelID: function(id) { | |
| if (!this.testOption('noOutput')) { | |
| Main.getEventBaton().trigger( | |
| 'commandSubmitted', | |
| 'level ' + id | |
| ); | |
| var level = LevelStore.getLevel(id); | |
| var name = level.name.en_US; | |
| log.levelSelected(name); | |
| } | |
| this.hide(); | |
| }, | |
| updateSolvedStatus: function() { | |
| this.seriesViews.forEach(function(view) { | |
| view.updateSolvedStatus(); | |
| }, this); | |
| }, | |
| buildSequences: function() { | |
| this.seriesViews = []; | |
| this.getSequencesOnTab().forEach(function(sequenceName) { | |
| this.seriesViews.push(new SeriesView({ | |
| destination: this.$el, | |
| name: sequenceName, | |
| navEvents: this.navEvents | |
| })); | |
| }, this); | |
| } | |
| }); | |
| var SeriesView = BaseView.extend({ | |
| tagName: 'div', | |
| className: 'seriesView box flex1 vertical', | |
| template: _.template($('#series-view').html()), | |
| events: { | |
| 'click div.levelIcon': 'click', | |
| 'mouseenter div.levelIcon': 'enterIcon' | |
| }, | |
| initialize: function(options) { | |
| this.name = options.name || 'intro'; | |
| this.navEvents = options.navEvents; | |
| this.info = LevelStore.getSequenceInfo(this.name); | |
| this.levels = LevelStore.getLevelsInSequence(this.name); | |
| this.levelIDs = []; | |
| var firstLevelInfo = null; | |
| this.levels.forEach(function(level) { | |
| if (firstLevelInfo === null) { | |
| firstLevelInfo = this.formatLevelAbout(level.id); | |
| } | |
| this.levelIDs.push(level.id); | |
| }, this); | |
| this.destination = options.destination; | |
| // use a non-breaking space to prevent the level from bouncing around | |
| // from missing strings | |
| this.JSON = { | |
| displayName: intl.getIntlKey(this.info, 'displayName'), | |
| about: intl.getIntlKey(this.info, 'about') || " ", | |
| levelInfo: firstLevelInfo, | |
| ids: this.levelIDs | |
| }; | |
| this.render(); | |
| this.updateSolvedStatus(); | |
| }, | |
| 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.$('div.levelIcon').each(function(index, el) { | |
| var id = $(el).attr('data-id'); | |
| $(el).toggleClass('solved', LevelStore.isLevelSolved(id)); | |
| }); | |
| }, | |
| getEventID: function(ev) { | |
| var element = ev.target; | |
| return $(element).attr('data-id'); | |
| }, | |
| setAbout: function(content) { | |
| this.$('p.levelInfo').text(content); | |
| }, | |
| enterIcon: function(ev) { | |
| var id = this.getEventID(ev); | |
| this.updateAboutForLevelID(id); | |
| }, | |
| updateAboutForLevelID: function(id) { | |
| this.setAbout(this.formatLevelAbout(id)); | |
| }, | |
| formatLevelAbout: function(id) { | |
| var level = LevelStore.getLevel(id); | |
| return this.getLevelNumberFromID(id) + | |
| ': ' + | |
| intl.getName(level); | |
| }, | |
| getLevelNumberFromID: function(id) { | |
| // hack -- parse out the level number from the ID | |
| return id.replace(/[^0-9]/g, ''); | |
| }, | |
| click: function(ev) { | |
| var id = this.getEventID(ev); | |
| this.navEvents.trigger('clickedID', id); | |
| } | |
| }); | |
| exports.LevelDropdownView = LevelDropdownView; | |