From 70bfad4e6a35ca0073b58d29b8aa304ff6b5dc42 Mon Sep 17 00:00:00 2001 From: Taloth Saldono Date: Fri, 13 Feb 2015 22:06:20 +0100 Subject: [PATCH] UI Cleanup - Updated Instrumentation, jQuery and Mixins subtrees. --- src/UI/Hotkeys/Hotkeys.js | 57 ++--- src/UI/Hotkeys/HotkeysView.js | 4 +- src/UI/Instrumentation/ErrorHandler.js | 129 ++++++----- src/UI/Instrumentation/StringFormat.js | 11 +- src/UI/Mixins/AsChangeTrackingModel.js | 16 +- src/UI/Mixins/AsEditModalView.js | 69 ++++-- src/UI/Mixins/AsFilteredCollection.js | 37 +-- src/UI/Mixins/AsModelBoundView.js | 35 ++- src/UI/Mixins/AsNamedView.js | 14 +- src/UI/Mixins/AsPersistedStateCollection.js | 43 ++-- src/UI/Mixins/AsSortedCollection.js | 78 +++++-- src/UI/Mixins/AsSortedCollectionView.js | 16 +- src/UI/Mixins/AsValidatedView.js | 66 ++++-- src/UI/Mixins/AutoComplete.js | 92 ++++---- src/UI/Mixins/CopyToClipboard.js | 4 +- src/UI/Mixins/DirectoryAutoComplete.js | 37 +-- src/UI/Mixins/FileBrowser.js | 50 ++-- src/UI/Mixins/TagInput.js | 245 +++++++++++--------- src/UI/Mixins/backbone.signalr.mixin.js | 24 +- src/UI/jQuery/RouteBinder.js | 50 ++-- src/UI/jQuery/ToTheTop.js | 14 +- src/UI/jQuery/jquery.ajax.js | 13 +- src/UI/jQuery/jquery.spin.js | 37 ++- src/UI/jQuery/jquery.validation.js | 65 ++++-- 24 files changed, 716 insertions(+), 490 deletions(-) diff --git a/src/UI/Hotkeys/Hotkeys.js b/src/UI/Hotkeys/Hotkeys.js index fc92a14ad..b72a574da 100644 --- a/src/UI/Hotkeys/Hotkeys.js +++ b/src/UI/Hotkeys/Hotkeys.js @@ -2,30 +2,33 @@ var $ = require('jquery'); var vent = require('vent'); var HotkeysView = require('./HotkeysView'); -module.exports = (function(){ - $(document).on('keypress', function(e){ - if($(e.target).is('input') || $(e.target).is('textarea')) { - return; - } - if(e.charCode === 63) { - vent.trigger(vent.Commands.OpenModalCommand, new HotkeysView()); - } - }); - $(document).on('keydown', function(e){ - if(e.ctrlKey && e.keyCode === 83) { - vent.trigger(vent.Hotkeys.SaveSettings); - e.preventDefault(); - return; - } - if($(e.target).is('input') || $(e.target).is('textarea')) { - return; - } - if(e.ctrlKey || e.metaKey || e.altKey) { - return; - } - if(e.keyCode === 84) { - vent.trigger(vent.Hotkeys.NavbarSearch); - e.preventDefault(); - } - }); -}).call(this); \ No newline at end of file +$(document).on('keypress', function(e) { + if ($(e.target).is('input') || $(e.target).is('textarea')) { + return; + } + + if (e.charCode === 63) { + vent.trigger(vent.Commands.OpenModalCommand, new HotkeysView()); + } +}); + +$(document).on('keydown', function(e) { + if (e.ctrlKey && e.keyCode === 83) { + vent.trigger(vent.Hotkeys.SaveSettings); + e.preventDefault(); + return; + } + + if ($(e.target).is('input') || $(e.target).is('textarea')) { + return; + } + + if (e.ctrlKey || e.metaKey || e.altKey) { + return; + } + + if (e.keyCode === 84) { + vent.trigger(vent.Hotkeys.NavbarSearch); + e.preventDefault(); + } +}); diff --git a/src/UI/Hotkeys/HotkeysView.js b/src/UI/Hotkeys/HotkeysView.js index 69a1764b0..ee643fbb2 100644 --- a/src/UI/Hotkeys/HotkeysView.js +++ b/src/UI/Hotkeys/HotkeysView.js @@ -1,4 +1,6 @@ var vent = require('vent'); var Marionette = require('marionette'); -module.exports = Marionette.ItemView.extend({template : 'Hotkeys/HotkeysViewTemplate'}); +module.exports = Marionette.ItemView.extend({ + template : 'Hotkeys/HotkeysViewTemplate' +}); \ No newline at end of file diff --git a/src/UI/Instrumentation/ErrorHandler.js b/src/UI/Instrumentation/ErrorHandler.js index 06a6e495f..189173662 100644 --- a/src/UI/Instrumentation/ErrorHandler.js +++ b/src/UI/Instrumentation/ErrorHandler.js @@ -1,69 +1,86 @@ var $ = require('jquery'); var Messenger = require('messenger'); -module.exports = (function(){ - 'use strict'; - window.alert = function(message){ - new Messenger().post(message); - }; - var addError = function(message){ - $('#errors').append('
' + message + '
'); - }; - window.onerror = function(msg, url, line){ - try { - var a = document.createElement('a'); - a.href = url; - var filename = a.pathname.split('/').pop(); - if(filename.toLowerCase() === 'markupview.jsm' || filename.toLowerCase() === 'markup-view.js') { - return false; - } - var messageText = filename + ' : ' + line + '
' + msg; - var message = { - message : messageText, - type : 'error', - hideAfter : 1000, - showCloseButton : true - }; - new Messenger().post(message); - addError(message.message); - } - catch (error) { - console.log('An error occurred while reporting error. ' + error); - console.log(msg); - new Messenger().post('Couldn\'t report JS error. ' + msg); - } - return false; - }; +window.alert = function(message) { + new Messenger().post(message); +}; - $(document).ajaxError(function(event, xmlHttpRequest, ajaxOptions){ - if(xmlHttpRequest.status >= 200 && xmlHttpRequest.status <= 300) { - return undefined; - } - if(xmlHttpRequest.statusText === 'abort') { - return undefined; +var addError = function(message) { + $('#errors').append('
' + message + '
'); +}; + +window.onerror = function(msg, url, line) { + + try { + + var a = document.createElement('a'); + a.href = url; + var filename = a.pathname.split('/').pop(); + + //Suppress Firefox debug errors when console window is closed + if (filename.toLowerCase() === 'markupview.jsm' || filename.toLowerCase() === 'markup-view.js') { + return false; } + + var messageText = filename + ' : ' + line + '
' + msg; + var message = { + message : messageText, type : 'error', hideAfter : 1000, showCloseButton : true }; - if(xmlHttpRequest.status === 0 && xmlHttpRequest.readyState === 0) { - return false; - } - if(xmlHttpRequest.status === 400 && ajaxOptions.isValidatedCall) { - return false; - } - if(xmlHttpRequest.status === 503) { - message.message = xmlHttpRequest.responseJSON.message; - } - if(xmlHttpRequest.status === 409) { - message.message = xmlHttpRequest.responseJSON.message; - } - else { - message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url); - } + new Messenger().post(message); + addError(message.message); + + } + catch (error) { + console.log('An error occurred while reporting error. ' + error); + console.log(msg); + new Messenger().post('Couldn\'t report JS error. ' + msg); + } + + return false; //don't suppress default alerts and logs. +}; + +$(document).ajaxError(function(event, xmlHttpRequest, ajaxOptions) { + + //don't report 200 error codes + if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status <= 300) { + return undefined; + } + + //don't report aborted requests + if (xmlHttpRequest.statusText === 'abort') { + return undefined; + } + + var message = { + type : 'error', + hideAfter : 1000, + showCloseButton : true + }; + + if (xmlHttpRequest.status === 0 && xmlHttpRequest.readyState === 0) { return false; - }); -}).call(this); \ No newline at end of file + } + + if (xmlHttpRequest.status === 400 && ajaxOptions.isValidatedCall) { + return false; + } + + if (xmlHttpRequest.status === 503) { + message.message = xmlHttpRequest.responseJSON.message; + } else if (xmlHttpRequest.status === 409) { + message.message = xmlHttpRequest.responseJSON.message; + } else { + message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url); + } + + new Messenger().post(message); + addError(message.message); + + return false; +}); \ No newline at end of file diff --git a/src/UI/Instrumentation/StringFormat.js b/src/UI/Instrumentation/StringFormat.js index d3a5595a3..059d25f5e 100644 --- a/src/UI/Instrumentation/StringFormat.js +++ b/src/UI/Instrumentation/StringFormat.js @@ -1,11 +1,12 @@ 'use strict'; -String.prototype.format = function(){ + +String.prototype.format = function() { var args = arguments; - return this.replace(/{(\d+)}/g, function(match, number){ - if(typeof args[number] !== 'undefined') { + + return this.replace(/{(\d+)}/g, function(match, number) { + if (typeof args[number] !== 'undefined') { return args[number]; - } - else { + } else { return match; } }); diff --git a/src/UI/Mixins/AsChangeTrackingModel.js b/src/UI/Mixins/AsChangeTrackingModel.js index 6bbbccaff..b3524b244 100644 --- a/src/UI/Mixins/AsChangeTrackingModel.js +++ b/src/UI/Mixins/AsChangeTrackingModel.js @@ -1,16 +1,22 @@ -module.exports = function(){ +module.exports = function() { var originalInit = this.prototype.initialize; - this.prototype.initialize = function(){ + + this.prototype.initialize = function() { + this.isSaved = true; - this.on('change', function(){ + + this.on('change', function() { this.isSaved = false; }, this); - this.on('sync', function(){ + + this.on('sync', function() { this.isSaved = true; }, this); - if(originalInit) { + + if (originalInit) { originalInit.call(this); } }; + return this; }; \ No newline at end of file diff --git a/src/UI/Mixins/AsEditModalView.js b/src/UI/Mixins/AsEditModalView.js index 8098df059..cb3b0df36 100644 --- a/src/UI/Mixins/AsEditModalView.js +++ b/src/UI/Mixins/AsEditModalView.js @@ -1,75 +1,100 @@ var AppLayout = require('../AppLayout'); -module.exports = function(){ +module.exports = function() { var originalInitialize = this.prototype.initialize; var originalOnBeforeClose = this.prototype.onBeforeClose; - var saveInternal = function(){ + + var saveInternal = function() { var self = this; this.ui.indicator.show(); - if(this._onBeforeSave) { + + if (this._onBeforeSave) { this._onBeforeSave.call(this); } + var promise = this.model.save(); - promise.always(function(){ - if(!self.isClosed) { + + promise.always(function() { + if (!self.isClosed) { self.ui.indicator.hide(); } }); - promise.done(function(){ + + promise.done(function() { self.originalModelData = JSON.stringify(self.model.toJSON()); }); + return promise; }; - this.prototype.initialize = function(options){ - if(!this.model) { + + this.prototype.initialize = function(options) { + + if (!this.model) { throw 'View has no model'; } + this.originalModelData = JSON.stringify(this.model.toJSON()); + this.events = this.events || {}; this.events['click .x-save'] = '_save'; this.events['click .x-save-and-add'] = '_saveAndAdd'; this.events['click .x-test'] = '_test'; this.events['click .x-delete'] = '_delete'; + this.ui = this.ui || {}; this.ui.indicator = '.x-indicator'; - if(originalInitialize) { + + if (originalInitialize) { originalInitialize.call(this, options); } }; - this.prototype._save = function(){ + + this.prototype._save = function() { + var self = this; var promise = saveInternal.call(this); - promise.done(function(){ - if(self._onAfterSave) { + + promise.done(function() { + if (self._onAfterSave) { self._onAfterSave.call(self); } }); }; - this.prototype._saveAndAdd = function(){ + + this.prototype._saveAndAdd = function() { + var self = this; var promise = saveInternal.call(this); - promise.done(function(){ - if(self._onAfterSaveAndAdd) { + + promise.done(function() { + if (self._onAfterSaveAndAdd) { self._onAfterSaveAndAdd.call(self); } }); }; - this.prototype._test = function(){ + + this.prototype._test = function() { var self = this; + this.ui.indicator.show(); - this.model.test().always(function(){ + + this.model.test().always(function() { self.ui.indicator.hide(); }); }; - this.prototype._delete = function(){ - var view = new this._deleteView({model : this.model}); + + this.prototype._delete = function() { + var view = new this._deleteView({ model : this.model }); AppLayout.modalRegion.show(view); }; - this.prototype.onBeforeClose = function(){ + + this.prototype.onBeforeClose = function() { this.model.set(JSON.parse(this.originalModelData)); - if(originalOnBeforeClose) { + + if (originalOnBeforeClose) { originalOnBeforeClose.call(this); } }; + return this; -}; \ No newline at end of file +}; diff --git a/src/UI/Mixins/AsFilteredCollection.js b/src/UI/Mixins/AsFilteredCollection.js index d68eb9fc1..2b7b92048 100644 --- a/src/UI/Mixins/AsFilteredCollection.js +++ b/src/UI/Mixins/AsFilteredCollection.js @@ -1,65 +1,70 @@ var _ = require('underscore'); var Backbone = require('backbone'); -module.exports = function(){ +module.exports = function() { + + this.prototype.setFilter = function(filter, options) { + options = _.extend({ reset : true }, options || {}); - this.prototype.setFilter = function(filter, options){ - options = _.extend({reset : true}, options || {}); this.state.filterKey = filter[0]; this.state.filterValue = filter[1]; - if(options.reset) { - if(this.mode !== 'server') { + + if (options.reset) { + if (this.mode !== 'server') { this.fullCollection.resetFiltered(); - } - else { + } else { return this.fetch(); } } }; - this.prototype.setFilterMode = function(mode, options){ + this.prototype.setFilterMode = function(mode, options) { return this.setFilter(this.filterModes[mode], options); }; var originalMakeFullCollection = this.prototype._makeFullCollection; - this.prototype._makeFullCollection = function(models, options){ + this.prototype._makeFullCollection = function(models, options) { var self = this; + self.shadowCollection = originalMakeFullCollection.call(this, models, options); - var filterModel = function(model){ - if(!self.state.filterKey || !self.state.filterValue) { + + var filterModel = function(model) { + if (!self.state.filterKey || !self.state.filterValue) { return true; - } - else { + } else { return model.get(self.state.filterKey) === self.state.filterValue; } }; - self.shadowCollection.filtered = function(){ + self.shadowCollection.filtered = function() { return this.filter(filterModel); }; var filteredModels = self.shadowCollection.filtered(); var fullCollection = originalMakeFullCollection.call(this, filteredModels, options); - fullCollection.resetFiltered = function(options){ + fullCollection.resetFiltered = function(options) { Backbone.Collection.prototype.reset.call(this, self.shadowCollection.filtered(), options); }; - fullCollection.reset = function(models, options){ + fullCollection.reset = function(models, options) { self.shadowCollection.reset(models, options); self.fullCollection.resetFiltered(); }; return fullCollection; }; + _.extend(this.prototype.state, { filterKey : null, filterValue : null }); + _.extend(this.prototype.queryParams, { filterKey : 'filterKey', filterValue : 'filterValue' }); + return this; }; \ No newline at end of file diff --git a/src/UI/Mixins/AsModelBoundView.js b/src/UI/Mixins/AsModelBoundView.js index bf9c58959..12d3fcca3 100644 --- a/src/UI/Mixins/AsModelBoundView.js +++ b/src/UI/Mixins/AsModelBoundView.js @@ -1,35 +1,46 @@ var ModelBinder = require('backbone.modelbinder'); -module.exports = function(){ +module.exports = function() { + var originalOnRender = this.prototype.onRender; var originalBeforeClose = this.prototype.onBeforeClose; - this.prototype.onRender = function(){ - if(!this.model) { + + this.prototype.onRender = function() { + + if (!this.model) { throw 'View has no model for binding'; } - if(!this._modelBinder) { + + if (!this._modelBinder) { this._modelBinder = new ModelBinder(); } + var options = { changeTriggers : { - "" : 'change typeahead:selected typeahead:autocompleted', - "[contenteditable]" : 'blur', - "[data-onkeyup]" : 'keyup' + '' : 'change typeahead:selected typeahead:autocompleted', + '[contenteditable]' : 'blur', + '[data-onkeyup]' : 'keyup' } }; + this._modelBinder.bind(this.model, this.el, null, options); - if(originalOnRender) { + + if (originalOnRender) { originalOnRender.call(this); } }; - this.prototype.onBeforeClose = function(){ - if(this._modelBinder) { + + this.prototype.onBeforeClose = function() { + + if (this._modelBinder) { this._modelBinder.unbind(); delete this._modelBinder; } - if(originalBeforeClose) { + + if (originalBeforeClose) { originalBeforeClose.call(this); } }; + return this; -}; \ No newline at end of file +}; diff --git a/src/UI/Mixins/AsNamedView.js b/src/UI/Mixins/AsNamedView.js index 43b801529..8bdd4b604 100644 --- a/src/UI/Mixins/AsNamedView.js +++ b/src/UI/Mixins/AsNamedView.js @@ -1,24 +1,26 @@ -module.exports = function(){ +module.exports = function() { window.NzbDrone.NameViews = window.NzbDrone.NameViews || !window.NzbDrone.Production; var regex = new RegExp('/', 'g'); - var _getViewName = function(template){ - if(template) { + var _getViewName = function(template) { + if (template) { return template.toLocaleLowerCase().replace('template', '').replace(regex, '-'); } + return undefined; }; var originalOnRender = this.onRender; - this.onRender = function(){ - if(window.NzbDrone.NameViews) { + this.onRender = function() { + + if (window.NzbDrone.NameViews) { this.$el.addClass('iv-' + _getViewName(this.template)); } - if(originalOnRender) { + if (originalOnRender) { return originalOnRender.call(this); } diff --git a/src/UI/Mixins/AsPersistedStateCollection.js b/src/UI/Mixins/AsPersistedStateCollection.js index 175dc8a7a..cecdeb2d8 100644 --- a/src/UI/Mixins/AsPersistedStateCollection.js +++ b/src/UI/Mixins/AsPersistedStateCollection.js @@ -1,55 +1,72 @@ var _ = require('underscore'); var Config = require('../Config'); -module.exports = function(){ +module.exports = function() { + var originalInit = this.prototype.initialize; - this.prototype.initialize = function(options){ + this.prototype.initialize = function(options) { + options = options || {}; - if(options.tableName) { + + if (options.tableName) { this.tableName = options.tableName; } - if(!this.tableName && !options.tableName) { + + if (!this.tableName && !options.tableName) { throw 'tableName is required'; } + _setInitialState.call(this); + this.on('backgrid:sort', _storeStateFromBackgrid, this); this.on('drone:sort', _storeState, this); - if(originalInit) { + + if (originalInit) { originalInit.call(this, options); } }; - if(!this.prototype._getSortMapping) { - this.prototype._getSortMapping = function(key){ + + if (!this.prototype._getSortMapping) { + this.prototype._getSortMapping = function(key) { return { name : key, sortKey : key }; }; } - var _setInitialState = function(){ + + var _setInitialState = function() { var key = Config.getValue('{0}.sortKey'.format(this.tableName), this.state.sortKey); var direction = Config.getValue('{0}.sortDirection'.format(this.tableName), this.state.order); var order = parseInt(direction, 10); + this.state.sortKey = this._getSortMapping(key).sortKey; this.state.order = order; }; - var _storeStateFromBackgrid = function(column, sortDirection){ + + var _storeStateFromBackgrid = function(column, sortDirection) { var order = _convertDirectionToInt(sortDirection); var sortKey = this._getSortMapping(column.get('name')).sortKey; + Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortDirection'.format(this.tableName), order); }; - var _storeState = function(sortModel, sortDirection){ + + var _storeState = function(sortModel, sortDirection) { var order = _convertDirectionToInt(sortDirection); var sortKey = this._getSortMapping(sortModel.get('name')).sortKey; + Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortDirection'.format(this.tableName), order); }; - var _convertDirectionToInt = function(dir){ - if(dir === 'ascending') { + + var _convertDirectionToInt = function(dir) { + if (dir === 'ascending') { return '-1'; } + return '1'; }; + return this; -}; \ No newline at end of file +}; diff --git a/src/UI/Mixins/AsSortedCollection.js b/src/UI/Mixins/AsSortedCollection.js index fd92af2a3..78a31edb6 100644 --- a/src/UI/Mixins/AsSortedCollection.js +++ b/src/UI/Mixins/AsSortedCollection.js @@ -1,17 +1,23 @@ var _ = require('underscore'); var Config = require('../Config'); -module.exports = function(){ +module.exports = function() { + var originalSetSorting = this.prototype.setSorting; - this.prototype.setSorting = function(sortKey, order, options){ + + this.prototype.setSorting = function(sortKey, order, options) { var sortMapping = this._getSortMapping(sortKey); - options = _.defaults({sortValue : sortMapping.sortValue}, options || {}); + + options = _.defaults({ sortValue : sortMapping.sortValue }, options || {}); + return originalSetSorting.call(this, sortMapping.sortKey, order, options); }; - this.prototype._getSortMappings = function(){ + + this.prototype._getSortMappings = function() { var result = {}; - if(this.sortMappings) { - _.each(this.sortMappings, function(values, key){ + + if (this.sortMappings) { + _.each(this.sortMappings, function(values, key) { var item = { name : key, sortKey : values.sortKey || key, @@ -21,80 +27,104 @@ module.exports = function(){ result[item.sortKey] = item; }); } + return result; }; - this.prototype._getSortMapping = function(key){ + + this.prototype._getSortMapping = function(key) { var sortMappings = this._getSortMappings(); + return sortMappings[key] || { name : key, sortKey : key }; }; - this.prototype._getSecondarySorting = function(){ + + this.prototype._getSecondarySorting = function() { var sortKey = this.state.secondarySortKey; var sortOrder = this.state.secondarySortOrder || -1; - if(!sortKey || sortKey === this.state.sortKey) { + + if (!sortKey || sortKey === this.state.sortKey) { return null; } + var sortMapping = this._getSortMapping(sortKey); - if(!sortMapping.sortValue) { - sortMapping.sortValue = function(model, attr){ + + if (!sortMapping.sortValue) { + sortMapping.sortValue = function(model, attr) { return model.get(attr); }; } + return { key : sortKey, order : sortOrder, sortValue : sortMapping.sortValue }; }; - this.prototype._makeComparator = function(sortKey, order, sortValue){ + + this.prototype._makeComparator = function(sortKey, order, sortValue) { var state = this.state; var secondarySorting = this._getSecondarySorting(); + sortKey = sortKey || state.sortKey; order = order || state.order; - if(!sortKey || !order) { + + if (!sortKey || !order) { return; } - if(!sortValue) { - sortValue = function(model, attr){ + + if (!sortValue) { + sortValue = function(model, attr) { return model.get(attr); }; } - return function(left, right){ + + return function(left, right) { var l = sortValue(left, sortKey, order); var r = sortValue(right, sortKey, order); var t; - if(order === 1) { + + if (order === 1) { t = l; l = r; r = t; } - if(l === r) { - if(secondarySorting) { + + if (l === r) { + + if (secondarySorting) { var ls = secondarySorting.sortValue(left, secondarySorting.key, order); var rs = secondarySorting.sortValue(right, secondarySorting.key, order); var ts; - if(secondarySorting.order === 1) { + + if (secondarySorting.order === 1) { ts = ls; ls = rs; rs = ts; } - if(ls === rs) { + + if (ls === rs) { return 0; } - if(ls < rs) { + + if (ls < rs) { return -1; } + return 1; } + return 0; } - else if(l < r) { + + else if (l < r) { return -1; } + return 1; }; }; + return this; -}; \ No newline at end of file +}; diff --git a/src/UI/Mixins/AsSortedCollectionView.js b/src/UI/Mixins/AsSortedCollectionView.js index 14be1d26f..e68b833a7 100644 --- a/src/UI/Mixins/AsSortedCollectionView.js +++ b/src/UI/Mixins/AsSortedCollectionView.js @@ -1,20 +1,24 @@ -module.exports = function(){ - this.prototype.appendHtml = function(collectionView, itemView, index){ +module.exports = function() { + this.prototype.appendHtml = function(collectionView, itemView, index) { var childrenContainer = collectionView.itemViewContainer ? collectionView.$(collectionView.itemViewContainer) : collectionView.$el; var collection = collectionView.collection; - if(index >= collection.size() - 1) { + + // If the index of the model is at the end of the collection append, else insert at proper index + if (index >= collection.size() - 1) { childrenContainer.append(itemView.el); - } - else { + } else { var previousModel = collection.at(index + 1); var previousView = this.children.findByModel(previousModel); - if(previousView) { + + if (previousView) { previousView.$el.before(itemView.$el); } + else { childrenContainer.append(itemView.el); } } }; + return this; }; \ No newline at end of file diff --git a/src/UI/Mixins/AsValidatedView.js b/src/UI/Mixins/AsValidatedView.js index b4658e580..22e3c0844 100644 --- a/src/UI/Mixins/AsValidatedView.js +++ b/src/UI/Mixins/AsValidatedView.js @@ -1,77 +1,93 @@ var Validation = require('backbone.validation'); var _ = require('underscore'); -module.exports = (function(){ +module.exports = (function() { 'use strict'; - return function(){ + return function() { + var originalInitialize = this.prototype.initialize; var originalOnRender = this.prototype.onRender; var originalBeforeClose = this.prototype.onBeforeClose; - var errorHandler = function(response){ - if(this.model) { + + var errorHandler = function(response) { + if (this.model) { this.model.trigger('validation:failed', response); - } - else { + } else { this.trigger('validation:failed', response); } }; - var validatedSync = function(method, model, options){ + + var validatedSync = function(method, model, options) { model.trigger('validation:sync'); + arguments[2].isValidatedCall = true; return model._originalSync.apply(this, arguments).fail(errorHandler.bind(this)); }; - var bindToModel = function(model){ - if(!model._originalSync) { + + var bindToModel = function(model) { + if (!model._originalSync) { model._originalSync = model.sync; model.sync = validatedSync.bind(this); } }; - var validationFailed = function(response){ - if(response.status === 400) { + + var validationFailed = function(response) { + if (response.status === 400) { var view = this; var validationErrors = JSON.parse(response.responseText); - _.each(validationErrors, function(error){ + _.each(validationErrors, function(error) { view.$el.processServerError(error); }); } }; - this.prototype.initialize = function(options){ - if(this.model) { - this.listenTo(this.model, 'validation:sync', function(){ + + this.prototype.initialize = function(options) { + if (this.model) { + this.listenTo(this.model, 'validation:sync', function() { this.$el.removeAllErrors(); }); + this.listenTo(this.model, 'validation:failed', validationFailed); - } - else { - this.listenTo(this, 'validation:sync', function(){ + } else { + this.listenTo(this, 'validation:sync', function() { this.$el.removeAllErrors(); }); + this.listenTo(this, 'validation:failed', validationFailed); } - if(originalInitialize) { + + if (originalInitialize) { originalInitialize.call(this, options); } }; - this.prototype.onRender = function(){ + + this.prototype.onRender = function() { Validation.bind(this); this.bindToModelValidation = bindToModel.bind(this); - if(this.model) { + + if (this.model) { this.bindToModelValidation(this.model); } - if(originalOnRender) { + + if (originalOnRender) { originalOnRender.call(this); } }; - this.prototype.onBeforeClose = function(){ - if(this.model) { + + this.prototype.onBeforeClose = function() { + if (this.model) { Validation.unbind(this); + + //If we don't do this the next time the model is used the sync is bound to an old view this.model.sync = this.model._originalSync; this.model._originalSync = undefined; } - if(originalBeforeClose) { + + if (originalBeforeClose) { originalBeforeClose.call(this); } }; + return this; }; }).call(this); \ No newline at end of file diff --git a/src/UI/Mixins/AutoComplete.js b/src/UI/Mixins/AutoComplete.js index ceb2b7bd2..4d1a5ad3b 100644 --- a/src/UI/Mixins/AutoComplete.js +++ b/src/UI/Mixins/AutoComplete.js @@ -1,49 +1,51 @@ var $ = require('jquery'); require('typeahead'); -module.exports = (function(){ - $.fn.autoComplete = function(options){ - if(!options) { - throw 'options are required'; - } - if(!options.resource) { - throw 'resource is required'; - } - if(!options.query) { - throw 'query is required'; - } - $(this).typeahead({ - hint : true, - highlight : true, - minLength : 3, - items : 20 - }, { - name : options.resource.replace('/'), - displayKey : '', - source : function(filter, callback){ - var data = {}; - data[options.query] = filter; - $.ajax({ - url : window.NzbDrone.ApiRoot + options.resource, - dataType : 'json', - type : 'GET', - data : data, - success : function(response){ - if(options.filter) { - options.filter.call(this, filter, response, callback); - } - else { - var matches = []; - $.each(response, function(i, d){ - if(d[options.query] && d[options.property].startsWith(filter)) { - matches.push({value : d[options.property]}); - } - }); - callback(matches); - } +$.fn.autoComplete = function(options) { + if (!options) { + throw 'options are required'; + } + + if (!options.resource) { + throw 'resource is required'; + } + + if (!options.query) { + throw 'query is required'; + } + + $(this).typeahead({ + hint : true, + highlight : true, + minLength : 3, + items : 20 + }, { + name : options.resource.replace('/'), + displayKey : '', + source : function(filter, callback) { + var data = {}; + data[options.query] = filter; + $.ajax({ + url : window.NzbDrone.ApiRoot + options.resource, + dataType : 'json', + type : 'GET', + data : data, + success : function(response) { + if (options.filter) { + options.filter.call(this, filter, response, callback); + } else { + var matches = []; + + $.each(response, function(i, d) { + if (d[options.query] && d[options.property].startsWith(filter)) { + matches.push({ value : d[options.property] }); + } + }); + + callback(matches); } - }); - } - }); - }; -}).call(this); \ No newline at end of file + } + }); + } + }); +}; \ No newline at end of file diff --git a/src/UI/Mixins/CopyToClipboard.js b/src/UI/Mixins/CopyToClipboard.js index d3b01e628..77db6e39a 100644 --- a/src/UI/Mixins/CopyToClipboard.js +++ b/src/UI/Mixins/CopyToClipboard.js @@ -6,7 +6,7 @@ var Messenger = require('../Shared/Messenger'); $.fn.copyToClipboard = function(input) { ZeroClipboard.config({ - swfPath: StatusModel.get('urlBase') + '/Content/zero.clipboard.swf' + swfPath : StatusModel.get('urlBase') + '/Content/zero.clipboard.swf' }); var client = new ZeroClipboard(this); @@ -16,7 +16,7 @@ $.fn.copyToClipboard = function(input) { e.clipboardData.setData("text/plain", input.val()); }); client.on('aftercopy', function() { - Messenger.show({message : 'Copied text to clipboard'}); + Messenger.show({ message : 'Copied text to clipboard' }); }); }); }; \ No newline at end of file diff --git a/src/UI/Mixins/DirectoryAutoComplete.js b/src/UI/Mixins/DirectoryAutoComplete.js index bcb0737ef..9e9d606e7 100644 --- a/src/UI/Mixins/DirectoryAutoComplete.js +++ b/src/UI/Mixins/DirectoryAutoComplete.js @@ -1,21 +1,22 @@ var $ = require('jquery'); require('./AutoComplete'); -module.exports = (function(){ - $.fn.directoryAutoComplete = function(){ - var query = 'path'; - $(this).autoComplete({ - resource : '/filesystem', - query : query, - filter : function(filter, response, callback){ - var matches = []; - $.each(response.directories, function(i, d){ - if(d[query] && d[query].startsWith(filter)) { - matches.push({value : d[query]}); - } - }); - callback(matches); - } - }); - }; -}).call(this); \ No newline at end of file +$.fn.directoryAutoComplete = function() { + var query = 'path'; + + $(this).autoComplete({ + resource : '/filesystem', + query : query, + filter : function(filter, response, callback) { + var matches = []; + + $.each(response.directories, function(i, d) { + if (d[query] && d[query].startsWith(filter)) { + matches.push({ value : d[query] }); + } + }); + + callback(matches); + } + }); +}; \ No newline at end of file diff --git a/src/UI/Mixins/FileBrowser.js b/src/UI/Mixins/FileBrowser.js index 6ab68e73e..3545211be 100644 --- a/src/UI/Mixins/FileBrowser.js +++ b/src/UI/Mixins/FileBrowser.js @@ -1,29 +1,31 @@ -var $ = require('jquery'); +var $ = require('jquery'); var vent = require('vent'); require('../Shared/FileBrowser/FileBrowserLayout'); require('./DirectoryAutoComplete'); -module.exports = (function(){ - $.fn.fileBrowser = function(options){ - var inputs = $(this); - inputs.each(function(){ - var input = $(this); - var inputOptions = $.extend({input : input}, options); - var inputGroup = $('
'); - var inputGroupButton = $(''); - var button = $(''); - if(input.parent('.input-group').length > 0) { - input.parent('.input-group').find('.input-group-btn').prepend(button); - } - else { - inputGroupButton.append(button); - input.wrap(inputGroup); - input.after(inputGroupButton); - } - button.on('click', function(){ - vent.trigger(vent.Commands.ShowFileBrowser, inputOptions); - }); +$.fn.fileBrowser = function(options) { + var inputs = $(this); + + inputs.each(function() { + var input = $(this); + var inputOptions = $.extend({ input : input }, options); + var inputGroup = $('
'); + var inputGroupButton = $(''); + + var button = $(''); + + if (input.parent('.input-group').length > 0) { + input.parent('.input-group').find('.input-group-btn').prepend(button); + } else { + inputGroupButton.append(button); + input.wrap(inputGroup); + input.after(inputGroupButton); + } + + button.on('click', function() { + vent.trigger(vent.Commands.ShowFileBrowser, inputOptions); }); - inputs.directoryAutoComplete(); - }; -}).call(this); \ No newline at end of file + }); + + inputs.directoryAutoComplete(); +}; diff --git a/src/UI/Mixins/TagInput.js b/src/UI/Mixins/TagInput.js index 440fc9755..1994e3d3b 100644 --- a/src/UI/Mixins/TagInput.js +++ b/src/UI/Mixins/TagInput.js @@ -4,120 +4,143 @@ var TagCollection = require('../Tags/TagCollection'); var TagModel = require('../Tags/TagModel'); require('bootstrap.tagsinput'); -module.exports = (function(){ - var originalAdd = $.fn.tagsinput.Constructor.prototype.add; - var originalRemove = $.fn.tagsinput.Constructor.prototype.remove; - var originalBuild = $.fn.tagsinput.Constructor.prototype.build; - $.fn.tagsinput.Constructor.prototype.add = function(item, dontPushVal){ - var self = this; - if(typeof item === 'string' && this.options.tag) { - var test = testTag(item); - if(item === null || item === '' || !testTag(item)) { - return; - } - var existing = _.find(TagCollection.toJSON(), {label : item}); - if(existing) { - originalAdd.call(this, existing, dontPushVal); - } - else { - var newTag = new TagModel(); - newTag.set({label : item.toLowerCase()}); - TagCollection.add(newTag); - newTag.save().done(function(){ - item = newTag.toJSON(); - originalAdd.call(self, item, dontPushVal); - }); - } - } - else { - originalAdd.call(this, item, dontPushVal); - } - if(this.options.tag) { - self.$input.typeahead('val', ''); - } +var substringMatcher = function() { + return function findMatches (q, cb) { + var matches = _.select(TagCollection.toJSON(), function(tag) { + return tag.label.toLowerCase().indexOf(q.toLowerCase()) > -1; + }); + cb(matches); }; - $.fn.tagsinput.Constructor.prototype.remove = function(item, dontPushVal){ - if(item === null) { +}; +var getExistingTags = function(tagValues) { + return _.select(TagCollection.toJSON(), function(tag) { + return _.contains(tagValues, tag.id); + }); +}; + +var testTag = function(item) { + var tagLimitations = new RegExp('[^-_a-z0-9]', 'i'); + try { + return !tagLimitations.test(item); + } + catch (e) { + return false; + } +}; + +var originalAdd = $.fn.tagsinput.Constructor.prototype.add; +var originalRemove = $.fn.tagsinput.Constructor.prototype.remove; +var originalBuild = $.fn.tagsinput.Constructor.prototype.build; + +$.fn.tagsinput.Constructor.prototype.add = function(item, dontPushVal) { + var self = this; + + if (typeof item === 'string' && this.options.tag) { + var test = testTag(item); + if (item === null || item === '' || !testTag(item)) { return; } - originalRemove.call(this, item, dontPushVal); - }; - $.fn.tagsinput.Constructor.prototype.build = function(options){ - var self = this; - var defaults = { - confirmKeys : [9, 13, 32, 44, 59] - }; - options = $.extend({}, defaults, options); - self.$input.on('keydown', function(event){ - if(event.which === 9) { - var e = $.Event('keypress'); - e.which = 9; - self.$input.trigger(e); - event.preventDefault(); - } - }); - self.$input.on('focusout', function(){ - self.add(self.$input.val()); - self.$input.val(''); - }); - originalBuild.call(this, options); - }; - $.fn.tagInput = function(options){ - var input = this; - var model = options.model; - var property = options.property; - var tags = getExistingTags(model.get(property)); - var tagInput = $(this).tagsinput({ - tag : true, - freeInput : true, - itemValue : 'id', - itemText : 'label', - trimValue : true, - typeaheadjs : { - name : 'tags', - displayKey : 'label', - source : substringMatcher() - } - }); - $(tagInput)[0].options.freeInput = true; - $(this).tagsinput('removeAll'); - _.each(tags, function(tag){ - $(input).tagsinput('add', tag); - }); - $(this).tagsinput('refresh'); - $(this).on('itemAdded', function(event){ - var tags = model.get(property); - tags.push(event.item.id); - model.set(property, tags); - }); - $(this).on('itemRemoved', function(event){ - if(!event.item) { - return; - } - var tags = _.without(model.get(property), event.item.id); - model.set(property, tags); - }); - }; - var substringMatcher = function(){ - return function findMatches (q, cb){ - var matches = _.select(TagCollection.toJSON(), function(tag){ - return tag.label.toLowerCase().indexOf(q.toLowerCase()) > -1; + + var existing = _.find(TagCollection.toJSON(), { label : item }); + + if (existing) { + originalAdd.call(this, existing, dontPushVal); + } else { + var newTag = new TagModel(); + newTag.set({ label : item.toLowerCase() }); + TagCollection.add(newTag); + + newTag.save().done(function() { + item = newTag.toJSON(); + originalAdd.call(self, item, dontPushVal); }); - cb(matches); - }; - }; - var getExistingTags = function(tagValues){ - return _.select(TagCollection.toJSON(), function(tag){ - return _.contains(tagValues, tag.id); - }); - }; - var testTag = function(item){ - var tagLimitations = new RegExp('[^-_a-z0-9]', 'i'); - try { - return !tagLimitations.test(item); - } - catch (e) { - return false; } + } else { + originalAdd.call(this, item, dontPushVal); + } + + if (this.options.tag) { + self.$input.typeahead('val', ''); + } +}; + +$.fn.tagsinput.Constructor.prototype.remove = function(item, dontPushVal) { + if (item === null) { + return; + } + + originalRemove.call(this, item, dontPushVal); +}; + +$.fn.tagsinput.Constructor.prototype.build = function(options) { + var self = this; + var defaults = { + confirmKeys : [ + 9, + 13, + 32, + 44, + 59 + ] //tab, enter, space, comma, semi-colon }; -}).call(this); \ No newline at end of file + + options = $.extend({}, defaults, options); + + self.$input.on('keydown', function(event) { + if (event.which === 9) { + var e = $.Event('keypress'); + e.which = 9; + self.$input.trigger(e); + event.preventDefault(); + } + }); + + self.$input.on('focusout', function() { + self.add(self.$input.val()); + self.$input.val(''); + }); + + originalBuild.call(this, options); +}; + +$.fn.tagInput = function(options) { + var input = this; + var model = options.model; + var property = options.property; + var tags = getExistingTags(model.get(property)); + + var tagInput = $(this).tagsinput({ + tag : true, + freeInput : true, + itemValue : 'id', + itemText : 'label', + trimValue : true, + typeaheadjs : { + name : 'tags', + displayKey : 'label', + source : substringMatcher() + } + }); + + //Override the free input being set to false because we're using objects + $(tagInput)[0].options.freeInput = true; + + //Remove any existing tags and re-add them + $(this).tagsinput('removeAll'); + _.each(tags, function(tag) { + $(input).tagsinput('add', tag); + }); + $(this).tagsinput('refresh'); + $(this).on('itemAdded', function(event) { + var tags = model.get(property); + tags.push(event.item.id); + model.set(property, tags); + }); + $(this).on('itemRemoved', function(event) { + if (!event.item) { + return; + } + var tags = _.without(model.get(property), event.item.id); + model.set(property, tags); + }); +}; \ No newline at end of file diff --git a/src/UI/Mixins/backbone.signalr.mixin.js b/src/UI/Mixins/backbone.signalr.mixin.js index dd91864a9..8aad9b71c 100644 --- a/src/UI/Mixins/backbone.signalr.mixin.js +++ b/src/UI/Mixins/backbone.signalr.mixin.js @@ -5,27 +5,37 @@ var Backbone = require('backbone'); require('signalR'); module.exports = _.extend(Backbone.Collection.prototype, { - bindSignalR : function(bindOptions){ + bindSignalR : function(bindOptions) { + var collection = this; bindOptions = bindOptions || {}; - var processMessage = function(options){ - if(options.action === 'sync') { + + var processMessage = function(options) { + if (options.action === 'sync') { console.log('sync received, re-fetching collection'); collection.fetch(); + return; } - if(options.action === 'deleted') { - collection.remove(new collection.model(options.resource, {parse : true})); + + if (options.action === 'deleted') { + collection.remove(new collection.model(options.resource, { parse : true })); + return; } - var model = new collection.model(options.resource, {parse : true}); - if(bindOptions.updateOnly && !collection.get(model.get('id'))) { + + var model = new collection.model(options.resource, { parse : true }); + + //updateOnly will prevent the collection from adding a new item + if (bindOptions.updateOnly && !collection.get(model.get('id'))) { return; } + collection.add(model, { merge : true, changeSource : 'signalr' }); + console.log(options.action + ': {0}}'.format(options.resource)); }; diff --git a/src/UI/jQuery/RouteBinder.js b/src/UI/jQuery/RouteBinder.js index 19c2a7d32..6662349da 100644 --- a/src/UI/jQuery/RouteBinder.js +++ b/src/UI/jQuery/RouteBinder.js @@ -2,49 +2,67 @@ var Backbone = require('backbone'); var $ = require('jquery'); var StatusModel = require('../System/StatusModel'); +//This module will automatically route all relative links through backbone router rather than +//causing links to reload pages. + var routeBinder = { - bind : function(){ + + bind : function() { var self = this; - $(document).on('click', 'a[href]', function(event){ + $(document).on('click', 'a[href]', function(event) { self._handleClick(event); }); }, - _handleClick : function(event){ + + _handleClick : function(event) { var $target = $(event.target); - if($target.parents('.nav-tabs').length) { + + //check if tab nav + if ($target.parents('.nav-tabs').length) { return; } - if($target.hasClass('no-router')) { + + if ($target.hasClass('no-router')) { return; } + var href = event.target.getAttribute('href'); - if(!href && $target.closest('a') && $target.closest('a')[0]) { + + if (!href && $target.closest('a') && $target.closest('a')[0]) { + var linkElement = $target.closest('a')[0]; - if($(linkElement).hasClass('no-router')) { + + if ($(linkElement).hasClass('no-router')) { return; } + href = linkElement.getAttribute('href'); } + event.preventDefault(); - if(!href) { + + if (!href) { throw 'couldn\'t find route target'; } - if(!href.startsWith('http')) { - if(event.ctrlKey) { + + if (!href.startsWith('http')) { + if (event.ctrlKey) { window.open(href, '_blank'); } + else { var relativeHref = href.replace(StatusModel.get('urlBase'), ''); - Backbone.history.navigate(relativeHref, {trigger : true}); + + Backbone.history.navigate(relativeHref, { trigger : true }); } - } - else if(href.contains('#')) { + } else if (href.contains('#')) { + //Open in new tab without dereferer (since it doesn't support fragments) window.open(href, '_blank'); - } - else { + } else { + //Open in new tab window.open('http://www.dereferer.org/?' + encodeURI(href), '_blank'); } } }; -module.exports = routeBinder; +module.exports = routeBinder; \ No newline at end of file diff --git a/src/UI/jQuery/ToTheTop.js b/src/UI/jQuery/ToTheTop.js index 764ea464d..635da9a6a 100644 --- a/src/UI/jQuery/ToTheTop.js +++ b/src/UI/jQuery/ToTheTop.js @@ -1,23 +1,21 @@ var $ = require('jquery'); var _ = require('underscore'); - -$(document).ready(function(){ +$(document).ready(function() { var _window = $(window); var _scrollButton = $('#scroll-up'); - var _scrollHandler = function(){ - if(_window.scrollTop() > 100) { + var _scrollHandler = function() { + if (_window.scrollTop() > 100) { _scrollButton.fadeIn(); - } - else { + } else { _scrollButton.fadeOut(); } }; $(window).scroll(_.throttle(_scrollHandler, 500)); - _scrollButton.click(function(){ - $('html, body').animate({scrollTop : 0}, 600); + _scrollButton.click(function() { + $('html, body').animate({ scrollTop : 0 }, 600); return false; }); }); diff --git a/src/UI/jQuery/jquery.ajax.js b/src/UI/jQuery/jquery.ajax.js index fb622707b..0073e8619 100644 --- a/src/UI/jQuery/jquery.ajax.js +++ b/src/UI/jQuery/jquery.ajax.js @@ -1,21 +1,20 @@ -module.exports = function(){ +module.exports = function() { var $ = this; var original = $.ajax; - $.ajax = function(xhr){ + $.ajax = function(xhr) { 'use strict'; - if(xhr && xhr.data && xhr.type === 'DELETE') { - if(xhr.url.contains('?')) { + if (xhr && xhr.data && xhr.type === 'DELETE') { + if (xhr.url.contains('?')) { xhr.url += '&'; - } - else { + } else { xhr.url += '?'; } xhr.url += $.param(xhr.data); delete xhr.data; } - if(xhr) { + if (xhr) { xhr.headers = xhr.headers || {}; xhr.headers['X-Api-Key'] = window.NzbDrone.ApiKey; } diff --git a/src/UI/jQuery/jquery.spin.js b/src/UI/jQuery/jquery.spin.js index 3a2874fa0..740428297 100644 --- a/src/UI/jQuery/jquery.spin.js +++ b/src/UI/jQuery/jquery.spin.js @@ -1,47 +1,60 @@ -module.exports = function(){ +module.exports = function() { 'use strict'; var $ = this; - $.fn.spinForPromise = function(promise){ + $.fn.spinForPromise = function(promise) { var self = this; - if(!promise || promise.state() !== 'pending') { + + if (!promise || promise.state() !== 'pending') { return this; } - promise.always(function(){ + promise.always(function() { self.stopSpin(); }); + return this.startSpin(); }; - $.fn.startSpin = function(){ + + $.fn.startSpin = function() { var icon = this.find('i').andSelf('i'); - if(!icon || !icon.attr('class')) { + + if (!icon || !icon.attr('class')) { return this; } + var iconClasses = icon.attr('class').match(/(?:^|\s)icon\-.+?(?:$|\s)/); - if(iconClasses.length === 0) { + + if (iconClasses.length === 0) { return this; } + var iconClass = $.trim(iconClasses[0]); + this.addClass('disabled'); - if(icon.hasClass('icon-can-spin')) { + + if (icon.hasClass('icon-can-spin')) { icon.addClass('icon-spin'); - } - else { + } else { icon.attr('data-idle-icon', iconClass); icon.removeClass(iconClass); icon.addClass('icon-nd-spinner'); } + return this; }; - $.fn.stopSpin = function(){ + + $.fn.stopSpin = function() { var icon = this.find('i').andSelf('i'); + this.removeClass('disabled'); icon.removeClass('icon-spin icon-nd-spinner'); var idleIcon = icon.attr('data-idle-icon'); - if(idleIcon) { + + if (idleIcon) { icon.addClass(idleIcon); } + return this; }; }; \ No newline at end of file diff --git a/src/UI/jQuery/jquery.validation.js b/src/UI/jQuery/jquery.validation.js index 910d8488c..e28274a69 100644 --- a/src/UI/jQuery/jquery.validation.js +++ b/src/UI/jQuery/jquery.validation.js @@ -1,74 +1,95 @@ -module.exports = function(){ +module.exports = function() { 'use strict'; var $ = this; - $.fn.processServerError = function(error){ + $.fn.processServerError = function(error) { var validationName = error.propertyName.toLowerCase(); + var errorMessage = this.formatErrorMessage(error); + this.find('.validation-errors').addClass('alert alert-danger').append('
' + errorMessage + '
'); - if(!validationName || validationName === '') { + + if (!validationName || validationName === '') { this.addFormError(error); return this; } - var input = this.find('[name]').filter(function(){ + + var input = this.find('[name]').filter(function() { return this.name.toLowerCase() === validationName; }); - if(input.length === 0) { - input = this.find('[validation-name]').filter(function(){ + + if (input.length === 0) { + input = this.find('[validation-name]').filter(function() { return $(this).attr('validation-name').toLowerCase() === validationName; }); - if(input.length === 0) { + + //still not found? + if (input.length === 0) { this.addFormError(error); console.error('couldn\'t find input for ' + error.propertyName); return this; } } + var formGroup = input.parents('.form-group'); - if(formGroup.length === 0) { + + if (formGroup.length === 0) { formGroup = input.parent(); - } - else { + } else { var inputGroup = formGroup.find('.input-group'); - if(inputGroup.length === 0) { + + if (inputGroup.length === 0) { formGroup.append('' + errorMessage + ''); } + else { inputGroup.parent().append('' + errorMessage + ''); } } + formGroup.addClass('has-error'); + return formGroup.find('.help-inline').text(); }; - $.fn.processClientError = function(error){ + + $.fn.processClientError = function(error) { + }; - $.fn.addFormError = function(error){ + + $.fn.addFormError = function(error) { + var errorMessage = this.formatErrorMessage(error); - if(this.find('.modal-body')) { + + if (this.find('.modal-body')) { this.find('.modal-body').prepend('
' + errorMessage + '
'); } + else { this.prepend('
' + errorMessage + '
'); } }; - $.fn.removeAllErrors = function(){ + + $.fn.removeAllErrors = function() { this.find('.has-error').removeClass('has-error'); this.find('.error').removeClass('error'); this.find('.validation-errors').removeClass('alert').removeClass('alert-danger').html(''); this.find('.validation-error').remove(); return this.find('.help-inline.error-message').remove(); }; - $.fn.formatErrorMessage = function(error){ + + $.fn.formatErrorMessage = function(error) { + var errorMessage = error.errorMessage; - if(error.infoLink) { - if(error.detailedDescription) { + + if (error.infoLink) { + if (error.detailedDescription) { errorMessage += ' '; - } - else { + } else { errorMessage += ' '; } - } - else if(error.detailedDescription) { + } else if (error.detailedDescription) { errorMessage += ' '; } + return errorMessage; }; }; \ No newline at end of file