add make targets for js and css, add js linter (#6952)

* add make targets for js,css, add javascript linter

- add `make js`, deprecating `make javascripts`
- add `make css`, deprecating `make generate-stylesheets` and
  `make stylesheets-check`
- changed the unclean css check to only run on CI
- add JS linting via eslint with basic configuration and fixed
  discovered issues
- changed autoprefixer to use official `postcss-cli` avoiding the need
  to loop in the makefile
- moved browserslist to package.json so other future tools can use it
  too.
- update documentation for new make targets and added JS section

* fix indentation

* move functions used in html to 'exported' list

* Run lessc binary without having to install anything to node_modules

* use relative paths to node bin scripts, removing npx

* Revert "use relative paths to node bin scripts, removing npx"

This reverts commit 119b725525a8430b32ee7a6e6009b4ece544e39b.

* fix lessc and postcss plugins

* check for node_modules and use actual bin names
This commit is contained in:
silverwind 2019-05-16 07:57:47 +02:00 committed by Lauris BH
parent 775a5a5b0f
commit d9dcd09340
9 changed files with 891 additions and 132 deletions

View file

@ -50,7 +50,8 @@ pipeline:
pull: true pull: true
commands: commands:
- npm install - npm install
- make stylesheets-check - make css
- make js
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]

25
.eslintrc Normal file
View file

@ -0,0 +1,25 @@
root: true
extends:
- eslint:recommended
parserOptions:
ecmaVersion: 2015
env:
browser: true
jquery: true
es6: true
globals:
Clipboard: false
CodeMirror: false
emojify: false
SimpleMDE: false
Vue: false
Dropzone: false
u2fApi: false
hljs: false
rules:
no-unused-vars: [error, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]

View file

@ -114,7 +114,7 @@ Generally, the go build tools are installed as-needed in the `Makefile`.
An exception are the tools to build the CSS and images. An exception are the tools to build the CSS and images.
- To build CSS: Install [Node.js](https://nodejs.org/en/download/package-manager) at version 8.0 or above - To build CSS: Install [Node.js](https://nodejs.org/en/download/package-manager) at version 8.0 or above
with `npm` and then run `npm install` and `make generate-stylesheets`. with `npm` and then run `npm install` and `make css`.
- To build Images: ImageMagick, inkscape and zopflipng binaries must be - To build Images: ImageMagick, inkscape and zopflipng binaries must be
available in your `PATH` to run `make generate-images`. available in your `PATH` to run `make generate-images`.

View file

@ -365,33 +365,55 @@ release-compress:
fi fi
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done; cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
.PHONY: javascripts .PHONY: js
javascripts: public/js/index.js js:
@if ([ ! -d "$(PWD)/node_modules" ]); then \
.IGNORE: public/js/index.js echo "node_modules directory is absent, please run 'npm install' first"; \
public/js/index.js: $(JAVASCRIPTS)
cat $< >| $@
.PHONY: stylesheets-check
stylesheets-check: generate-stylesheets
@diff=$$(git diff public/css/*); \
if [ -n "$$diff" ]; then \
echo "Please run 'make generate-stylesheets' and commit the result:"; \
echo "$${diff}"; \
exit 1; \ exit 1; \
fi; fi;
.PHONY: generate-stylesheets
generate-stylesheets:
@hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Please install npm version 5.2+"; \ echo "Please install npm version 5.2+"; \
exit 1; \ exit 1; \
fi; fi;
$(eval BROWSERS := "> 1%, last 2 firefox versions, last 2 safari versions, ie 11") npx eslint public/js
.PHONY: css
css:
@if ([ ! -d "$(PWD)/node_modules" ]); then \
echo "node_modules directory is absent, please run 'npm install' first"; \
exit 1; \
fi;
@hash npx > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Please install npm version 5.2+"; \
exit 1; \
fi;
npx lesshint public/less/ npx lesshint public/less/
npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css npx lessc --clean-css="--s0 -b" public/less/index.less public/css/index.css
$(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;) $(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),npx lessc --clean-css="--s0 -b" public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;)
$(foreach file, $(wildcard public/css/*),npx postcss --use autoprefixer --autoprefixer.browsers $(BROWSERS) -o $(file) $(file);) npx postcss --use autoprefixer --no-map --replace public/css/*
@diff=$$(git diff public/css/*); \
if ([ ! -z "$CI" ] && [ -n "$$diff" ]); then \
echo "Generated files in public/css have changed, please commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: javascripts
javascripts:
echo "'make javascripts' is deprecated, please use 'make js'"
$(MAKE) js
.PHONY: stylesheets-check
stylesheets-check:
echo "'make stylesheets-check' is deprecated, please use 'make css'"
$(MAKE) css
.PHONY: generate-stylesheets
generate-stylesheets:
echo "'make generate-stylesheets' is deprecated, please use 'make css'"
$(MAKE) css
.PHONY: swagger-ui .PHONY: swagger-ui
swagger-ui: swagger-ui:

View file

@ -136,30 +136,36 @@ You should lint, vet and spell-check with:
make vet lint misspell-check make vet lint misspell-check
``` ```
### Updating the stylesheets ### Updating CSS
To generate the stylsheets, you will need [Node.js](https://nodejs.org/) at version 8.0 or above. To generate the CSS, you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies:
At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our stylesheets. Do
**not** edit the files in `public/css/` directly, as they are generated from
`lessc` from the files in `public/less/`.
If you wish to work on the stylesheets, you will need to install `lessc` the
less compiler and `postcss`. The recommended way to do this is using `npm install`:
```bash ```bash
cd "$GOPATH/src/code.gitea.io/gitea"
npm install npm install
``` ```
You can then edit the less stylesheets and regenerate the stylesheets using: At present we use [less](http://lesscss.org/) and [postcss](https://postcss.org) to generate our CSS. Do
**not** edit the files in `public/css` directly, as they are generated from `lessc` from the files in `public/less`.
Edit files in `public/less`, run the linter, regenerate the CSS and commit all changed files:
```bash ```bash
make generate-stylesheets make css
``` ```
You should commit both the changes to the css and the less files when making ### Updating JS
PRs.
To run the JavaScript linter you will need [Node.js](https://nodejs.org/) 8.0 or greater and the build dependencies:
```bash
npm install
```
Edit files in `public/js` and run the linter:
```bash
make js
```
### Updating the API ### Updating the API

728
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,16 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"autoprefixer": "9.5.1", "autoprefixer": "9.5.1",
"eslint": "5.16.0",
"less": "3.9.0", "less": "3.9.0",
"less-plugin-clean-css": "1.5.1", "less-plugin-clean-css": "1.5.1",
"lesshint": "^6.3.6", "lesshint": "^6.3.6",
"postcss-cli-simple": "3.0.0" "postcss-cli": "6.1.2"
} },
"browserslist": [
"> 1%",
"last 2 firefox versions",
"last 2 safari versions",
"ie 11"
]
} }

View file

@ -1,3 +1,5 @@
/* globals gitGraph */
$(document).ready(function () { $(document).ready(function () {
var graphList = []; var graphList = [];

View file

@ -1,3 +1,6 @@
/* globals wipPrefixes, issuesTribute, emojiTribute */
/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
/* exported toggleDeadlineForm, setDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
'use strict'; 'use strict';
function htmlEncode(text) { function htmlEncode(text) {
@ -89,7 +92,7 @@ if (!Array.from) {
if (typeof Object.assign != 'function') { if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true // Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", { Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2 value: function assign(target, _varArgs) { // .length of function is 2
'use strict'; 'use strict';
if (target == null) { // TypeError if undefined or null if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object'); throw new TypeError('Cannot convert undefined or null to object');
@ -131,8 +134,8 @@ function initCommentPreviewTab($form) {
var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
$previewPanel.html(data); $previewPanel.html(data);
emojify.run($previewPanel[0]); emojify.run($previewPanel[0]);
$('pre code', $previewPanel[0]).each(function (i, block) { $('pre code', $previewPanel[0]).each(function () {
hljs.highlightBlock(block); hljs.highlightBlock(this);
}); });
} }
); );
@ -161,8 +164,8 @@ function initEditPreviewTab($form) {
var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]'); var $previewPanel = $form.find('.tab.segment[data-tab="' + $tabMenu.data('preview') + '"]');
$previewPanel.html(data); $previewPanel.html(data);
emojify.run($previewPanel[0]); emojify.run($previewPanel[0]);
$('pre code', $previewPanel[0]).each(function (i, block) { $('pre code', $previewPanel[0]).each(function () {
hljs.highlightBlock(block); hljs.highlightBlock(this);
}); });
} }
); );
@ -355,7 +358,8 @@ function reload() {
} }
function initImagePaste(target) { function initImagePaste(target) {
target.each(function(i, field) { target.each(function() {
var field = this;
field.addEventListener('paste', function(event){ field.addEventListener('paste', function(event){
retrieveImageFromClipboardAsBlob(event, function(img) { retrieveImageFromClipboardAsBlob(event, function(img) {
var name = img.name.substr(0, img.name.lastIndexOf('.')); var name = img.name.substr(0, img.name.lastIndexOf('.'));
@ -606,7 +610,7 @@ function initInstall() {
$('#sql_settings').show(); $('#sql_settings').show();
$('#pgsql_settings').toggle(dbType === "PostgreSQL"); $('#pgsql_settings').toggle(dbType === "PostgreSQL");
$.each(dbDefaults, function(type, defaultHost) { $.each(dbDefaults, function(_type, defaultHost) {
if ($('#db_host').val() == defaultHost) { if ($('#db_host').val() == defaultHost) {
$('#db_host').val(dbDefaults[dbType]); $('#db_host').val(dbDefaults[dbType]);
return false; return false;
@ -636,8 +640,7 @@ function initInstall() {
}); });
$('#enable-openid-signin input').change(function () { $('#enable-openid-signin input').change(function () {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
if ( $('#disable-registration input').is(':checked') ) { if (!$('#disable-registration input').is(':checked')) {
} else {
$('#enable-openid-signup').checkbox('check'); $('#enable-openid-signup').checkbox('check');
} }
} else { } else {
@ -669,7 +672,7 @@ function initRepository() {
$dropdown.dropdown({ $dropdown.dropdown({
fullTextSearch: true, fullTextSearch: true,
selectOnKeydown: false, selectOnKeydown: false,
onChange: function (text, value, $choice) { onChange: function (_text, _value, $choice) {
if ($choice.data('url')) { if ($choice.data('url')) {
window.location.href = $choice.data('url'); window.location.href = $choice.data('url');
} }
@ -756,9 +759,6 @@ function initRepository() {
} }
// Milestones // Milestones
if ($('.repository.milestones').length > 0) {
}
if ($('.repository.new.milestone').length > 0) { if ($('.repository.new.milestone').length > 0) {
var $datepicker = $('.milestone.datepicker'); var $datepicker = $('.milestone.datepicker');
$datepicker.datetimepicker({ $datepicker.datetimepicker({
@ -857,8 +857,8 @@ function initRepository() {
} else { } else {
$renderContent.html(data.content); $renderContent.html(data.content);
emojify.run($renderContent[0]); emojify.run($renderContent[0]);
$('pre code', $renderContent[0]).each(function (i, block) { $('pre code', $renderContent[0]).each(function () {
hljs.highlightBlock(block); hljs.highlightBlock(this);
}); });
} }
}); });
@ -912,7 +912,7 @@ function initRepository() {
$(this).parent().hide(); $(this).parent().hide();
}); });
$('.merge-button > .dropdown').dropdown({ $('.merge-button > .dropdown').dropdown({
onChange: function (text, value, $choice) { onChange: function (_text, _value, $choice) {
if ($choice.data('do')) { if ($choice.data('do')) {
$mergeButton.find('.button-text').text($choice.text()); $mergeButton.find('.button-text').text($choice.text());
$mergeButton.data('do', $choice.data('do')); $mergeButton.data('do', $choice.data('do'));
@ -930,17 +930,14 @@ function initRepository() {
// Diff // Diff
if ($('.repository.diff').length > 0) { if ($('.repository.diff').length > 0) {
var $counter = $('.diff-counter'); $('.diff-counter').each(function () {
if ($counter.length >= 1) { var $item = $(this);
$counter.each(function (i, item) {
var $item = $(item);
var addLine = $item.find('span[data-line].add').data("line"); var addLine = $item.find('span[data-line].add').data("line");
var delLine = $item.find('span[data-line].del').data("line"); var delLine = $item.find('span[data-line].del').data("line");
var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100; var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
$item.find(".bar .add").css("width", addPercent + "%"); $item.find(".bar .add").css("width", addPercent + "%");
}); });
} }
}
// Quick start and repository home // Quick start and repository home
$('#repo-clone-ssh').click(function () { $('#repo-clone-ssh').click(function () {
@ -1085,8 +1082,9 @@ function assingMenuAttributes(menu) {
var id = Math.floor(Math.random() * Math.floor(1000000)); var id = Math.floor(Math.random() * Math.floor(1000000));
menu.attr('data-write', menu.attr('data-write') + id); menu.attr('data-write', menu.attr('data-write') + id);
menu.attr('data-preview', menu.attr('data-preview') + id); menu.attr('data-preview', menu.attr('data-preview') + id);
menu.find('.item').each(function(i, item) { menu.find('.item').each(function() {
$(item).attr('data-tab', $(item).attr('data-tab') + id); var tab = $(this).attr('data-tab') + id;
$(this).attr('data-tab', tab);
}); });
menu.parent().find("*[data-tab='write']").attr('data-tab', 'write' + id); menu.parent().find("*[data-tab='write']").attr('data-tab', 'write' + id);
menu.parent().find("*[data-tab='preview']").attr('data-tab', 'preview' + id); menu.parent().find("*[data-tab='preview']").attr('data-tab', 'preview' + id);
@ -1170,7 +1168,6 @@ String.prototype.endsWith = function (pattern) {
}; };
// Adding function to get the cursor position in a text field to jQuery object. // Adding function to get the cursor position in a text field to jQuery object.
(function ($, undefined) {
$.fn.getCursorPosition = function () { $.fn.getCursorPosition = function () {
var el = $(this).get(0); var el = $(this).get(0);
var pos = 0; var pos = 0;
@ -1185,7 +1182,6 @@ String.prototype.endsWith = function (pattern) {
} }
return pos; return pos;
} }
})(jQuery);
function setSimpleMDE($editArea) { function setSimpleMDE($editArea) {
if (codeMirrorEditor) { if (codeMirrorEditor) {
@ -1249,7 +1245,7 @@ function setCodeMirror($editArea) {
codeMirrorEditor = CodeMirror.fromTextArea($editArea[0], { codeMirrorEditor = CodeMirror.fromTextArea($editArea[0], {
lineNumbers: true lineNumbers: true
}); });
codeMirrorEditor.on("change", function (cm, change) { codeMirrorEditor.on("change", function (cm, _change) {
$editArea.val(cm.getValue()); $editArea.val(cm.getValue());
}); });
@ -1271,10 +1267,13 @@ function initEditor() {
$editFilename.keyup(function (e) { $editFilename.keyup(function (e) {
var $section = $('.breadcrumb span.section'); var $section = $('.breadcrumb span.section');
var $divider = $('.breadcrumb div.divider'); var $divider = $('.breadcrumb div.divider');
var value;
var parts;
if (e.keyCode == 8) { if (e.keyCode == 8) {
if ($(this).getCursorPosition() == 0) { if ($(this).getCursorPosition() == 0) {
if ($section.length > 0) { if ($section.length > 0) {
var value = $section.last().find('a').text(); value = $section.last().find('a').text();
$(this).val(value + $(this).val()); $(this).val(value + $(this).val());
$(this)[0].setSelectionRange(value.length, value.length); $(this)[0].setSelectionRange(value.length, value.length);
$section.last().remove(); $section.last().remove();
@ -1283,9 +1282,9 @@ function initEditor() {
} }
} }
if (e.keyCode == 191) { if (e.keyCode == 191) {
var parts = $(this).val().split('/'); parts = $(this).val().split('/');
for (var i = 0; i < parts.length; ++i) { for (var i = 0; i < parts.length; ++i) {
var value = parts[i]; value = parts[i];
if (i < parts.length - 1) { if (i < parts.length - 1) {
if (value.length) { if (value.length) {
$('<span class="section"><a href="#">' + value + '</a></span>').insertBefore($(this)); $('<span class="section"><a href="#">' + value + '</a></span>').insertBefore($(this));
@ -1298,9 +1297,9 @@ function initEditor() {
$(this)[0].setSelectionRange(0, 0); $(this)[0].setSelectionRange(0, 0);
} }
} }
var parts = []; parts = [];
$('.breadcrumb span.section').each(function (i, element) { $('.breadcrumb span.section').each(function () {
element = $(element); var element = $(this);
if (element.find('a').length) { if (element.find('a').length) {
parts.push(element.find('a').text()); parts.push(element.find('a').text());
} else { } else {
@ -1319,10 +1318,11 @@ function initEditor() {
var markdownFileExts = $editArea.data("markdown-file-exts").split(","); var markdownFileExts = $editArea.data("markdown-file-exts").split(",");
var lineWrapExtensions = $editArea.data("line-wrap-extensions").split(","); var lineWrapExtensions = $editArea.data("line-wrap-extensions").split(",");
$editFilename.on("keyup", function (e) { $editFilename.on("keyup", function () {
var val = $editFilename.val(), m, mode, spec, extension, extWithDot, previewLink, dataUrl, apiCall; var val = $editFilename.val(), m, mode, spec, extension, extWithDot, previewLink, dataUrl, apiCall;
extension = extWithDot = ""; extension = extWithDot = "";
if (m = /.+\.([^.]+)$/.exec(val)) { m = /.+\.([^.]+)$/.exec(val);
if (m) {
extension = m[1]; extension = m[1];
extWithDot = "." + extension; extWithDot = "." + extension;
} }
@ -1684,15 +1684,6 @@ function buttonsClickOnEnter() {
}); });
} }
function hideWhenLostFocus(body, parent) {
$(document).click(function (e) {
var target = e.target;
if (!$(target).is(body) && !$(target).parents().is(parent)) {
$(body).hide();
}
});
}
function searchUsers() { function searchUsers() {
var $searchUserBox = $('#search-user-box'); var $searchUserBox = $('#search-user-box');
$searchUserBox.search({ $searchUserBox.search({
@ -1701,7 +1692,7 @@ function searchUsers() {
url: suburl + '/api/v1/users/search?q={query}', url: suburl + '/api/v1/users/search?q={query}',
onResponse: function(response) { onResponse: function(response) {
var items = []; var items = [];
$.each(response.data, function (i, item) { $.each(response.data, function (_i, item) {
var title = item.login; var title = item.login;
if (item.full_name && item.full_name.length > 0) { if (item.full_name && item.full_name.length > 0) {
title += ' (' + htmlEncode(item.full_name) + ')'; title += ' (' + htmlEncode(item.full_name) + ')';
@ -1728,7 +1719,7 @@ function searchRepositories() {
url: suburl + '/api/v1/repos/search?q={query}&uid=' + $searchRepoBox.data('uid'), url: suburl + '/api/v1/repos/search?q={query}&uid=' + $searchRepoBox.data('uid'),
onResponse: function(response) { onResponse: function(response) {
var items = []; var items = [];
$.each(response.data, function (i, item) { $.each(response.data, function (_i, item) {
items.push({ items.push({
title: item.full_name.split("/")[1], title: item.full_name.split("/")[1],
description: item.full_name description: item.full_name
@ -1752,8 +1743,8 @@ function initCodeView() {
deSelect(); deSelect();
}); });
$(window).on('hashchange', function (e) { $(window).on('hashchange', function () {
var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/); var m = window.location.hash.match(/^#(L\d+)-(L\d+)$/);
var $list = $('.code-view ol.linenums > li'); var $list = $('.code-view ol.linenums > li');
var $first; var $first;
if (m) { if (m) {
@ -1803,7 +1794,7 @@ function u2fSigned(resp) {
contentType: "application/json; charset=utf-8", contentType: "application/json; charset=utf-8",
}).done(function(res){ }).done(function(res){
window.location.replace(res); window.location.replace(res);
}).fail(function (xhr, textStatus) { }).fail(function () {
u2fError(1); u2fError(1);
}); });
} }
@ -1821,7 +1812,7 @@ function u2fRegistered(resp) {
success: function(){ success: function(){
reload(); reload();
}, },
fail: function (xhr, textStatus) { fail: function () {
u2fError(1); u2fError(1);
} }
}); });
@ -1889,7 +1880,7 @@ function u2fRegisterRequest() {
} }
u2fError(reason.metaData.code); u2fError(reason.metaData.code);
}); });
}).fail(function(xhr, status, error) { }).fail(function(xhr) {
if(xhr.status === 409) { if(xhr.status === 409) {
$("#nickname").closest("div.field").addClass("error"); $("#nickname").closest("div.field").addClass("error");
} }
@ -1962,7 +1953,7 @@ $(document).ready(function () {
}); });
// make table <tr> element clickable like a link // make table <tr> element clickable like a link
$('tr[data-href]').click(function(event) { $('tr[data-href]').click(function() {
window.location = $(this).data('href'); window.location = $(this).data('href');
}); });
@ -2388,7 +2379,7 @@ function initVueComponents(){
var searchedURL = this.searchURL; var searchedURL = this.searchURL;
var searchedQuery = this.searchQuery; var searchedQuery = this.searchQuery;
$.getJSON(searchedURL, function(result, textStatus, request) { $.getJSON(searchedURL, function(result, _textStatus, request) {
if (searchedURL == self.searchURL) { if (searchedURL == self.searchURL) {
self.repos = result.data; self.repos = result.data;
var count = request.getResponseHeader('X-Total-Count'); var count = request.getResponseHeader('X-Total-Count');
@ -2446,6 +2437,7 @@ function initVueApp() {
}, },
}); });
} }
function timeAddManual() { function timeAddManual() {
$('.mini.modal') $('.mini.modal')
.modal({ .modal({
@ -2796,7 +2788,7 @@ function initTopicbar() {
$.post(saveBtn.data('link'), { $.post(saveBtn.data('link'), {
"_csrf": csrf, "_csrf": csrf,
"topics": topics "topics": topics
}, function(data, textStatus, xhr){ }, function(_data, _textStatus, xhr){
if (xhr.responseJSON.status === 'ok') { if (xhr.responseJSON.status === 'ok') {
viewDiv.children(".topic").remove(); viewDiv.children(".topic").remove();
if (topics.length) { if (topics.length) {
@ -2873,14 +2865,14 @@ function initTopicbar() {
this.attr("data-value", value).contents().first().replaceWith(value); this.attr("data-value", value).contents().first().replaceWith(value);
return $(this); return $(this);
}, },
onAdd: function(addedValue, addedText, $addedChoice) { onAdd: function(addedValue, _addedText, $addedChoice) {
addedValue = addedValue.toLowerCase().trim(); addedValue = addedValue.toLowerCase().trim();
$($addedChoice).attr('data-value', addedValue); $($addedChoice).attr('data-value', addedValue);
$($addedChoice).attr('data-text', addedValue); $($addedChoice).attr('data-text', addedValue);
} }
}); });
$.fn.form.settings.rules.validateTopic = function(values, regExp) { $.fn.form.settings.rules.validateTopic = function(_values, regExp) {
var topics = topicDropdown.children('a.ui.label'), var topics = topicDropdown.children('a.ui.label'),
status = topics.length === 0 || topics.last().attr("data-value").match(regExp); status = topics.length === 0 || topics.last().attr("data-value").match(regExp);
if (!status) { if (!status) {
@ -2981,7 +2973,7 @@ function initIssueList() {
var filteredResponse = {'success': true, 'results': []}; var filteredResponse = {'success': true, 'results': []};
var currIssueId = $('#new-dependency-drop-list').data('issue-id'); var currIssueId = $('#new-dependency-drop-list').data('issue-id');
// Parse the response from the api to work with our dropdown // Parse the response from the api to work with our dropdown
$.each(response, function(index, issue) { $.each(response, function(_i, issue) {
// Don't list current issue in the dependency list. // Don't list current issue in the dependency list.
if(issue.id === currIssueId) { if(issue.id === currIssueId) {
return; return;