From 42efe6264b40dbee679f7013f78c5ebfc2556d22 Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Wed, 27 Jan 2016 13:55:17 -0800
Subject: [PATCH 1/6] Sticks the level submission data into the contact form's
 message attribute

---
 app/views/editor/level/modals/ArtisanGuideModal.coffee | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/app/views/editor/level/modals/ArtisanGuideModal.coffee b/app/views/editor/level/modals/ArtisanGuideModal.coffee
index a0887a3c4..e5fa82b53 100644
--- a/app/views/editor/level/modals/ArtisanGuideModal.coffee
+++ b/app/views/editor/level/modals/ArtisanGuideModal.coffee
@@ -32,9 +32,13 @@ module.exports = class ArtisanGuideModal extends ModalView
   levelSubmit: ->
     @playSound 'menu-button-click'
     forms.clearFormAlerts @$el
-    contactMessage = forms.formToObject @$el
-    res = tv4.validateMultiple contactMessage, contactSchema
+    results = forms.formToObject @$el
+    res = tv4.validateMultiple results, contactSchema
     return forms.applyErrorsToForm @$el, res.errors unless res.valid
+    contactMessage = {message:"""Name: #{results.creditName}
+      Purpose: #{results.levelPurpose}
+      Inspiration: #{results.levelInspiration}
+      Location: #{results.levelLocation}"""}
     @populateBrowserData contactMessage
     contactMessage = _.merge contactMessage, @options
     contactMessage.country = me.get('country')

From bd825d3108acc53cdb5427791c668983473ce0c4 Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Wed, 27 Jan 2016 14:10:32 -0800
Subject: [PATCH 2/6] Includes the level name in the email and makes it
 clickable

---
 app/views/editor/level/modals/ArtisanGuideModal.coffee | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/app/views/editor/level/modals/ArtisanGuideModal.coffee b/app/views/editor/level/modals/ArtisanGuideModal.coffee
index e5fa82b53..48d16b58d 100644
--- a/app/views/editor/level/modals/ArtisanGuideModal.coffee
+++ b/app/views/editor/level/modals/ArtisanGuideModal.coffee
@@ -25,7 +25,9 @@ module.exports = class ArtisanGuideModal extends ModalView
 
   initialize: (options) ->
     @level = options.level
-    @options = level: @level.get 'name'
+    @options = 
+      level:@level.get('name')
+      levelSlug:@level.get('slug')
     @creator = @level.get 'creator'
     @meID = me.id
 
@@ -35,7 +37,8 @@ module.exports = class ArtisanGuideModal extends ModalView
     results = forms.formToObject @$el
     res = tv4.validateMultiple results, contactSchema
     return forms.applyErrorsToForm @$el, res.errors unless res.valid
-    contactMessage = {message:"""Name: #{results.creditName}
+    contactMessage = {message:"""User Name: #{results.creditName}
+      Level: <a href="http://codecombat.com/editor/level/#{@options.levelSlug}">#{@options.level}</a>
       Purpose: #{results.levelPurpose}
       Inspiration: #{results.levelInspiration}
       Location: #{results.levelLocation}"""}

From 4a2d5c2e59795d4daed3ac96cf2ae254a41e0b22 Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Wed, 27 Jan 2016 14:47:27 -0800
Subject: [PATCH 3/6] Fixes level ownership check

---
 app/templates/editor/level/modal/artisan-guide-modal.jade | 6 +++---
 app/views/editor/level/modals/ArtisanGuideModal.coffee    | 8 ++++++--
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/app/templates/editor/level/modal/artisan-guide-modal.jade b/app/templates/editor/level/modal/artisan-guide-modal.jade
index 29c685853..6e55db911 100644
--- a/app/templates/editor/level/modal/artisan-guide-modal.jade
+++ b/app/templates/editor/level/modal/artisan-guide-modal.jade
@@ -6,7 +6,7 @@ block modal-header-content
 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
+    if view.hasOwnership()
       |, 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
@@ -17,7 +17,7 @@ block modal-body-content
       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
+  if view.hasOwnership()
     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!
@@ -38,5 +38,5 @@ block modal-body-content
 block modal-footer-content
   div
     a(href='#', data-dismiss="modal", aria-hidden="true").btn Close
-    if view.creator === view.meID
+    if view.hasOwnership()
       button.btn.btn-primary#level-submit Submit
diff --git a/app/views/editor/level/modals/ArtisanGuideModal.coffee b/app/views/editor/level/modals/ArtisanGuideModal.coffee
index 48d16b58d..9651c8df0 100644
--- a/app/views/editor/level/modals/ArtisanGuideModal.coffee
+++ b/app/views/editor/level/modals/ArtisanGuideModal.coffee
@@ -28,8 +28,6 @@ module.exports = class ArtisanGuideModal extends ModalView
     @options = 
       level:@level.get('name')
       levelSlug:@level.get('slug')
-    @creator = @level.get 'creator'
-    @meID = me.id
 
   levelSubmit: ->
     @playSound 'menu-button-click'
@@ -53,3 +51,9 @@ module.exports = class ArtisanGuideModal extends ModalView
       context.browser = "#{$.browser.platform} #{$.browser.name} #{$.browser.versionNumber}"
     context.screenSize = "#{screen?.width ? $(window).width()} x #{screen?.height ? $(window).height()}"
     context.screenshotURL = @screenshotURL
+
+  hasOwnership: ->
+    for permObj in @level.get('permissions')
+      if permObj.target is me.id and permObj.access is 'owner'
+        return true
+    return false
\ No newline at end of file

From 7b5b4ca898675d7a3387ce4b4df776e4c03662d9 Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Thu, 28 Jan 2016 13:46:55 -0800
Subject: [PATCH 4/6] Uses @$ instead of @.find,  method to convert dom into
 jQuery objects, and superior CoCoModel's getOwner() instead of trawling
 through the permissions list

---
 .../level/modals/ArtisanGuideModal.coffee     |  5 ++---
 .../editor/level/tasks/TasksTabView.coffee    | 22 +++++++++----------
 2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/app/views/editor/level/modals/ArtisanGuideModal.coffee b/app/views/editor/level/modals/ArtisanGuideModal.coffee
index 9651c8df0..58c82a59f 100644
--- a/app/views/editor/level/modals/ArtisanGuideModal.coffee
+++ b/app/views/editor/level/modals/ArtisanGuideModal.coffee
@@ -53,7 +53,6 @@ module.exports = class ArtisanGuideModal extends ModalView
     context.screenshotURL = @screenshotURL
 
   hasOwnership: ->
-    for permObj in @level.get('permissions')
-      if permObj.target is me.id and permObj.access is 'owner'
-        return true
+    if @level.getOwner() is me.id
+      return true
     return false
\ No newline at end of file
diff --git a/app/views/editor/level/tasks/TasksTabView.coffee b/app/views/editor/level/tasks/TasksTabView.coffee
index 005e19a9f..b51b8f74e 100644
--- a/app/views/editor/level/tasks/TasksTabView.coffee
+++ b/app/views/editor/level/tasks/TasksTabView.coffee
@@ -98,7 +98,7 @@ module.exports = class TasksTabView extends CocoView
       @render()
 
   focusEditInput: ->
-    editInput = @$el.find('#cur-edit')[0]
+    editInput = @$('#cur-edit')[0]
     if editInput
       editInput.focus()
       len = editInput.value.length * 2
@@ -138,9 +138,9 @@ module.exports = class TasksTabView extends CocoView
     @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 not $(e.target).is('input') and not $(e.target).is('a') and not $(e.target).hasClass('start-edit') and @$('#cur-edit').length is 0
+      task = @tasks.get $(e.target).closest('tr').data('task-cid')
+      checkbox = $(e.currentTarget).find('.task-input')[0]
       if task.get 'complete'
         task.set 'complete', false
       else
@@ -149,29 +149,29 @@ module.exports = class TasksTabView extends CocoView
       @pushTasks()
 
   onClickTaskInput: (e) ->
-    task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
+    task = @tasks.get $(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')
+    if @$('#cur-edit').length is 0
+      task = @tasks.get $(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 = @$('#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')
+    editInput = @$('#cur-edit')[0]
+    task = @tasks.get $(e.target).closest('tr').data('task-cid')
     @applyTaskName(task, editInput)
 
   onClickCreateTask: (e) ->
-    if @$el.find('#cur-edit').length is 0
+    if @$('#cur-edit').length is 0
       @tasks.add
         name: ''
         complete: false

From 0eb32aac24233bbebac72249bdaa6230dd15450e Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Wed, 3 Feb 2016 10:26:36 -0800
Subject: [PATCH 5/6] Creates clickable links for default tasks

---
 app/templates/editor/level/tasks-tab.jade     | 10 ++---
 .../editor/level/tasks/TasksTabView.coffee    | 44 +++----------------
 2 files changed, 10 insertions(+), 44 deletions(-)

diff --git a/app/templates/editor/level/tasks-tab.jade b/app/templates/editor/level/tasks-tab.jade
index 8902434a3..247653b4d 100644
--- a/app/templates/editor/level/tasks-tab.jade
+++ b/app/templates/editor/level/tasks-tab.jade
@@ -2,7 +2,6 @@ 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
@@ -15,11 +14,10 @@ mixin task-row(cid)
       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
+        - var result = view.getTaskURL(taskName)
+        if result !== null
+          // https://github.com/codecombat/codecombat/wiki/Tasks-Tab#<slug goes here>
+          a(href='https://github.com/codecombat/codecombat/wiki/Tasks-Tab#' + result, target='blank')= taskName
         else
           span= taskName
 
diff --git a/app/views/editor/level/tasks/TasksTabView.coffee b/app/views/editor/level/tasks/TasksTabView.coffee
index b51b8f74e..c4218232e 100644
--- a/app/views/editor/level/tasks/TasksTabView.coffee
+++ b/app/views/editor/level/tasks/TasksTabView.coffee
@@ -18,44 +18,6 @@ module.exports = class TasksTabView extends CocoView
   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
@@ -115,6 +77,7 @@ module.exports = class TasksTabView extends CocoView
 
   onLevelLoaded: (e) ->
     @level = e.level
+    @defaultTasks = @level.schema().properties.tasks.default
     Task = Backbone.Model.extend({
       initialize: ->
         # We want to keep track of the revertAttributes easily without digging back into the level every time.
@@ -181,3 +144,8 @@ module.exports = class TasksTabView extends CocoView
           complete: false
       @render()
       @focusEditInput()
+
+  getTaskURL: (_n) ->
+    if _.find(@defaultTasks, {name:_n})?
+      return _.string.slugify(_n)
+    return null

From 99955aa034c9c01b28f7b136c5c60968e7fc346c Mon Sep 17 00:00:00 2001
From: Josh Callebaut <josh.callebaut@gmail.com>
Date: Tue, 9 Feb 2016 09:37:09 -0800
Subject: [PATCH 6/6] Corrects artisan guide modal subdomain

---
 app/templates/editor/level/modal/artisan-guide-modal.jade | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/templates/editor/level/modal/artisan-guide-modal.jade b/app/templates/editor/level/modal/artisan-guide-modal.jade
index 6e55db911..cb6758712 100644
--- a/app/templates/editor/level/modal/artisan-guide-modal.jade
+++ b/app/templates/editor/level/modal/artisan-guide-modal.jade
@@ -16,7 +16,7 @@ block modal-body-content
     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
+      a(href='http://www.codecombat.com/community', target='_blank') Artisan Rankings
   if view.hasOwnership()
     h4 Level Submission
     p