{"action":"created","comment":{"url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/comments/54248976","id":54248976,"diff_hunk":"@@ -0,0 +1,181 @@\n+//= require templates/course/assessment/submission/answer/programming/add_annotation_button\n+//= require templates/course/assessment/submission/answer/programming/annotation_form\n+\n+(function($) {\n+  /* global JST */\n+  'use strict';\n+  var DOCUMENT_SELECTOR = '.course-assessment-submission-submissions.edit ';\n+\n+  /**\n+   * Renders a programming submission template.\n+   *\n+   * @param {String} template The relative path to the template. Absolute paths or paths\n+   *   beginning with a period are not expanded.\n+   * @param {Object} locals The local variables to be given to the template.\n+   * @return {String} The rendered template.\n+   */\n+  function render(template, locals) {\n+    if (template[0] !== '/' && template[0] !== '.') {\n+      template = 'templates/course/assessment/submission/answer/programming/' + template;\n+    }\n+\n+    return JST[template](locals);\n+  }\n+\n+  /**\n+   * Adds the programming annotation links to every line of code.\n+   *\n+   * @param {HTMLElement} element The table containing the code, tabulated by lines. This is the\n+   *   output of the Ruby `format_code_block` helper.\n+   */\n+  function addProgrammingAnnotationLinks(element) {\n+    var $lineNumbers = $(DOCUMENT_SELECTOR + 'table.codehilite td', element).\n+      not('.line-number').\n+      not(function() {\n+        return $(this).find('.add-annotation').length > 0;\n+      });\n+\n+    $lineNumbers.prepend(render('add_annotation_button'));\n+  }\n+\n+  /**\n+   * Handles the click event when the add annotation button is clicked.\n+   *\n+   * @param {Event} e The event object.\n+   */\n+  function onAddProgrammingAnnotation(e) {\n+    var $target = $(e.target);\n+    var $answer = $target.parents('.answer:first');\n+    var $programmingFile = $target.parents('.answer_programming_file');\n+    var $line = $target.parents('tr:first');\n+\n+    var answerId = $answer.data('answerId');\n+    var programmingFileId = $programmingFile.data('programmingFileId');\n+    var lineNumber = $line.find('.line-number').data('lineNumber');\n+\n+    createAnnotationBox($line[0], answerId, programmingFileId, lineNumber);\n+  }\n+\n+  /**\n+   * Creates a annotation box for the user to enter his annotation.\n+   *\n+   * @param {HTMLTableRowElement} line The containing the line number and code. This directs the\n+   *   placement of the annotation form.\n+   * @param {Number} answerId The answer ID that the annotation is associated with.\n+   * @param {Number} programmingFileId The programming answer file ID that the annotation is\n+   *   associated with.\n+   * @param {Number} lineNumber The line number that the user is annotating.\n+   */\n+  function createAnnotationBox(line, answerId, programmingFileId, lineNumber) {\n+    var $line = $(line);\n+    $line.after(render('annotation_form', {\n+      answerId: answerId,\n+      programmingFileId: programmingFileId,\n+      lineNumber: lineNumber\n+    }));\n+  }\n+\n+  /**\n+   * Handles the reset of the annotation form.\n+   *\n+   * @param e The event object.\n+   */\n+  function onAnnotationFormResetted(e) {\n+    var $button = $(e.target);\n+    var $form = $button.parents('div[data-action]:first');\n+\n+    $form.remove();\n+  }\n+\n+  /**\n+   * Blocks the submission of the submission form if we click on a submit button within the\n+   * annotation form.\n+   *\n+   * @param e The event object.\n+   */\n+  function onAnnotationFormSubmitted(e) {\n+    var $button = $(e.target);\n+    var $form = $button.parents('div[data-action]:first');\n+    var action = $form.data('action');\n+    var method = $form.data('method');\n+\n+    $.ajax({ url: action, method: method, data: buildFormData($form) }).\n+      done(function(data) { onAnnotationFormSubmitSuccess(data, $form[0]); }).\n+      fail(function(data) { onAnnotationFormSubmitFail(data, $form[0]); });\n+\n+    findFormFields($form).prop('disabled', true);\n+    e.preventDefault();\n+  }\n+\n+  /**\n+   * Finds the form fields in the given form.\n+   *\n+   * @param {jQuery} $form The form to search.\n+   * @param {String|undefined} selector The filter to apply on the returned fields.\n+   *\n+   * @returns {jQuery} The set of fields matching the filter.\n+   */\n+  function findFormFields($form, selector) {\n+    var $result = $form.find('textarea, input');\n+    if (selector) {\n+      $result = $result.filter(selector);\n+    }\n+\n+    return $result;\n+  }\n+\n+  /**\n+   * Builds the form data from the given form.\n+   *\n+   * This is a less sophisticated version of $.serialize() in that it only supports inputs and\n+   * textareas.\n+   *\n+   * @param {jQuery} $form The form being submitted.\n+   * @returns {Object} The form data to be submitted.\n+   */\n+  function buildFormData($form) {\n+    var $fields = findFormFields($form, ':not(:disabled)');\n+    var data = {\n+      authenticity_token: $(document).find('meta[name=\"csrf-token\"]').attr('content')","path":"app/assets/javascripts/course/assessment/submission/answer/programming.js","position":139,"original_position":139,"commit_id":"5f3459df55cd2fe575c5661f11d90b964a6b6166","original_commit_id":"5f3459df55cd2fe575c5661f11d90b964a6b6166","user":{"login":"houndci-bot","id":6697940,"avatar_url":"https://avatars.githubusercontent.com/u/6697940?v=3","gravatar_id":"","url":"https://api.github.com/users/houndci-bot","html_url":"https://github.com/houndci-bot","followers_url":"https://api.github.com/users/houndci-bot/followers","following_url":"https://api.github.com/users/houndci-bot/following{/other_user}","gists_url":"https://api.github.com/users/houndci-bot/gists{/gist_id}","starred_url":"https://api.github.com/users/houndci-bot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/houndci-bot/subscriptions","organizations_url":"https://api.github.com/users/houndci-bot/orgs","repos_url":"https://api.github.com/users/houndci-bot/repos","events_url":"https://api.github.com/users/houndci-bot/events{/privacy}","received_events_url":"https://api.github.com/users/houndci-bot/received_events","type":"User","site_admin":false},"body":"Identifier 'authenticity_token' is not in camel case.","created_at":"2016-02-26T14:26:56Z","updated_at":"2016-02-26T14:26:56Z","html_url":"https://github.com/Coursemology/coursemology2/pull/857#discussion_r54248976","pull_request_url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857","_links":{"self":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/comments/54248976"},"html":{"href":"https://github.com/Coursemology/coursemology2/pull/857#discussion_r54248976"},"pull_request":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857"}}},"pull_request":{"url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857","id":60848720,"html_url":"https://github.com/Coursemology/coursemology2/pull/857","diff_url":"https://github.com/Coursemology/coursemology2/pull/857.diff","patch_url":"https://github.com/Coursemology/coursemology2/pull/857.patch","issue_url":"https://api.github.com/repos/Coursemology/coursemology2/issues/857","number":857,"state":"open","locked":false,"title":"Create programming answer annotations","user":{"login":"lowjoel","id":2505070,"avatar_url":"https://avatars.githubusercontent.com/u/2505070?v=3","gravatar_id":"","url":"https://api.github.com/users/lowjoel","html_url":"https://github.com/lowjoel","followers_url":"https://api.github.com/users/lowjoel/followers","following_url":"https://api.github.com/users/lowjoel/following{/other_user}","gists_url":"https://api.github.com/users/lowjoel/gists{/gist_id}","starred_url":"https://api.github.com/users/lowjoel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lowjoel/subscriptions","organizations_url":"https://api.github.com/users/lowjoel/orgs","repos_url":"https://api.github.com/users/lowjoel/repos","events_url":"https://api.github.com/users/lowjoel/events{/privacy}","received_events_url":"https://api.github.com/users/lowjoel/received_events","type":"User","site_admin":false},"body":" - Create associated models\r\n - Implement explicit line numbering when formatting code blocks\r\n - Implement the UI for creating new annotations in programming answers\r\n\r\nNext up will be creating the UI for displaying the existing annotations.","created_at":"2016-02-26T14:25:59Z","updated_at":"2016-02-26T14:26:56Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7f149eaf0680c1d9011b807587d11fe9f2fd3979","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857/commits","review_comments_url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857/comments","review_comment_url":"https://api.github.com/repos/Coursemology/coursemology2/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Coursemology/coursemology2/issues/857/comments","statuses_url":"https://api.github.com/repos/Coursemology/coursemology2/statuses/5f3459df55cd2fe575c5661f11d90b964a6b6166","head":{"label":"coursemology-collab:lowjoel/create-programming-answer-annotations","ref":"lowjoel/create-programming-answer-annotations","sha":"5f3459df55cd2fe575c5661f11d90b964a6b6166","user":{"login":"coursemology-collab","id":8666458,"avatar_url":"https://avatars.githubusercontent.com/u/8666458?v=3","gravatar_id":"","url":"https://api.github.com/users/coursemology-collab","html_url":"https://github.com/coursemology-collab","followers_url":"https://api.github.com/users/coursemology-collab/followers","following_url":"https://api.github.com/users/coursemology-collab/following{/other_user}","gists_url":"https://api.github.com/users/coursemology-collab/gists{/gist_id}","starred_url":"https://api.github.com/users/coursemology-collab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coursemology-collab/subscriptions","organizations_url":"https://api.github.com/users/coursemology-collab/orgs","repos_url":"https://api.github.com/users/coursemology-collab/repos","events_url":"https://api.github.com/users/coursemology-collab/events{/privacy}","received_events_url":"https://api.github.com/users/coursemology-collab/received_events","type":"Organization","site_admin":false},"repo":{"id":23697674,"name":"coursemology2","full_name":"coursemology-collab/coursemology2","owner":{"login":"coursemology-collab","id":8666458,"avatar_url":"https://avatars.githubusercontent.com/u/8666458?v=3","gravatar_id":"","url":"https://api.github.com/users/coursemology-collab","html_url":"https://github.com/coursemology-collab","followers_url":"https://api.github.com/users/coursemology-collab/followers","following_url":"https://api.github.com/users/coursemology-collab/following{/other_user}","gists_url":"https://api.github.com/users/coursemology-collab/gists{/gist_id}","starred_url":"https://api.github.com/users/coursemology-collab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coursemology-collab/subscriptions","organizations_url":"https://api.github.com/users/coursemology-collab/orgs","repos_url":"https://api.github.com/users/coursemology-collab/repos","events_url":"https://api.github.com/users/coursemology-collab/events{/privacy}","received_events_url":"https://api.github.com/users/coursemology-collab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/coursemology-collab/coursemology2","description":"Rails 4 re-write of Coursemology","fork":true,"url":"https://api.github.com/repos/coursemology-collab/coursemology2","forks_url":"https://api.github.com/repos/coursemology-collab/coursemology2/forks","keys_url":"https://api.github.com/repos/coursemology-collab/coursemology2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/coursemology-collab/coursemology2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/coursemology-collab/coursemology2/teams","hooks_url":"https://api.github.com/repos/coursemology-collab/coursemology2/hooks","issue_events_url":"https://api.github.com/repos/coursemology-collab/coursemology2/issues/events{/number}","events_url":"https://api.github.com/repos/coursemology-collab/coursemology2/events","assignees_url":"https://api.github.com/repos/coursemology-collab/coursemology2/assignees{/user}","branches_url":"https://api.github.com/repos/coursemology-collab/coursemology2/branches{/branch}","tags_url":"https://api.github.com/repos/coursemology-collab/coursemology2/tags","blobs_url":"https://api.github.com/repos/coursemology-collab/coursemology2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/coursemology-collab/coursemology2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/coursemology-collab/coursemology2/git/refs{/sha}","trees_url":"https://api.github.com/repos/coursemology-collab/coursemology2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/coursemology-collab/coursemology2/statuses/{sha}","languages_url":"https://api.github.com/repos/coursemology-collab/coursemology2/languages","stargazers_url":"https://api.github.com/repos/coursemology-collab/coursemology2/stargazers","contributors_url":"https://api.github.com/repos/coursemology-collab/coursemology2/contributors","subscribers_url":"https://api.github.com/repos/coursemology-collab/coursemology2/subscribers","subscription_url":"https://api.github.com/repos/coursemology-collab/coursemology2/subscription","commits_url":"https://api.github.com/repos/coursemology-collab/coursemology2/commits{/sha}","git_commits_url":"https://api.github.com/repos/coursemology-collab/coursemology2/git/commits{/sha}","comments_url":"https://api.github.com/repos/coursemology-collab/coursemology2/comments{/number}","issue_comment_url":"https://api.github.com/repos/coursemology-collab/coursemology2/issues/comments{/number}","contents_url":"https://api.github.com/repos/coursemology-collab/coursemology2/contents/{+path}","compare_url":"https://api.github.com/repos/coursemology-collab/coursemology2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/coursemology-collab/coursemology2/merges","archive_url":"https://api.github.com/repos/coursemology-collab/coursemology2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/coursemology-collab/coursemology2/downloads","issues_url":"https://api.github.com/repos/coursemology-collab/coursemology2/issues{/number}","pulls_url":"https://api.github.com/repos/coursemology-collab/coursemology2/pulls{/number}","milestones_url":"https://api.github.com/repos/coursemology-collab/coursemology2/milestones{/number}","notifications_url":"https://api.github.com/repos/coursemology-collab/coursemology2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/coursemology-collab/coursemology2/labels{/name}","releases_url":"https://api.github.com/repos/coursemology-collab/coursemology2/releases{/id}","deployments_url":"https://api.github.com/repos/coursemology-collab/coursemology2/deployments","created_at":"2014-09-05T09:32:07Z","updated_at":"2016-02-07T09:46:54Z","pushed_at":"2016-02-26T14:26:41Z","git_url":"git://github.com/coursemology-collab/coursemology2.git","ssh_url":"git@github.com:coursemology-collab/coursemology2.git","clone_url":"https://github.com/coursemology-collab/coursemology2.git","svn_url":"https://github.com/coursemology-collab/coursemology2","homepage":null,"size":3306,"stargazers_count":3,"watchers_count":3,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":3,"default_branch":"master"}},"base":{"label":"Coursemology:master","ref":"master","sha":"87e115f2aee3468b03c63c460afe980c3f32746a","user":{"login":"Coursemology","id":4427741,"avatar_url":"https://avatars.githubusercontent.com/u/4427741?v=3","gravatar_id":"","url":"https://api.github.com/users/Coursemology","html_url":"https://github.com/Coursemology","followers_url":"https://api.github.com/users/Coursemology/followers","following_url":"https://api.github.com/users/Coursemology/following{/other_user}","gists_url":"https://api.github.com/users/Coursemology/gists{/gist_id}","starred_url":"https://api.github.com/users/Coursemology/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Coursemology/subscriptions","organizations_url":"https://api.github.com/users/Coursemology/orgs","repos_url":"https://api.github.com/users/Coursemology/repos","events_url":"https://api.github.com/users/Coursemology/events{/privacy}","received_events_url":"https://api.github.com/users/Coursemology/received_events","type":"Organization","site_admin":false},"repo":{"id":22155032,"name":"coursemology2","full_name":"Coursemology/coursemology2","owner":{"login":"Coursemology","id":4427741,"avatar_url":"https://avatars.githubusercontent.com/u/4427741?v=3","gravatar_id":"","url":"https://api.github.com/users/Coursemology","html_url":"https://github.com/Coursemology","followers_url":"https://api.github.com/users/Coursemology/followers","following_url":"https://api.github.com/users/Coursemology/following{/other_user}","gists_url":"https://api.github.com/users/Coursemology/gists{/gist_id}","starred_url":"https://api.github.com/users/Coursemology/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Coursemology/subscriptions","organizations_url":"https://api.github.com/users/Coursemology/orgs","repos_url":"https://api.github.com/users/Coursemology/repos","events_url":"https://api.github.com/users/Coursemology/events{/privacy}","received_events_url":"https://api.github.com/users/Coursemology/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Coursemology/coursemology2","description":"Rails 4 re-write of Coursemology","fork":false,"url":"https://api.github.com/repos/Coursemology/coursemology2","forks_url":"https://api.github.com/repos/Coursemology/coursemology2/forks","keys_url":"https://api.github.com/repos/Coursemology/coursemology2/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Coursemology/coursemology2/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Coursemology/coursemology2/teams","hooks_url":"https://api.github.com/repos/Coursemology/coursemology2/hooks","issue_events_url":"https://api.github.com/repos/Coursemology/coursemology2/issues/events{/number}","events_url":"https://api.github.com/repos/Coursemology/coursemology2/events","assignees_url":"https://api.github.com/repos/Coursemology/coursemology2/assignees{/user}","branches_url":"https://api.github.com/repos/Coursemology/coursemology2/branches{/branch}","tags_url":"https://api.github.com/repos/Coursemology/coursemology2/tags","blobs_url":"https://api.github.com/repos/Coursemology/coursemology2/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Coursemology/coursemology2/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Coursemology/coursemology2/git/refs{/sha}","trees_url":"https://api.github.com/repos/Coursemology/coursemology2/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Coursemology/coursemology2/statuses/{sha}","languages_url":"https://api.github.com/repos/Coursemology/coursemology2/languages","stargazers_url":"https://api.github.com/repos/Coursemology/coursemology2/stargazers","contributors_url":"https://api.github.com/repos/Coursemology/coursemology2/contributors","subscribers_url":"https://api.github.com/repos/Coursemology/coursemology2/subscribers","subscription_url":"https://api.github.com/repos/Coursemology/coursemology2/subscription","commits_url":"https://api.github.com/repos/Coursemology/coursemology2/commits{/sha}","git_commits_url":"https://api.github.com/repos/Coursemology/coursemology2/git/commits{/sha}","comments_url":"https://api.github.com/repos/Coursemology/coursemology2/comments{/number}","issue_comment_url":"https://api.github.com/repos/Coursemology/coursemology2/issues/comments{/number}","contents_url":"https://api.github.com/repos/Coursemology/coursemology2/contents/{+path}","compare_url":"https://api.github.com/repos/Coursemology/coursemology2/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Coursemology/coursemology2/merges","archive_url":"https://api.github.com/repos/Coursemology/coursemology2/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Coursemology/coursemology2/downloads","issues_url":"https://api.github.com/repos/Coursemology/coursemology2/issues{/number}","pulls_url":"https://api.github.com/repos/Coursemology/coursemology2/pulls{/number}","milestones_url":"https://api.github.com/repos/Coursemology/coursemology2/milestones{/number}","notifications_url":"https://api.github.com/repos/Coursemology/coursemology2/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Coursemology/coursemology2/labels{/name}","releases_url":"https://api.github.com/repos/Coursemology/coursemology2/releases{/id}","deployments_url":"https://api.github.com/repos/Coursemology/coursemology2/deployments","created_at":"2014-07-23T14:57:06Z","updated_at":"2016-02-07T02:20:36Z","pushed_at":"2016-02-26T14:26:41Z","git_url":"git://github.com/Coursemology/coursemology2.git","ssh_url":"git@github.com:Coursemology/coursemology2.git","clone_url":"https://github.com/Coursemology/coursemology2.git","svn_url":"https://github.com/Coursemology/coursemology2","homepage":null,"size":4747,"stargazers_count":19,"watchers_count":19,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":17,"mirror_url":null,"open_issues_count":74,"forks":17,"open_issues":74,"watchers":19,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857"},"html":{"href":"https://github.com/Coursemology/coursemology2/pull/857"},"issue":{"href":"https://api.github.com/repos/Coursemology/coursemology2/issues/857"},"comments":{"href":"https://api.github.com/repos/Coursemology/coursemology2/issues/857/comments"},"review_comments":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857/comments"},"review_comment":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Coursemology/coursemology2/pulls/857/commits"},"statuses":{"href":"https://api.github.com/repos/Coursemology/coursemology2/statuses/5f3459df55cd2fe575c5661f11d90b964a6b6166"}}}}