mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-04-26 23:06:43 -04:00
UI Cleanup - Updated Instrumentation, jQuery and Mixins subtrees.
This commit is contained in:
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -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' });
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -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);
|
||||
$.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);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -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 = $('<div class="input-group"></div>');
|
||||
var inputGroupButton = $('<span class="input-group-btn "></span>');
|
||||
var button = $('<button class="btn btn-primary x-file-browser" title="Browse"><i class="icon-folder-open"/></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 = $('<div class="input-group"></div>');
|
||||
var inputGroupButton = $('<span class="input-group-btn "></span>');
|
||||
|
||||
var button = $('<button class="btn btn-primary x-file-browser" title="Browse"><i class="icon-folder-open"/></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);
|
||||
});
|
||||
|
||||
inputs.directoryAutoComplete();
|
||||
};
|
||||
|
||||
+134
-111
@@ -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);
|
||||
|
||||
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);
|
||||
});
|
||||
};
|
||||
@@ -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));
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user