diff --git a/Gruntfile.js b/Gruntfile.js index 20a533ca5..24bbaf1a6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -129,6 +129,27 @@ module.exports = function (grunt) { } }, + jshint: { + options: { + '-W030': false, + '-W064': false, + '-W097': false, + '-W100': false, + 'undef': true, + 'globals': { + 'require': true, + 'define': true, + 'window': true, + 'document': true, + 'console': true + } + }, + all: [ + srcRoot + '**/*.js', + '!**/JsLibraries/*.js' + ] + }, + requirejs: { compile:{ options: { @@ -184,6 +205,7 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-notify'); grunt.loadNpmTasks('grunt-curl'); grunt.loadNpmTasks('grunt-contrib-requirejs'); + grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('package', ['clean:output','handlebars', 'copy', 'less']); grunt.registerTask('packagerjs', ['clean:output','handlebars', 'requirejs', 'copy:content', 'less']); diff --git a/src/UI/AddSeries/AddSeriesView.js b/src/UI/AddSeries/AddSeriesView.js index 1f96de134..179cc4a52 100644 --- a/src/UI/AddSeries/AddSeriesView.js +++ b/src/UI/AddSeries/AddSeriesView.js @@ -80,7 +80,7 @@ define( this.collection.reset(); if (!options.term || options.term === this.collection.term) { - return $.Deferred().resolve(); + return Marionette.$.Deferred().resolve(); } this.searchResult.show(new LoadingView()); diff --git a/src/UI/AddSeries/Existing/UnmappedFolderCollection.js b/src/UI/AddSeries/Existing/UnmappedFolderCollection.js index a6328a521..cbebd6af7 100644 --- a/src/UI/AddSeries/Existing/UnmappedFolderCollection.js +++ b/src/UI/AddSeries/Existing/UnmappedFolderCollection.js @@ -2,8 +2,9 @@ define( [ 'backbone', - 'AddSeries/Existing/UnmappedFolderModel' - ], function (Backbone, UnmappedFolderModel) { + 'AddSeries/Existing/UnmappedFolderModel', + 'underscore' + ], function (Backbone, UnmappedFolderModel,_) { return Backbone.Collection.extend({ model: UnmappedFolderModel, diff --git a/src/UI/Calendar/CalendarView.js b/src/UI/Calendar/CalendarView.js index 0d4422845..727c8f578 100644 --- a/src/UI/Calendar/CalendarView.js +++ b/src/UI/Calendar/CalendarView.js @@ -7,7 +7,7 @@ define( 'moment', 'Calendar/Collection', 'fullcalendar' - ], function (vent, Marionette, Moment, CalendarCollection) { + ], function (vent, Marionette, moment, CalendarCollection) { var _instance; @@ -16,7 +16,10 @@ define( this.collection = new CalendarCollection(); }, render : function () { - $(this.$el).empty().fullCalendar({ + + var self = this; + + this.$el.empty().fullCalendar({ defaultView : 'basicWeek', allDayDefault : false, ignoreTimezone: false, @@ -34,8 +37,8 @@ define( }, events : this.getEvents, eventRender : function (event, element) { - $(element).addClass(event.statusLevel); - $(element).children('.fc-event-inner').addClass(event.statusLevel); + self.$(element).addClass(event.statusLevel); + self.$(element).children('.fc-event-inner').addClass(event.statusLevel); }, eventClick : function (event) { vent.trigger(vent.Commands.ShowEpisodeDetails, {episode: event.model}); @@ -50,8 +53,8 @@ define( }, getEvents: function (start, end, callback) { - var startDate = Moment(start).toISOString(); - var endDate = Moment(end).toISOString(); + var startDate = moment(start).toISOString(); + var endDate = moment(end).toISOString(); _instance.collection.fetch({ data : { start: startDate, end: endDate }, @@ -61,7 +64,7 @@ define( var seriesTitle = element.get('series').title; var start = element.get('airDateUtc'); var runtime = element.get('series').runtime; - var end = Moment(start).add('minutes', runtime).toISOString(); + var end = moment(start).add('minutes', runtime).toISOString(); element.set({ @@ -83,9 +86,9 @@ define( getStatusLevel: function (element) { var hasFile = element.get('hasFile'); - var currentTime = Moment(); - var start = Moment(element.get('airDateUtc')); - var end = Moment(element.get('end')); + var currentTime = moment(); + var start = moment(element.get('airDateUtc')); + var end = moment(element.get('end')); var statusLevel = 'primary'; @@ -94,10 +97,6 @@ define( } else if (currentTime.isAfter(start) && currentTime.isBefore(end)) { - var s = start.toISOString(); - var e = end.toISOString(); - var c = currentTime.toISOString(); - statusLevel = 'warning'; } diff --git a/src/UI/Cells/EpisodeNumberCell.js b/src/UI/Cells/EpisodeNumberCell.js index 0daf55b81..41a034ba2 100644 --- a/src/UI/Cells/EpisodeNumberCell.js +++ b/src/UI/Cells/EpisodeNumberCell.js @@ -3,8 +3,9 @@ define( [ 'Cells/NzbDroneCell', - 'Shared/FormatHelpers' - ], function (NzbDroneCell, FormatHelpers) { + 'Shared/FormatHelpers', + 'underscore' + ], function (NzbDroneCell, FormatHelpers, _) { return NzbDroneCell.extend({ className: 'episode-number-cell', diff --git a/src/UI/Cells/NzbDroneCell.js b/src/UI/Cells/NzbDroneCell.js index e5e6c595e..15bd99e76 100644 --- a/src/UI/Cells/NzbDroneCell.js +++ b/src/UI/Cells/NzbDroneCell.js @@ -2,8 +2,9 @@ define( [ - 'backgrid' - ], function (Backgrid) { + 'backgrid', + 'backbone' + ], function (Backgrid, Backbone) { return Backgrid.Cell.extend({ _originalInit: Backgrid.Cell.prototype.initialize, @@ -15,8 +16,8 @@ define( this.listenTo(this.model, 'change', this._refresh); if (this._onEdit) { - this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) { - if (column.get("name") == this.column.get("name")) { + this.listenTo(this.model, 'backgrid:edit', function (model, column, cell, editor) { + if (column.get('name') === this.column.get('name')) { this._onEdit(model, column, cell, editor); } }); diff --git a/src/UI/Cells/QualityProfileCell.js b/src/UI/Cells/QualityProfileCell.js index 292a1dd41..7cd6efd88 100644 --- a/src/UI/Cells/QualityProfileCell.js +++ b/src/UI/Cells/QualityProfileCell.js @@ -2,8 +2,9 @@ define( [ 'backgrid', - 'Quality/QualityProfileCollection' - ], function (Backgrid, QualityProfileCollection) { + 'Quality/QualityProfileCollection', + 'underscore' + ], function (Backgrid, QualityProfileCollection,_) { return Backgrid.Cell.extend({ className: 'quality-profile-cell', diff --git a/src/UI/Config.js b/src/UI/Config.js index f1bbf757c..7721fa79f 100644 --- a/src/UI/Config.js +++ b/src/UI/Config.js @@ -18,7 +18,7 @@ define( getValue: function (key, defaultValue) { - var storeValue = localStorage.getItem(key); + var storeValue = window.localStorage.getItem(key); if (!storeValue) { return defaultValue; @@ -35,7 +35,7 @@ define( return; } - localStorage.setItem(key, value); + window.localStorage.setItem(key, value); vent.trigger(this.Events.ConfigUpdatedEvent, {key: key, value: value}); } diff --git a/src/UI/Form/FormBuilder.js b/src/UI/Form/FormBuilder.js index c0d4535ff..bb391f162 100644 --- a/src/UI/Form/FormBuilder.js +++ b/src/UI/Form/FormBuilder.js @@ -1,8 +1,10 @@ 'use strict'; define( [ - 'handlebars' - ], function (Handlebars) { + 'marionette', + 'handlebars', + 'underscore' + ], function (Marionette, Handlebars, _) { var _fieldBuilder = function (field) { if (!field.type) { diff --git a/src/UI/Instrumentation/ErrorHandler.js b/src/UI/Instrumentation/ErrorHandler.js index 92ccd4db1..80fc27441 100644 --- a/src/UI/Instrumentation/ErrorHandler.js +++ b/src/UI/Instrumentation/ErrorHandler.js @@ -38,7 +38,7 @@ return false; //don't suppress default alerts and logs. }; - $(document).ajaxError(function (event, xmlHttpRequest, ajaxOptions) { + window.$(document).ajaxError(function (event, xmlHttpRequest, ajaxOptions) { //don't report 200 error codes if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status <= 300) { diff --git a/src/UI/Mixins/AutoComplete.js b/src/UI/Mixins/AutoComplete.js index 7903cef05..a80610313 100644 --- a/src/UI/Mixins/AutoComplete.js +++ b/src/UI/Mixins/AutoComplete.js @@ -1,6 +1,6 @@ 'use strict'; -define(function () { +define(['jquery'],function ($) { $.fn.autoComplete = function (resource) { $(this).typeahead({ diff --git a/src/UI/Navbar/NavbarView.js b/src/UI/Navbar/NavbarView.js index 85ca28cb6..fce2d5268 100644 --- a/src/UI/Navbar/NavbarView.js +++ b/src/UI/Navbar/NavbarView.js @@ -2,10 +2,11 @@ define( [ 'marionette', - 'Navbar/Search' - ], function (Marionette) { + 'Navbar/Search', + 'jquery' + ], function (Marionette, $) { return Marionette.ItemView.extend({ - template : 'Navbar/NavbarTemplate', + template: 'Navbar/NavbarTemplate', ui: { search: '.x-series-search' @@ -15,7 +16,7 @@ define( 'click a': 'onClick' }, - onRender: function (){ + onRender: function () { this.ui.search.bindSearch(); }, diff --git a/src/UI/Quality/QualitySizeCollection.js b/src/UI/Quality/QualitySizeCollection.js index b29fc62f7..92c580647 100644 --- a/src/UI/Quality/QualitySizeCollection.js +++ b/src/UI/Quality/QualitySizeCollection.js @@ -1,8 +1,9 @@ 'use strict'; define( [ + 'backbone', 'Quality/QualitySizeModel' - ], function (QualitySizeModel) { + ], function (Backbone, QualitySizeModel) { return Backbone.Collection.extend({ model: QualitySizeModel, url : window.NzbDrone.ApiRoot + '/qualitysize' diff --git a/src/UI/Require/require.api.js b/src/UI/Require/require.api.js index e3d855279..920cb76b0 100644 --- a/src/UI/Require/require.api.js +++ b/src/UI/Require/require.api.js @@ -1,9 +1,12 @@ -define(function () { +define( + [ + 'jquery' + ], function ($) { 'use strict'; return { load: function (name, parentRequire, onload, config) { - if(config.isBuild){ + if (config.isBuild) { return onload(); } @@ -19,7 +22,7 @@ define(function () { xhr : xhr, status: status, error : error}); - }); + }); } }; }); diff --git a/src/UI/SeasonPass/SeriesLayout.js b/src/UI/SeasonPass/SeriesLayout.js index 828f25341..b4e6d3bff 100644 --- a/src/UI/SeasonPass/SeriesLayout.js +++ b/src/UI/SeasonPass/SeriesLayout.js @@ -112,13 +112,13 @@ define( var element; if (e.target.localName === 'i') { - seasonNumber = parseInt($(e.target).parent('td').attr('data-season-number'), 10); - element = $(e.target); + seasonNumber = parseInt(this.$(e.target).parent('td').attr('data-season-number'), 10); + element = this.$(e.target); } else { - seasonNumber = parseInt($(e.target).attr('data-season-number'), 10); - element = $(e.target).children('i'); + seasonNumber = parseInt(this.$(e.target).attr('data-season-number'), 10); + element = this.$(e.target).children('i'); } this.model.setSeasonMonitored(seasonNumber); @@ -146,7 +146,7 @@ define( } }, - _toggleSeriesMonitored: function (e) { + _toggleSeriesMonitored: function () { var savePromise = this.model.save('monitored', !this.model.get('monitored'), { wait: true }); diff --git a/src/UI/Series/Details/SeriesDetailsLayout.js b/src/UI/Series/Details/SeriesDetailsLayout.js index e2b4ce627..b04aa0aa9 100644 --- a/src/UI/Series/Details/SeriesDetailsLayout.js +++ b/src/UI/Series/Details/SeriesDetailsLayout.js @@ -1,6 +1,7 @@ 'use strict'; define( [ + 'jquery', 'vent', 'reqres', 'marionette', @@ -15,7 +16,7 @@ define( 'underscore', 'backstrech', 'Mixins/backbone.signalr.mixin' - ], function (vent,reqres, Marionette, Backbone, EpisodeCollection, EpisodeFileCollection, SeasonCollection, SeasonCollectionView, InfoView, CommandController, LoadingView, _) { + ], function ($,vent,reqres, Marionette, Backbone, EpisodeCollection, EpisodeFileCollection, SeasonCollection, SeasonCollectionView, InfoView, CommandController, LoadingView, _) { return Marionette.Layout.extend({ itemViewContainer: '.x-series-seasons', diff --git a/src/UI/Series/EpisodeCollection.js b/src/UI/Series/EpisodeCollection.js index 3bd6d9979..8c72b2440 100644 --- a/src/UI/Series/EpisodeCollection.js +++ b/src/UI/Series/EpisodeCollection.js @@ -54,7 +54,7 @@ define( options = {}; } - options['data'] = { seriesId: this.seriesId }; + options.data = { seriesId: this.seriesId }; return this.originalFetch.call(this, options); } diff --git a/src/UI/Series/EpisodeFileCollection.js b/src/UI/Series/EpisodeFileCollection.js index 5cd65aaad..42472d0ed 100644 --- a/src/UI/Series/EpisodeFileCollection.js +++ b/src/UI/Series/EpisodeFileCollection.js @@ -23,7 +23,7 @@ define( options = {}; } - options['data'] = { seriesId: this.seriesId }; + options.data = { seriesId: this.seriesId }; return this.originalFetch.call(this, options); } diff --git a/src/UI/Series/Index/SeriesIndexLayout.js b/src/UI/Series/Index/SeriesIndexLayout.js index 704e7f725..6a78e0754 100644 --- a/src/UI/Series/Index/SeriesIndexLayout.js +++ b/src/UI/Series/Index/SeriesIndexLayout.js @@ -2,6 +2,7 @@ define( [ 'marionette', + 'backgrid', 'Series/Index/Posters/CollectionView', 'Series/Index/List/CollectionView', 'Series/Index/EmptyView', @@ -16,8 +17,10 @@ define( 'Cells/SeriesStatusCell', 'Series/Index/FooterView', 'Series/Index/FooterModel', - 'Shared/Toolbar/ToolbarLayout' + 'Shared/Toolbar/ToolbarLayout', + 'underscore' ], function (Marionette, + Backgrid, PosterCollectionView, ListCollectionView, EmptyView, @@ -32,7 +35,8 @@ define( SeriesStatusCell, FooterView, FooterModel, - ToolbarLayout) { + ToolbarLayout, + _) { return Marionette.Layout.extend({ template: 'Series/Index/SeriesIndexLayoutTemplate', diff --git a/src/UI/ServerStatus.js b/src/UI/ServerStatus.js index 589d45fc6..95e1fd968 100644 --- a/src/UI/ServerStatus.js +++ b/src/UI/ServerStatus.js @@ -1,6 +1,6 @@ window.NzbDrone.ApiRoot = '/api'; -var statusText = $.ajax({ +var statusText = window.$.ajax({ type : 'GET', url : window.NzbDrone.ApiRoot + '/system/status', async: false, @@ -13,10 +13,13 @@ window.NzbDrone.ServerStatus = JSON.parse(statusText); var footerText = window.NzbDrone.ServerStatus.version; -$(document).ready(function () { - if (window.NzbDrone.ServerStatus.branch != 'master') { +window.$(document).ready(function () { + if (window.NzbDrone.ServerStatus.branch !== 'master') { footerText += '' + window.NzbDrone.ServerStatus.branch; } - $('#footer-region .version').html(footerText); + window.$('#footer-region .version').html(footerText); }); + + + diff --git a/src/UI/Settings/SettingsLayout.js b/src/UI/Settings/SettingsLayout.js index f03ac5416..20ae6912d 100644 --- a/src/UI/Settings/SettingsLayout.js +++ b/src/UI/Settings/SettingsLayout.js @@ -83,7 +83,7 @@ define( this.indexerSettings = new IndexerCollection(); this.notificationSettings = new NotificationCollection(); - $.when(this.settings.fetch(), + Backbone.$.when(this.settings.fetch(), this.generalSettings.fetch(), this.namingSettings.fetch(), this.indexerSettings.fetch(), diff --git a/src/UI/Shared/FormatHelpers.js b/src/UI/Shared/FormatHelpers.js index c29e1606a..badfc18f3 100644 --- a/src/UI/Shared/FormatHelpers.js +++ b/src/UI/Shared/FormatHelpers.js @@ -51,7 +51,7 @@ define( return ''; } - return input.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return input.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } - } + }; }); diff --git a/src/UI/Shared/Grid/Pager.js b/src/UI/Shared/Grid/Pager.js index 7ddfe4ab5..e230f8d1d 100644 --- a/src/UI/Shared/Grid/Pager.js +++ b/src/UI/Shared/Grid/Pager.js @@ -1,8 +1,9 @@ 'use strict'; define( [ + 'marionette', 'backgrid.paginator' - ], function (Paginator) { + ], function (Marionette, Paginator) { return Paginator.extend({ @@ -24,7 +25,7 @@ define( changePage: function (e) { e.preventDefault(); - var target = $(e.target); + var target =this.$(e.target); if (target.closest('li').hasClass('disabled')) { return; @@ -59,7 +60,7 @@ define( } var state = collection.state; - var pageIndex = $(e.target).text() * 1; + var pageIndex = target.text(); collection.getPage(state.firstPage === 0 ? pageIndex - 1 :pageIndex); }, diff --git a/src/UI/Shared/NzbDroneController.js b/src/UI/Shared/NzbDroneController.js index 2ff57cfd4..f5c0adcf1 100644 --- a/src/UI/Shared/NzbDroneController.js +++ b/src/UI/Shared/NzbDroneController.js @@ -14,10 +14,10 @@ define( setTitle: function (title) { if (title.toLocaleLowerCase() === 'nzbdrone') { - window.document.title = 'NzbDrone'; + document.title = 'NzbDrone'; } else { - window.document.title = title + ' - NzbDrone'; + document.title = title + ' - NzbDrone'; } } }); diff --git a/src/UI/Shared/SignalRBroadcaster.js b/src/UI/Shared/SignalRBroadcaster.js index 453b08843..55b0c2b31 100644 --- a/src/UI/Shared/SignalRBroadcaster.js +++ b/src/UI/Shared/SignalRBroadcaster.js @@ -2,8 +2,9 @@ define( [ 'vent', + 'jquery', 'signalR' - ], function (vent) { + ], function (vent, $) { return { appInitializer: function () { diff --git a/src/UI/Shared/Toolbar/ToolbarLayout.js b/src/UI/Shared/Toolbar/ToolbarLayout.js index 8945337a2..7f4b64bf9 100644 --- a/src/UI/Shared/Toolbar/ToolbarLayout.js +++ b/src/UI/Shared/Toolbar/ToolbarLayout.js @@ -5,8 +5,9 @@ define( 'Shared/Toolbar/ButtonCollection', 'Shared/Toolbar/ButtonModel', 'Shared/Toolbar/Radio/RadioButtonCollectionView', - 'Shared/Toolbar/Button/ButtonCollectionView' - ], function (Marionette, ButtonCollection, ButtonModel, RadioButtonCollectionView, ButtonCollectionView) { + 'Shared/Toolbar/Button/ButtonCollectionView', + 'underscore' + ], function (Marionette, ButtonCollection, ButtonModel, RadioButtonCollectionView, ButtonCollectionView,_) { return Marionette.Layout.extend({ template: 'Shared/Toolbar/ToolbarLayoutTemplate', diff --git a/src/UI/System/Logs/Files/LogFileCollection.js b/src/UI/System/Logs/Files/LogFileCollection.js index b26a983fe..88fefca42 100644 --- a/src/UI/System/Logs/Files/LogFileCollection.js +++ b/src/UI/System/Logs/Files/LogFileCollection.js @@ -1,14 +1,17 @@ -'use strict'; +'use strict'; -define(['System/Logs/Files/LogFileModel' ], -function (LogFileModel) { - return Backbone.Collection.extend({ - url : window.NzbDrone.ApiRoot + '/log/files', - model: LogFileModel, +define( + [ + 'backbone', + 'System/Logs/Files/LogFileModel' + ], function (Backbone, LogFileModel) { + return Backbone.Collection.extend({ + url : window.NzbDrone.ApiRoot + '/log/files', + model: LogFileModel, - state: { - sortKey : 'lastWriteTime', - order : 1 - } + state: { + sortKey: 'lastWriteTime', + order : 1 + } + }); }); -}); diff --git a/src/UI/app.js b/src/UI/app.js index 490f4c5d9..18e2a9454 100644 --- a/src/UI/app.js +++ b/src/UI/app.js @@ -99,8 +99,8 @@ require.config({ exports: 'Marionette', init : function (Backbone, TemplateMixin, AsNamedView) { - TemplateMixin.call(Marionette.TemplateCache); - AsNamedView.call(Marionette.ItemView.prototype); + TemplateMixin.call(window.Marionette.TemplateCache); + AsNamedView.call(window.Marionette.ItemView.prototype); } }, @@ -140,7 +140,7 @@ require.config({ 'Shared/Grid/HeaderCell' ], function () { - Backgrid.Column.prototype.defaults = { + window.Backgrid.Column.prototype.defaults = { name : undefined, label : undefined, sortable : true, diff --git a/src/UI/jQuery/RouteBinder.js b/src/UI/jQuery/RouteBinder.js index fcd7effeb..8a1fac21f 100644 --- a/src/UI/jQuery/RouteBinder.js +++ b/src/UI/jQuery/RouteBinder.js @@ -1,55 +1,59 @@ 'use strict'; -define(['backbone'],function (Backbone) { - //This module will automatically route all relative links through backbone router rather than - //causing links to reload pages. +define( + [ + 'backbone', + 'jquery' + ], function (Backbone,$) { + //This module will automatically route all relative links through backbone router rather than + //causing links to reload pages. - var routeBinder = { + var routeBinder = { - bind: function () { - var self = this; - $(document).on('click', 'a[href]', function (event) { - self._handleClick(event); - }); - }, + bind: function () { + var self = this; + $(document).on('click', 'a[href]', function (event) { + self._handleClick(event); + }); + }, - _handleClick: function (event) { - var $target = $(event.target); + _handleClick: function (event) { + var $target = $(event.target); - //check if tab nav - if ($target.parents('.nav-tabs').length) { - return; + //check if tab nav + if ($target.parents('.nav-tabs').length) { + return; + } + + if ($target.hasClass('no-router')) { + return; + } + + event.preventDefault(); + + var href = event.target.getAttribute('href'); + + if (!href && $target.parent('a') && $target.parent('a')[0]) { + + var linkElement = $target.parent('a')[0]; + + href = linkElement.getAttribute('href'); + } + + if (!href) { + throw 'couldn\'t find route target'; + } + + + if (!href.startsWith('http')) { + Backbone.history.navigate(href, { trigger: true }); + } + + else { + //Open in new tab + window.open(href, '_blank'); + } } + }; - if ($target.hasClass('no-router')) { - return; - } - - event.preventDefault(); - - var href = event.target.getAttribute('href'); - - if (!href && $target.parent('a') && $target.parent('a')[0]) { - - var linkElement = $target.parent('a')[0]; - - href = linkElement.getAttribute('href'); - } - - if (!href) { - throw 'couldn\'t find route target'; - } - - - if (!href.startsWith('http')) { - Backbone.history.navigate(href, { trigger: true }); - } - - else { - //Open in new tab - window.open(href, '_blank'); - } - } - }; - - return routeBinder; -}); + return routeBinder; + }); diff --git a/src/UI/jQuery/jquery.validation.js b/src/UI/jQuery/jquery.validation.js index 6f94a50db..362dffaef 100644 --- a/src/UI/jQuery/jquery.validation.js +++ b/src/UI/jQuery/jquery.validation.js @@ -50,7 +50,7 @@ define( }; $.fn.addFormError = function (error) { - this.find('.control-group').parent().prepend('