total contributions in the last 12 months
'\n  });\n\n  new Vue({\n    delimiters: vueDelimeters,\n    el,\n\n    data: {\n      suburl: document.querySelector('meta[name=_suburl]').content,\n      heatmapUser,\n      locale\n    },\n  });\n};\n\nfunction initFilterBranchTagDropdown(selector) {\n  $(selector).each(function () {\n    const $dropdown = $(this);\n    const $data = $dropdown.find('.data');\n    const data = {\n      items: [],\n      mode: $data.data('mode'),\n      searchTerm: '',\n      noResults: '',\n      canCreateBranch: false,\n      menuVisible: false,\n      active: 0\n    };\n    $data.find('.item').each(function () {\n      data.items.push({\n        name: $(this).text(),\n        url: $(this).data('url'),\n        branch: $(this).hasClass('branch'),\n        tag: $(this).hasClass('tag'),\n        selected: $(this).hasClass('selected')\n      });\n    });\n    $data.remove();\n    new Vue({\n      delimiters: ['${', '}'],\n      el: this,\n      data,\n\n      beforeMount() {\n        const vm = this;\n\n        this.noResults = vm.$el.getAttribute('data-no-results');\n        this.canCreateBranch = vm.$el.getAttribute('data-can-create-branch') === 'true';\n\n        document.body.addEventListener('click', (event) => {\n          if (vm.$el.contains(event.target)) {\n            return;\n          }\n          if (vm.menuVisible) {\n            Vue.set(vm, 'menuVisible', false);\n          }\n        });\n      },\n\n      watch: {\n        menuVisible(visible) {\n          if (visible) {\n            this.focusSearchField();\n          }\n        }\n      },\n\n      computed: {\n        filteredItems() {\n          const vm = this;\n\n          const items = vm.items.filter((item) => {\n            return ((vm.mode === 'branches' && item.branch) || (vm.mode === 'tags' && item.tag))\n              && (!vm.searchTerm || item.name.toLowerCase().indexOf(vm.searchTerm.toLowerCase()) >= 0);\n          });\n\n          vm.active = (items.length === 0 && vm.showCreateNewBranch ? 0 : -1);\n\n          return items;\n        },\n        showNoResults() {\n          return this.filteredItems.length === 0 && !this.showCreateNewBranch;\n        },\n        showCreateNewBranch() {\n          const vm = this;\n          if (!this.canCreateBranch || !vm.searchTerm || vm.mode === 'tags') {\n            return false;\n          }\n\n          return vm.items.filter((item) => item.name.toLowerCase() === vm.searchTerm.toLowerCase()).length === 0;\n        }\n      },\n\n      methods: {\n        selectItem(item) {\n          const prev = this.getSelected();\n          if (prev !== null) {\n            prev.selected = false;\n          }\n          item.selected = true;\n          window.location.href = item.url;\n        },\n        createNewBranch() {\n          if (!this.showCreateNewBranch) {\n            return;\n          }\n          this.$refs.newBranchForm.submit();\n        },\n        focusSearchField() {\n          const vm = this;\n          Vue.nextTick(() => {\n            vm.$refs.searchField.focus();\n          });\n        },\n        getSelected() {\n          for (let i = 0, j = this.items.length; i < j; ++i) {\n            if (this.items[i].selected) return this.items[i];\n          }\n          return null;\n        },\n        getSelectedIndexInFiltered() {\n          for (let i = 0, j = this.filteredItems.length; i < j; ++i) {\n            if (this.filteredItems[i].selected) return i;\n          }\n          return -1;\n        },\n        scrollToActive() {\n          let el = this.$refs[`listItem${this.active}`];\n          if (!el || el.length === 0) {\n            return;\n          }\n          if (Array.isArray(el)) {\n            el = el[0];\n          }\n\n          const cont = this.$refs.scrollContainer;\n\n          if (el.offsetTop < cont.scrollTop) {\n            cont.scrollTop = el.offsetTop;\n          } else if (el.offsetTop + el.clientHeight > cont.scrollTop + cont.clientHeight) {\n            cont.scrollTop = el.offsetTop + el.clientHeight - cont.clientHeight;\n          }\n        },\n        keydown(event) {\n          const vm = this;\n          if (event.keyCode === 40) {\n            // arrow down\n            event.preventDefault();\n\n            if (vm.active === -1) {\n              vm.active = vm.getSelectedIndexInFiltered();\n            }\n\n            if (vm.active + (vm.showCreateNewBranch ? 0 : 1) >= vm.filteredItems.length) {\n              return;\n            }\n            vm.active++;\n            vm.scrollToActive();\n          }\n          if (event.keyCode === 38) {\n            // arrow up\n            event.preventDefault();\n\n            if (vm.active === -1) {\n              vm.active = vm.getSelectedIndexInFiltered();\n            }\n\n            if (vm.active <= 0) {\n              return;\n            }\n            vm.active--;\n            vm.scrollToActive();\n          }\n          if (event.keyCode === 13) {\n            // enter\n            event.preventDefault();\n\n            if (vm.active >= vm.filteredItems.length) {\n              vm.createNewBranch();\n            } else if (vm.active >= 0) {\n              vm.selectItem(vm.filteredItems[vm.active]);\n            }\n          }\n          if (event.keyCode === 27) {\n            // escape\n            event.preventDefault();\n            vm.menuVisible = false;\n          }\n        }\n      }\n    });\n  });\n}\n\n$('.commit-button').click(function (e) {\n  e.preventDefault();\n  $(this).parent().find('.commit-body').toggle();\n});\n\nfunction initNavbarContentToggle() {\n  const content = $('#navbar');\n  const toggle = $('#navbar-expand-toggle');\n  let isExpanded = false;\n  toggle.click(() => {\n    isExpanded = !isExpanded;\n    if (isExpanded) {\n      content.addClass('shown');\n      toggle.addClass('active');\n    } else {\n      content.removeClass('shown');\n      toggle.removeClass('active');\n    }\n  });\n}\n\nfunction initTopicbar() {\n  const mgrBtn = $('#manage_topic');\n  const editDiv = $('#topic_edit');\n  const viewDiv = $('#repo-topics');\n  const saveBtn = $('#save_topic');\n  const topicDropdown = $('#topic_edit .dropdown');\n  const topicForm = $('#topic_edit.ui.form');\n  const topicPrompts = getPrompts();\n\n  mgrBtn.click(() => {\n    viewDiv.hide();\n    editDiv.css('display', ''); // show Semantic UI Grid\n  });\n\n  function getPrompts() {\n    const hidePrompt = $('div.hide#validate_prompt');\n    const prompts = {\n      countPrompt: hidePrompt.children('#count_prompt').text(),\n      formatPrompt: hidePrompt.children('#format_prompt').text()\n    };\n    hidePrompt.remove();\n    return prompts;\n  }\n\n  saveBtn.click(() => {\n    const topics = $('input[name=topics]').val();\n\n    $.post(saveBtn.data('link'), {\n      _csrf: csrf,\n      topics\n    }, (_data, _textStatus, xhr) => {\n      if (xhr.responseJSON.status === 'ok') {\n        viewDiv.children('.topic').remove();\n        if (topics.length) {\n          const topicArray = topics.split(',');\n\n          const last = viewDiv.children('a').last();\n          for (let i = 0; i < topicArray.length; i++) {\n            $(`
${topicArray[i]}`).insertBefore(last);\n          }\n        }\n        editDiv.css('display', 'none');\n        viewDiv.show();\n      }\n    }).fail((xhr) => {\n      if (xhr.status === 422) {\n        if (xhr.responseJSON.invalidTopics.length > 0) {\n          topicPrompts.formatPrompt = xhr.responseJSON.message;\n\n          const { invalidTopics } = xhr.responseJSON;\n          const topicLables = topicDropdown.children('a.ui.label');\n\n          topics.split(',').forEach((value, index) => {\n            for (let i = 0; i < invalidTopics.length; i++) {\n              if (invalidTopics[i] === value) {\n                topicLables.eq(index).removeClass('green').addClass('red');\n              }\n            }\n          });\n        } else {\n          topicPrompts.countPrompt = xhr.responseJSON.message;\n        }\n      }\n    }).always(() => {\n      topicForm.form('validate form');\n    });\n  });\n\n  topicDropdown.dropdown({\n    allowAdditions: true,\n    forceSelection: false,\n    fields: { name: 'description', value: 'data-value' },\n    saveRemoteData: false,\n    label: {\n      transition: 'horizontal flip',\n      duration: 200,\n      variation: false,\n      blue: true,\n      basic: true,\n    },\n    className: {\n      label: 'ui small label'\n    },\n    apiSettings: {\n      url: `${suburl}/api/v1/topics/search?q={query}`,\n      throttle: 500,\n      cache: false,\n      onResponse(res) {\n        const formattedResponse = {\n          success: false,\n          results: [],\n        };\n        const stripTags = function (text) {\n          return text.replace(/<[^>]*>?/gm, '');\n        };\n\n        const query = stripTags(this.urlData.query.trim());\n        let found_query = false;\n        const current_topics = [];\n        topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, e) => { current_topics.push(e.dataset.value); });\n\n        if (res.topics) {\n          let found = false;\n          for (let i = 0; i < res.topics.length; i++) {\n            // skip currently added tags\n            if (current_topics.indexOf(res.topics[i].topic_name) !== -1) {\n              continue;\n            }\n\n            if (res.topics[i].topic_name.toLowerCase() === query.toLowerCase()) {\n              found_query = true;\n            }\n            formattedResponse.results.push({ description: res.topics[i].topic_name, 'data-value': res.topics[i].topic_name });\n            found = true;\n          }\n          formattedResponse.success = found;\n        }\n\n        if (query.length > 0 && !found_query) {\n          formattedResponse.success = true;\n          formattedResponse.results.unshift({ description: query, 'data-value': query });\n        } else if (query.length > 0 && found_query) {\n          formattedResponse.results.sort((a, b) => {\n            if (a.description.toLowerCase() === query.toLowerCase()) return -1;\n            if (b.description.toLowerCase() === query.toLowerCase()) return 1;\n            if (a.description > b.description) return -1;\n            if (a.description < b.description) return 1;\n            return 0;\n          });\n        }\n\n\n        return formattedResponse;\n      },\n    },\n    onLabelCreate(value) {\n      value = value.toLowerCase().trim();\n      this.attr('data-value', value).contents().first().replaceWith(value);\n      return $(this);\n    },\n    onAdd(addedValue, _addedText, $addedChoice) {\n      addedValue = addedValue.toLowerCase().trim();\n      $($addedChoice).attr('data-value', addedValue);\n      $($addedChoice).attr('data-text', addedValue);\n    }\n  });\n\n  $.fn.form.settings.rules.validateTopic = function (_values, regExp) {\n    const topics = topicDropdown.children('a.ui.label');\n    const status = topics.length === 0 || topics.last().attr('data-value').match(regExp);\n    if (!status) {\n      topics.last().removeClass('green').addClass('red');\n    }\n    return status && topicDropdown.children('a.ui.label.red').length === 0;\n  };\n\n  topicForm.form({\n    on: 'change',\n    inline: true,\n    fields: {\n      topics: {\n        identifier: 'topics',\n        rules: [\n          {\n            type: 'validateTopic',\n            value: /^[a-z0-9][a-z0-9-]{0,35}$/,\n            prompt: topicPrompts.formatPrompt\n          },\n          {\n            type: 'maxCount[25]',\n            prompt: topicPrompts.countPrompt\n          }\n        ]\n      },\n    }\n  });\n}\n\nwindow.toggleDeadlineForm = function () {\n  $('#deadlineForm').fadeToggle(150);\n};\n\nwindow.setDeadline = function () {\n  const deadline = $('#deadlineDate').val();\n  window.updateDeadline(deadline);\n};\n\nwindow.updateDeadline = function (deadlineString) {\n  $('#deadline-err-invalid-date').hide();\n  $('#deadline-loader').addClass('loading');\n\n  let realDeadline = null;\n  if (deadlineString !== '') {\n    const newDate = Date.parse(deadlineString);\n\n    if (Number.isNaN(newDate)) {\n      $('#deadline-loader').removeClass('loading');\n      $('#deadline-err-invalid-date').show();\n      return false;\n    }\n    realDeadline = new Date(newDate);\n  }\n\n  $.ajax(`${$('#update-issue-deadline-form').attr('action')}/deadline`, {\n    data: JSON.stringify({\n      due_date: realDeadline,\n    }),\n    headers: {\n      'X-Csrf-Token': csrf,\n      'X-Remote': true,\n    },\n    contentType: 'application/json',\n    type: 'POST',\n    success() {\n      reload();\n    },\n    error() {\n      $('#deadline-loader').removeClass('loading');\n      $('#deadline-err-invalid-date').show();\n    }\n  });\n};\n\nwindow.deleteDependencyModal = function (id, type) {\n  $('.remove-dependency')\n    .modal({\n      closable: false,\n      duration: 200,\n      onApprove() {\n        $('#removeDependencyID').val(id);\n        $('#dependencyType').val(type);\n        $('#removeDependencyForm').submit();\n      }\n    }).modal('show');\n};\n\nfunction initIssueList() {\n  const repolink = $('#repolink').val();\n  const repoId = $('#repoId').val();\n  const crossRepoSearch = $('#crossRepoSearch').val();\n  let issueSearchUrl = `${suburl}/api/v1/repos/${repolink}/issues?q={query}`;\n  if (crossRepoSearch === 'true') {\n    issueSearchUrl = `${suburl}/api/v1/repos/issues/search?q={query}&priority_repo_id=${repoId}`;\n  }\n  $('#new-dependency-drop-list')\n    .dropdown({\n      apiSettings: {\n        url: issueSearchUrl,\n        onResponse(response) {\n          const filteredResponse = { success: true, results: [] };\n          const currIssueId = $('#new-dependency-drop-list').data('issue-id');\n          // Parse the response from the api to work with our dropdown\n          $.each(response, (_i, issue) => {\n            // Don't list current issue in the dependency list.\n            if (issue.id === currIssueId) {\n              return;\n            }\n            filteredResponse.results.push({\n              name: `#${issue.number} ${htmlEncode(issue.title)\n              }
${htmlEncode(issue.repository.full_name)}
`,\n              value: issue.id\n            });\n          });\n          return filteredResponse;\n        },\n        cache: false,\n      },\n\n      fullTextSearch: true\n    });\n\n  $('.menu a.label-filter-item').each(function () {\n    $(this).click(function (e) {\n      if (e.altKey) {\n        e.preventDefault();\n\n        const href = $(this).attr('href');\n        const id = $(this).data('label-id');\n\n        const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`;\n        const newStr = 'labels=$1-$2$3&';\n\n        window.location = href.replace(new RegExp(regStr), newStr);\n      }\n    });\n  });\n\n  $('.menu .ui.dropdown.label-filter').keydown((e) => {\n    if (e.altKey && e.keyCode === 13) {\n      const selectedItems = $('.menu .ui.dropdown.label-filter .menu .item.selected');\n\n      if (selectedItems.length > 0) {\n        const item = $(selectedItems[0]);\n\n        const href = item.attr('href');\n        const id = item.data('label-id');\n\n        const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`;\n        const newStr = 'labels=$1-$2$3&';\n\n        window.location = href.replace(new RegExp(regStr), newStr);\n      }\n    }\n  });\n}\nwindow.cancelCodeComment = function (btn) {\n  const form = $(btn).closest('form');\n  if (form.length > 0 && form.hasClass('comment-form')) {\n    form.addClass('hide');\n    form.parent().find('button.comment-form-reply').show();\n  } else {\n    form.closest('.comment-code-cloud').remove();\n  }\n};\nwindow.onOAuthLoginClick = function () {\n  const oauthLoader = $('#oauth2-login-loader');\n  const oauthNav = $('#oauth2-login-navigator');\n\n  oauthNav.hide();\n  oauthLoader.removeClass('disabled');\n\n  setTimeout(() => {\n    // recover previous content to let user try again\n    // usually redirection will be performed before this action\n    oauthLoader.addClass('disabled');\n    oauthNav.show();\n  }, 5000);\n};\n"],"sourceRoot":""}
\ No newline at end of file