mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-01 07:40:22 -04:00
Merge pull request #3369 from Zerrien/master
Editor Changes (Task tab, pre-initialize tasks, Artisan nurturing, level submission)
This commit is contained in:
commit
14ef28b658
15 changed files with 375 additions and 6 deletions
app
schemas/models
styles
templates
editor
play
views/editor
|
@ -118,6 +118,9 @@ _.extend CampaignSchema.properties, {
|
|||
campaign: c.shortString title: 'Campaign', description: 'Which campaign this level is part of (like "desert").', format: 'hidden' # Automatically set by campaign editor.
|
||||
campaignIndex: c.int title: 'Campaign Index', description: 'The 0-based index of this level in its campaign.', format: 'hidden' # Automatically set by campaign editor.
|
||||
|
||||
scoreTypes: c.array {title: 'Score Types', description: 'What metric to show leaderboards for.', uniqueItems: true},
|
||||
c.shortString(title: 'Score Type', 'enum': ['time', 'damage-taken', 'damage-dealt', 'gold-collected', 'difficulty']) # TODO: good version of LoC; total gear value.
|
||||
|
||||
tasks: c.array {title: 'Tasks', description: 'Tasks to be completed for this level.'}, c.task
|
||||
concepts: c.array {title: 'Programming Concepts', description: 'Which programming concepts this level covers.'}, c.concept
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ LevelSchema = c.object {
|
|||
'default':
|
||||
name: 'Ineffable Wizardry'
|
||||
description: 'This level is indescribably flarmy.'
|
||||
tasks: (name: t, complete: false for t in defaultTasks)
|
||||
documentation: {}
|
||||
scripts: []
|
||||
thangs: []
|
||||
|
|
3
app/styles/editor/level/modal/artisan-guide-modal.sass
Normal file
3
app/styles/editor/level/modal/artisan-guide-modal.sass
Normal file
|
@ -0,0 +1,3 @@
|
|||
#artisan-guide-modal
|
||||
.centered-stack
|
||||
text-align: center
|
19
app/styles/editor/level/tasks-tab.sass
Normal file
19
app/styles/editor/level/tasks-tab.sass
Normal file
|
@ -0,0 +1,19 @@
|
|||
#editor-level-tasks-tab-view
|
||||
td
|
||||
cursor: pointer
|
||||
.task-check
|
||||
width: 5em
|
||||
.task-check, .task-check *
|
||||
margin: auto
|
||||
text-align: center
|
||||
.edit-cell
|
||||
width: 5em
|
||||
.edit-cell, .edit-cell *
|
||||
margin: auto
|
||||
text-align: center
|
||||
.task-name
|
||||
margin: auto
|
||||
.start-edit
|
||||
cursor: pointer
|
||||
.no-article
|
||||
color: rgba(160, 0, 0, 1)
|
|
@ -280,7 +280,7 @@ $gameControlMargin: 30px
|
|||
opacity: 1
|
||||
padding: 3px 9px
|
||||
|
||||
&.complete
|
||||
&.shows-leaderboard
|
||||
.start-level, .view-solutions
|
||||
min-width: calc(50% - 5px)
|
||||
display: inline-block
|
||||
|
|
|
@ -27,6 +27,8 @@ block header
|
|||
a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components")#components-tab Components
|
||||
li
|
||||
a(href="#systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems
|
||||
li
|
||||
a(href="#editor-level-tasks-tab-view", data-toggle="tab", data-i18n="editor.level_tab_tasks")#tasks-tab= "Tasks" + " " + view.getTaskCompletionRatio()
|
||||
li
|
||||
a(href="#editor-level-patches", data-toggle="tab")#patches-tab
|
||||
span(data-i18n="resources.patches").spr Patches
|
||||
|
@ -50,6 +52,9 @@ block header
|
|||
li#redo-button
|
||||
a
|
||||
span.glyphicon-arrow-right.glyphicon
|
||||
li#artisan-guide-button
|
||||
a
|
||||
span.glyphicon-book.glyphicon
|
||||
if authorized
|
||||
li#commit-level-start-button
|
||||
a
|
||||
|
@ -58,7 +63,7 @@ block header
|
|||
li#level-patch-button
|
||||
a
|
||||
span.glyphicon-floppy-disk.glyphicon
|
||||
|
||||
|
||||
if level.get('type') === 'ladder'
|
||||
li.dropdown
|
||||
a(data-toggle='dropdown').play-with-team-parent
|
||||
|
@ -124,6 +129,8 @@ block outer_content
|
|||
div.tab-pane#editor-level-components-tab-view
|
||||
|
||||
div.tab-pane#systems-tab-view
|
||||
|
||||
div.tab-pane#editor-level-tasks-tab-view
|
||||
|
||||
div.tab-pane#editor-level-patches
|
||||
.patches-view
|
||||
|
|
42
app/templates/editor/level/modal/artisan-guide-modal.jade
Normal file
42
app/templates/editor/level/modal/artisan-guide-modal.jade
Normal file
|
@ -0,0 +1,42 @@
|
|||
extends /templates/core/modal-base
|
||||
|
||||
block modal-header-content
|
||||
h3 Artisan Compendium
|
||||
|
||||
block modal-body-content
|
||||
p
|
||||
| Welcome to the Artisan Compendium. Below you will find a series of helpful guides and tutorials for getting your levels to Master Artisan quality
|
||||
if view.creator === view.meID
|
||||
|, as well as a way to submit your level for official Artisan review
|
||||
|! If you have any feedback on the Level Editor, please contact us at:
|
||||
a(href='mailto:artisans@codecombat.com') artisans@codecombat.com
|
||||
div.centered-stack
|
||||
div
|
||||
a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', target='_blank') Wiki Homepage
|
||||
div
|
||||
a(href='https://github.com/codecombat/codecombat/wiki/Artisan-How-To-Index', target='_blank') Basic How-tos
|
||||
div
|
||||
a(href='http://direct.codecombat.com/community', target='_blank') Artisan Rankings
|
||||
if view.creator === view.meID
|
||||
h4 Level Submission
|
||||
p
|
||||
| Do you want your level to be added to the campaign? Please take a moment to fill out the questions below! Don’t worry, this isn’t a timed quiz. It is just a way for the artisans at CodeCombat HQ to get a feel for the purpose of this level. If it doesn’t quite yet meet our standards for release we will give you feedback to help polish it further!
|
||||
.form
|
||||
.form-group
|
||||
label.control-label(for='credit-name') How would you like to be credited?
|
||||
input#credit-name.form-control(name='creditName')
|
||||
.form-group
|
||||
label.control-label(for='level-purpose') What is the purpose of this level?
|
||||
textarea#level-purpose.form-control(name='levelPurpose', rows=4)
|
||||
.form-group
|
||||
label.control-label(for='level-inspiration') What was the inspiration for the level?
|
||||
textarea#level-inspiration.form-control(name='levelInspiration', rows=4)
|
||||
.form-group
|
||||
label.control-label(for='level-location') Where in the campaign do you think this level belongs?
|
||||
textarea#level-location.form-control(name='levelLocation', rows=4)
|
||||
|
||||
block modal-footer-content
|
||||
div
|
||||
a(href='#', data-dismiss="modal", aria-hidden="true").btn Close
|
||||
if view.creator === view.meID
|
||||
button.btn.btn-primary#level-submit Submit
|
44
app/templates/editor/level/tasks-tab.jade
Normal file
44
app/templates/editor/level/tasks-tab.jade
Normal file
|
@ -0,0 +1,44 @@
|
|||
mixin task-row(cid)
|
||||
- var task = view.getTaskByCID(cid)
|
||||
- var taskName = task.get('name');
|
||||
- var isComplete = task.get('complete')
|
||||
- var taskLink = view.defaultTaskLinks[taskName]
|
||||
tr.task-row(data-task-cid=cid)
|
||||
td.task-check
|
||||
div.checkbox
|
||||
input(type='checkbox', checked=(isComplete || false)).task-input
|
||||
if task.get('curEdit') == true
|
||||
td.edit-cell
|
||||
td.task-name
|
||||
input(type="input", value=taskName)#cur-edit
|
||||
else
|
||||
td.edit-cell
|
||||
span.glyphicon.glyphicon-edit.start-edit
|
||||
td.task-name
|
||||
if taskLink
|
||||
if taskLink === './'
|
||||
a.no-article(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', target='blank')= taskName
|
||||
else
|
||||
a(href=taskLink, target='_blank')= taskName
|
||||
else
|
||||
span= taskName
|
||||
|
||||
block
|
||||
table.table.table-striped.table-hover
|
||||
tr
|
||||
th.task-check Complete
|
||||
th.edit-cell Edit
|
||||
th Incomplete Tasks
|
||||
for task in (view.taskArray() || [])
|
||||
if task.get('revert').complete !== true
|
||||
+task-row(task.cid)
|
||||
tr
|
||||
th.task-check
|
||||
th.edit-cell
|
||||
th Completed Tasks
|
||||
for task in (view.taskArray() || [])
|
||||
if task.get('revert').complete === true
|
||||
+task-row(task.cid)
|
||||
button#create-task.btn.btn-primary Add Task
|
||||
if view.missingDefaults().length !== 0
|
||||
button#add-default-tasks.btn.btn-default Add Default Tasks
|
|
@ -26,4 +26,4 @@ mixin thangRow(thang)
|
|||
for task in (thang.tasks || [])
|
||||
if !task.complete
|
||||
tr
|
||||
td= task.name
|
||||
td= task.name
|
||||
|
|
|
@ -30,7 +30,9 @@ if campaign
|
|||
- var playCount = levelPlayCountMap[level.slug]
|
||||
.progress.progress-striped.active.hide
|
||||
.progress-bar(style="width: 100%")
|
||||
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : ""))
|
||||
- var showsLeaderboard = levelStatusMap[level.slug] === 'complete' && ((level.scoreTypes && level.scoreTypes.length) || ['hero-ladder', 'course-ladder'].indexOf(level.type) !== -1);
|
||||
|
||||
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : "") + (showsLeaderboard ? " shows-leaderboard" : ""))
|
||||
.level-status
|
||||
h3= i18n(level, 'name') + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
|
||||
- var description = i18n(level, 'description') || level.description || ""
|
||||
|
@ -53,7 +55,7 @@ if campaign
|
|||
span(data-i18n="play.players") players
|
||||
span.spr , #{Math.round(playCount.playtime / 3600)}
|
||||
span(data-i18n="play.hours_played") hours played
|
||||
if levelStatusMap[level.slug] === 'complete'
|
||||
if showsLeaderboard
|
||||
button.btn.btn-warning.btn.btn-lg.btn-illustrated.view-solutions(data-level-slug=level.slug)
|
||||
span(data-i18n="leaderboard.scores")
|
||||
button.btn.btn-success.btn.btn-lg.btn-illustrated.start-level(data-i18n="common.play") Play
|
||||
|
|
|
@ -15,7 +15,9 @@ SettingsTabView = require './settings/SettingsTabView'
|
|||
ScriptsTabView = require './scripts/ScriptsTabView'
|
||||
ComponentsTabView = require './components/ComponentsTabView'
|
||||
SystemsTabView = require './systems/SystemsTabView'
|
||||
TasksTabView = require './tasks/TasksTabView'
|
||||
SaveLevelModal = require './modals/SaveLevelModal'
|
||||
ArtisanGuideModal = require './modals/ArtisanGuideModal'
|
||||
ForkModal = require 'views/editor/ForkModal'
|
||||
SaveVersionModal = require 'views/editor/modal/SaveVersionModal'
|
||||
PatchesView = require 'views/editor/PatchesView'
|
||||
|
@ -56,6 +58,7 @@ module.exports = class LevelEditView extends RootView
|
|||
'mouseenter #redo-button': 'showRedoDescription'
|
||||
'click #patches-tab': -> @patchesView.load()
|
||||
'click #components-tab': -> @subviews.editor_level_components_tab_view.refreshLevelThangsTreema @level.get('thangs')
|
||||
'click #artisan-guide-button': 'showArtisanGuide'
|
||||
'click #level-patch-button': 'startPatchingLevel'
|
||||
'click #level-watch-button': 'toggleWatchLevel'
|
||||
'click li:not(.disabled) > #pop-level-i18n-button': 'onPopulateI18N'
|
||||
|
@ -105,10 +108,12 @@ module.exports = class LevelEditView extends RootView
|
|||
@insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files
|
||||
@insertSubView new ComponentsTabView supermodel: @supermodel
|
||||
@insertSubView new SystemsTabView supermodel: @supermodel, world: @world
|
||||
@insertSubView new TasksTabView world: @world, supermodel: @supermodel, level: @level
|
||||
@insertSubView new RelatedAchievementsView supermodel: @supermodel, level: @level
|
||||
@insertSubView new ComponentsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it!
|
||||
@insertSubView new SystemsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it!
|
||||
@insertSubView new LevelFeedbackView level: @level
|
||||
|
||||
|
||||
Backbone.Mediator.publish 'editor:level-loaded', level: @level
|
||||
@showReadOnly() if me.get('anonymous')
|
||||
|
@ -170,6 +175,10 @@ module.exports = class LevelEditView extends RootView
|
|||
@openModalView new SaveLevelModal level: @level, supermodel: @supermodel, buildTime: @levelBuildTime
|
||||
Backbone.Mediator.publish 'editor:view-switched', {}
|
||||
|
||||
showArtisanGuide: (e) ->
|
||||
@openModalView new ArtisanGuideModal level: @level
|
||||
Backbone.Mediator.publish 'editor:view-switched', {}
|
||||
|
||||
startForking: (e) ->
|
||||
@openModalView new ForkModal model: @level, editorPath: 'level'
|
||||
Backbone.Mediator.publish 'editor:view-switched', {}
|
||||
|
@ -210,3 +219,9 @@ module.exports = class LevelEditView extends RootView
|
|||
return if application.userIsIdle
|
||||
@levelBuildTime ?= @level.get('buildTime') ? 0
|
||||
++@levelBuildTime
|
||||
|
||||
getTaskCompletionRatio: ->
|
||||
if not @level.get('tasks')?
|
||||
return '0/0'
|
||||
else
|
||||
return _.filter(@level.get('tasks'), (_elem) -> return _elem.complete).length + '/' + @level.get('tasks').length
|
||||
|
|
48
app/views/editor/level/modals/ArtisanGuideModal.coffee
Normal file
48
app/views/editor/level/modals/ArtisanGuideModal.coffee
Normal file
|
@ -0,0 +1,48 @@
|
|||
ModalView = require 'views/core/ModalView'
|
||||
template = require 'templates/editor/level/modal/artisan-guide-modal'
|
||||
|
||||
forms = require 'core/forms'
|
||||
{sendContactMessage} = require 'core/contact'
|
||||
|
||||
contactSchema =
|
||||
additionalProperties: false
|
||||
required: ['creditName', 'levelPurpose', 'levelInspiration', 'levelLocation']
|
||||
properties:
|
||||
creditName:
|
||||
type: 'string'
|
||||
levelPurpose:
|
||||
type: 'string'
|
||||
levelInspiration:
|
||||
type: 'string'
|
||||
levelLocation:
|
||||
type: 'string'
|
||||
|
||||
module.exports = class ArtisanGuideModal extends ModalView
|
||||
id: 'artisan-guide-modal'
|
||||
template: template
|
||||
events:
|
||||
'click #level-submit': 'levelSubmit'
|
||||
|
||||
initialize: (options) ->
|
||||
@level = options.level
|
||||
@options = level: @level.get 'name'
|
||||
@creator = @level.get 'creator'
|
||||
@meID = me.id
|
||||
|
||||
levelSubmit: ->
|
||||
@playSound 'menu-button-click'
|
||||
forms.clearFormAlerts @$el
|
||||
contactMessage = forms.formToObject @$el
|
||||
res = tv4.validateMultiple contactMessage, contactSchema
|
||||
return forms.applyErrorsToForm @$el, res.errors unless res.valid
|
||||
@populateBrowserData contactMessage
|
||||
contactMessage = _.merge contactMessage, @options
|
||||
contactMessage.country = me.get('country')
|
||||
sendContactMessage contactMessage, @$el
|
||||
$.post "/db/user/#{me.id}/track/contact_codecombat"
|
||||
|
||||
populateBrowserData: (context) ->
|
||||
if $.browser
|
||||
context.browser = "#{$.browser.platform} #{$.browser.name} #{$.browser.versionNumber}"
|
||||
context.screenSize = "#{screen?.width ? $(window).width()} x #{screen?.height ? $(window).height()}"
|
||||
context.screenshotURL = @screenshotURL
|
|
@ -15,7 +15,7 @@ module.exports = class SettingsTabView extends CocoView
|
|||
editableSettings: [
|
||||
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
|
||||
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
|
||||
'tasks', 'helpVideos', 'replayable', 'scoreTypes', 'concepts'
|
||||
'helpVideos', 'replayable', 'scoreTypes', 'concepts'
|
||||
]
|
||||
|
||||
subscriptions:
|
||||
|
|
183
app/views/editor/level/tasks/TasksTabView.coffee
Normal file
183
app/views/editor/level/tasks/TasksTabView.coffee
Normal file
|
@ -0,0 +1,183 @@
|
|||
CocoView = require 'views/core/CocoView'
|
||||
template = require 'templates/editor/level/tasks-tab'
|
||||
Level = require 'models/Level'
|
||||
|
||||
module.exports = class TasksTabView extends CocoView
|
||||
id: 'editor-level-tasks-tab-view'
|
||||
className: 'tab-pane'
|
||||
template: template
|
||||
events:
|
||||
'click .task-row': 'onClickTaskRow'
|
||||
'click .task-input': 'onClickTaskInput'
|
||||
'click .start-edit': 'onClickStartEdit'
|
||||
'click #create-task': 'onClickCreateTask'
|
||||
'keydown #cur-edit': 'onKeyDownCurEdit'
|
||||
'blur #cur-edit': 'onBlurCurEdit'
|
||||
'click #add-default-tasks': 'onClickAddDefaultTasks'
|
||||
|
||||
subscriptions:
|
||||
'editor:level-loaded': 'onLevelLoaded'
|
||||
|
||||
defaultTaskLinks:
|
||||
# Order doesn't matter.
|
||||
'Name the level.':'./'
|
||||
'Create a Referee stub, if needed.':'./'
|
||||
'Build the level.':'./'
|
||||
'Set up goals.':'./'
|
||||
'Choose the Existence System lifespan and frame rate.':'./'
|
||||
'Choose the UI System paths and coordinate hover if needed.':'./'
|
||||
'Choose the AI System pathfinding and Vision System line of sight.':'./'
|
||||
'Write the sample code.':'./'
|
||||
'Do basic set decoration.':'./'
|
||||
'Adjust script camera bounds.':'./'
|
||||
'Choose music file in Introduction script.':'./'
|
||||
'Choose autoplay in Introduction script.':'./'
|
||||
'Add to a campaign.':'./'
|
||||
'Publish.':'./'
|
||||
'Choose level options like required/restricted gear.':'./'
|
||||
'Create achievements, including unlocking next level.':'./'
|
||||
'Choose leaderboard score types.':'./'
|
||||
'Playtest with a slow/tough hero.':'./'
|
||||
'Playtest with a fast/weak hero.':'./'
|
||||
'Playtest with a couple random seeds.':'./'
|
||||
'Make sure the level ends promptly on success and failure.':'./'
|
||||
'Remove/simplify unnecessary doodad collision.':'./'
|
||||
'Release to adventurers via MailChimp.':'./'
|
||||
'Write the description.':'./'
|
||||
'Add i18n field for the sample code comments.':'./'
|
||||
'Add Clojure/Lua/CoffeeScript.':'./'
|
||||
'Write the guide.':'./'
|
||||
'Write a loading tip, if needed.':'./'
|
||||
'Click the Populate i18n button.':'./'
|
||||
'Add programming concepts covered.':'./'
|
||||
'Mark whether it requires a subscription.':'./'
|
||||
'Release to everyone via MailChimp.':'./'
|
||||
'Check completion/engagement/problem analytics.':'./'
|
||||
'Do thorough set decoration.':'./'
|
||||
'Add a walkthrough video.':'./'
|
||||
|
||||
missingDefaults: ->
|
||||
missingTasks = []
|
||||
if @level
|
||||
for task in @level.schema().properties.tasks.default
|
||||
unless _.findIndex(@level.get('tasks'), {name: task.name}) isnt -1
|
||||
missingTasks.push task
|
||||
return missingTasks
|
||||
|
||||
onClickAddDefaultTasks: ->
|
||||
results = @missingDefaults()
|
||||
for result in results
|
||||
@tasks.add
|
||||
name: result.name
|
||||
complete: result.complete
|
||||
curEdit: false
|
||||
revert:
|
||||
name: result.name
|
||||
complete: false
|
||||
@pushTasks()
|
||||
@render()
|
||||
|
||||
applyTaskName: (_task, _input) ->
|
||||
name = _input.value
|
||||
potentialTask = @tasks.findWhere({'name':_input})
|
||||
if potentialTask and potentialTask isnt _task
|
||||
noty
|
||||
timeout: 5000
|
||||
text: 'Task with name already exists!'
|
||||
type: 'error'
|
||||
layout: 'topCenter'
|
||||
_input.focus()
|
||||
else if name is ''
|
||||
@tasks.remove _task
|
||||
@pushTasks()
|
||||
@render()
|
||||
else
|
||||
_task.set 'name', name
|
||||
_task.set 'curEdit', false
|
||||
@pushTasks()
|
||||
@render()
|
||||
|
||||
focusEditInput: ->
|
||||
editInput = @$el.find('#cur-edit')[0]
|
||||
if editInput
|
||||
editInput.focus()
|
||||
len = editInput.value.length * 2
|
||||
editInput.setSelectionRange len, len
|
||||
|
||||
getTaskByCID: (_cid) ->
|
||||
return @tasks.get _cid
|
||||
|
||||
taskMap: ->
|
||||
return @tasks?.map((_obj) -> return (name: _obj.get('name'), complete: (_obj.get('complete') || false)))
|
||||
|
||||
taskArray: ->
|
||||
return @tasks?.toArray()
|
||||
|
||||
onLevelLoaded: (e) ->
|
||||
@level = e.level
|
||||
Task = Backbone.Model.extend({
|
||||
initialize: ->
|
||||
# We want to keep track of the revertAttributes easily without digging back into the level every time.
|
||||
# So per TaskModel we check to see if there is a revertAttribute associated with the task's name.
|
||||
# If there is a reversion available, we use it, otherwise (e.g. new tasks without a reversion) we just use the Task's current name/completion status.
|
||||
if e?.level?._revertAttributes?.tasks?
|
||||
if _.find(e.level._revertAttributes.tasks, {name:arguments[0].name})
|
||||
@set 'revert', _.find(e.level._revertAttributes.tasks, {name:arguments[0].name})
|
||||
else
|
||||
@set 'revert', arguments[0]
|
||||
else
|
||||
@set 'revert', arguments[0]
|
||||
})
|
||||
TaskList = Backbone.Collection.extend({
|
||||
model: Task
|
||||
})
|
||||
@tasks = new TaskList(@level.get 'tasks')
|
||||
@render()
|
||||
|
||||
pushTasks: ->
|
||||
@level.set 'tasks', @taskMap()
|
||||
|
||||
onClickTaskRow: (e) ->
|
||||
if not @$el.find(e.target).is('input') and not @$el.find(e.target).is('a') and not @$el.find(e.target).hasClass('start-edit') and @$el.find('#cur-edit').length is 0
|
||||
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
|
||||
checkbox = @$el.find(e.currentTarget).find('.task-input')[0]
|
||||
if task.get 'complete'
|
||||
task.set 'complete', false
|
||||
else
|
||||
task.set 'complete', true
|
||||
checkbox.checked = task.get 'complete'
|
||||
@pushTasks()
|
||||
|
||||
onClickTaskInput: (e) ->
|
||||
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
|
||||
task.set 'complete', e.currentTarget.checked
|
||||
@pushTasks()
|
||||
|
||||
onClickStartEdit: (e) ->
|
||||
if @$el.find('#cur-edit').length is 0
|
||||
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
|
||||
task.set 'curEdit', true
|
||||
@render()
|
||||
@focusEditInput()
|
||||
|
||||
onKeyDownCurEdit: (e) ->
|
||||
if e.keyCode is 13
|
||||
editInput = @$el.find('#cur-edit')[0]
|
||||
editInput.blur()
|
||||
|
||||
onBlurCurEdit: (e) ->
|
||||
editInput = @$el.find('#cur-edit')[0]
|
||||
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
|
||||
@applyTaskName(task, editInput)
|
||||
|
||||
onClickCreateTask: (e) ->
|
||||
if @$el.find('#cur-edit').length is 0
|
||||
@tasks.add
|
||||
name: ''
|
||||
complete: false
|
||||
curEdit: true
|
||||
revert:
|
||||
name: 'null'
|
||||
complete: false
|
||||
@render()
|
||||
@focusEditInput()
|
|
@ -22,6 +22,8 @@ module.exports = class NewModelModal extends ModalView
|
|||
model = new @modelClass
|
||||
name = @$el.find('#name').val()
|
||||
model.set('name', name)
|
||||
if @modelClass.name is 'Level'
|
||||
model.set('tasks', @modelClass.schema.default.tasks)
|
||||
if model.schema().properties.permissions
|
||||
model.set 'permissions', [{access: 'owner', target: me.id}]
|
||||
model.set(key, prop) for key, prop of @properties if @properties?
|
||||
|
|
Loading…
Add table
Reference in a new issue