UI Cleanup - Updated Instrumentation, jQuery and Mixins subtrees.

pull/197/head
Taloth Saldono 10 years ago
parent 44928c8f64
commit 70bfad4e6a

@ -2,30 +2,33 @@ var $ = require('jquery');
var vent = require('vent'); var vent = require('vent');
var HotkeysView = require('./HotkeysView'); var HotkeysView = require('./HotkeysView');
module.exports = (function(){
$(document).on('keypress', function(e) { $(document).on('keypress', function(e) {
if ($(e.target).is('input') || $(e.target).is('textarea')) { if ($(e.target).is('input') || $(e.target).is('textarea')) {
return; return;
} }
if (e.charCode === 63) { if (e.charCode === 63) {
vent.trigger(vent.Commands.OpenModalCommand, new HotkeysView()); vent.trigger(vent.Commands.OpenModalCommand, new HotkeysView());
} }
}); });
$(document).on('keydown', function(e) { $(document).on('keydown', function(e) {
if (e.ctrlKey && e.keyCode === 83) { if (e.ctrlKey && e.keyCode === 83) {
vent.trigger(vent.Hotkeys.SaveSettings); vent.trigger(vent.Hotkeys.SaveSettings);
e.preventDefault(); e.preventDefault();
return; return;
} }
if ($(e.target).is('input') || $(e.target).is('textarea')) { if ($(e.target).is('input') || $(e.target).is('textarea')) {
return; return;
} }
if (e.ctrlKey || e.metaKey || e.altKey) { if (e.ctrlKey || e.metaKey || e.altKey) {
return; return;
} }
if (e.keyCode === 84) { if (e.keyCode === 84) {
vent.trigger(vent.Hotkeys.NavbarSearch); vent.trigger(vent.Hotkeys.NavbarSearch);
e.preventDefault(); e.preventDefault();
} }
}); });
}).call(this);

@ -1,4 +1,6 @@
var vent = require('vent'); var vent = require('vent');
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'Hotkeys/HotkeysViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'Hotkeys/HotkeysViewTemplate'
});

@ -1,69 +1,86 @@
var $ = require('jquery'); var $ = require('jquery');
var Messenger = require('messenger'); var Messenger = require('messenger');
module.exports = (function(){
'use strict';
window.alert = function(message) { window.alert = function(message) {
new Messenger().post(message); new Messenger().post(message);
}; };
var addError = function(message) { var addError = function(message) {
$('#errors').append('<div>' + message + '</div>'); $('#errors').append('<div>' + message + '</div>');
}; };
window.onerror = function(msg, url, line) { window.onerror = function(msg, url, line) {
try { try {
var a = document.createElement('a'); var a = document.createElement('a');
a.href = url; a.href = url;
var filename = a.pathname.split('/').pop(); 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') { if (filename.toLowerCase() === 'markupview.jsm' || filename.toLowerCase() === 'markup-view.js') {
return false; return false;
} }
var messageText = filename + ' : ' + line + '</br>' + msg; var messageText = filename + ' : ' + line + '</br>' + msg;
var message = { var message = {
message : messageText, message : messageText,
type : 'error', type : 'error',
hideAfter : 1000, hideAfter : 1000,
showCloseButton : true showCloseButton : true
}; };
new Messenger().post(message); new Messenger().post(message);
addError(message.message); addError(message.message);
} }
catch (error) { catch (error) {
console.log('An error occurred while reporting error. ' + error); console.log('An error occurred while reporting error. ' + error);
console.log(msg); console.log(msg);
new Messenger().post('Couldn\'t report JS error. ' + msg); new Messenger().post('Couldn\'t report JS error. ' + msg);
} }
return false;
return false; //don't suppress default alerts and logs.
}; };
$(document).ajaxError(function(event, xmlHttpRequest, ajaxOptions) { $(document).ajaxError(function(event, xmlHttpRequest, ajaxOptions) {
//don't report 200 error codes
if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status <= 300) { if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status <= 300) {
return undefined; return undefined;
} }
//don't report aborted requests
if (xmlHttpRequest.statusText === 'abort') { if (xmlHttpRequest.statusText === 'abort') {
return undefined; return undefined;
} }
var message = { var message = {
type : 'error', type : 'error',
hideAfter : 1000, hideAfter : 1000,
showCloseButton : true showCloseButton : true
}; };
if (xmlHttpRequest.status === 0 && xmlHttpRequest.readyState === 0) { if (xmlHttpRequest.status === 0 && xmlHttpRequest.readyState === 0) {
return false; return false;
} }
if (xmlHttpRequest.status === 400 && ajaxOptions.isValidatedCall) { if (xmlHttpRequest.status === 400 && ajaxOptions.isValidatedCall) {
return false; return false;
} }
if (xmlHttpRequest.status === 503) { if (xmlHttpRequest.status === 503) {
message.message = xmlHttpRequest.responseJSON.message; message.message = xmlHttpRequest.responseJSON.message;
} } else if (xmlHttpRequest.status === 409) {
if(xmlHttpRequest.status === 409) {
message.message = xmlHttpRequest.responseJSON.message; message.message = xmlHttpRequest.responseJSON.message;
} } else {
else {
message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url); message.message = '[{0}] {1} : {2}'.format(ajaxOptions.type, xmlHttpRequest.statusText, ajaxOptions.url);
} }
new Messenger().post(message); new Messenger().post(message);
addError(message.message); addError(message.message);
return false; return false;
}); });
}).call(this);

@ -1,11 +1,12 @@
'use strict'; 'use strict';
String.prototype.format = function() { String.prototype.format = function() {
var args = arguments; var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) { return this.replace(/{(\d+)}/g, function(match, number) {
if (typeof args[number] !== 'undefined') { if (typeof args[number] !== 'undefined') {
return args[number]; return args[number];
} } else {
else {
return match; return match;
} }
}); });

@ -1,16 +1,22 @@
module.exports = function() { module.exports = function() {
var originalInit = this.prototype.initialize; var originalInit = this.prototype.initialize;
this.prototype.initialize = function() { this.prototype.initialize = function() {
this.isSaved = true; this.isSaved = true;
this.on('change', function() { this.on('change', function() {
this.isSaved = false; this.isSaved = false;
}, this); }, this);
this.on('sync', function() { this.on('sync', function() {
this.isSaved = true; this.isSaved = true;
}, this); }, this);
if (originalInit) { if (originalInit) {
originalInit.call(this); originalInit.call(this);
} }
}; };
return this; return this;
}; };

@ -3,73 +3,98 @@ var AppLayout = require('../AppLayout');
module.exports = function() { module.exports = function() {
var originalInitialize = this.prototype.initialize; var originalInitialize = this.prototype.initialize;
var originalOnBeforeClose = this.prototype.onBeforeClose; var originalOnBeforeClose = this.prototype.onBeforeClose;
var saveInternal = function() { var saveInternal = function() {
var self = this; var self = this;
this.ui.indicator.show(); this.ui.indicator.show();
if (this._onBeforeSave) { if (this._onBeforeSave) {
this._onBeforeSave.call(this); this._onBeforeSave.call(this);
} }
var promise = this.model.save(); var promise = this.model.save();
promise.always(function() { promise.always(function() {
if (!self.isClosed) { if (!self.isClosed) {
self.ui.indicator.hide(); self.ui.indicator.hide();
} }
}); });
promise.done(function() { promise.done(function() {
self.originalModelData = JSON.stringify(self.model.toJSON()); self.originalModelData = JSON.stringify(self.model.toJSON());
}); });
return promise; return promise;
}; };
this.prototype.initialize = function(options) { this.prototype.initialize = function(options) {
if (!this.model) { if (!this.model) {
throw 'View has no model'; throw 'View has no model';
} }
this.originalModelData = JSON.stringify(this.model.toJSON()); this.originalModelData = JSON.stringify(this.model.toJSON());
this.events = this.events || {}; this.events = this.events || {};
this.events['click .x-save'] = '_save'; this.events['click .x-save'] = '_save';
this.events['click .x-save-and-add'] = '_saveAndAdd'; this.events['click .x-save-and-add'] = '_saveAndAdd';
this.events['click .x-test'] = '_test'; this.events['click .x-test'] = '_test';
this.events['click .x-delete'] = '_delete'; this.events['click .x-delete'] = '_delete';
this.ui = this.ui || {}; this.ui = this.ui || {};
this.ui.indicator = '.x-indicator'; this.ui.indicator = '.x-indicator';
if (originalInitialize) { if (originalInitialize) {
originalInitialize.call(this, options); originalInitialize.call(this, options);
} }
}; };
this.prototype._save = function() { this.prototype._save = function() {
var self = this; var self = this;
var promise = saveInternal.call(this); var promise = saveInternal.call(this);
promise.done(function() { promise.done(function() {
if (self._onAfterSave) { if (self._onAfterSave) {
self._onAfterSave.call(self); self._onAfterSave.call(self);
} }
}); });
}; };
this.prototype._saveAndAdd = function() { this.prototype._saveAndAdd = function() {
var self = this; var self = this;
var promise = saveInternal.call(this); var promise = saveInternal.call(this);
promise.done(function() { promise.done(function() {
if (self._onAfterSaveAndAdd) { if (self._onAfterSaveAndAdd) {
self._onAfterSaveAndAdd.call(self); self._onAfterSaveAndAdd.call(self);
} }
}); });
}; };
this.prototype._test = function() { this.prototype._test = function() {
var self = this; var self = this;
this.ui.indicator.show(); this.ui.indicator.show();
this.model.test().always(function() { this.model.test().always(function() {
self.ui.indicator.hide(); self.ui.indicator.hide();
}); });
}; };
this.prototype._delete = function() { this.prototype._delete = function() {
var view = new this._deleteView({ model : this.model }); var view = new this._deleteView({ model : this.model });
AppLayout.modalRegion.show(view); AppLayout.modalRegion.show(view);
}; };
this.prototype.onBeforeClose = function() { this.prototype.onBeforeClose = function() {
this.model.set(JSON.parse(this.originalModelData)); this.model.set(JSON.parse(this.originalModelData));
if (originalOnBeforeClose) { if (originalOnBeforeClose) {
originalOnBeforeClose.call(this); originalOnBeforeClose.call(this);
} }
}; };
return this; return this;
}; };

@ -5,13 +5,14 @@ module.exports = function(){
this.prototype.setFilter = function(filter, options) { this.prototype.setFilter = function(filter, options) {
options = _.extend({ reset : true }, options || {}); options = _.extend({ reset : true }, options || {});
this.state.filterKey = filter[0]; this.state.filterKey = filter[0];
this.state.filterValue = filter[1]; this.state.filterValue = filter[1];
if (options.reset) { if (options.reset) {
if (this.mode !== 'server') { if (this.mode !== 'server') {
this.fullCollection.resetFiltered(); this.fullCollection.resetFiltered();
} } else {
else {
return this.fetch(); return this.fetch();
} }
} }
@ -25,12 +26,13 @@ module.exports = function(){
this.prototype._makeFullCollection = function(models, options) { this.prototype._makeFullCollection = function(models, options) {
var self = this; var self = this;
self.shadowCollection = originalMakeFullCollection.call(this, models, options); self.shadowCollection = originalMakeFullCollection.call(this, models, options);
var filterModel = function(model) { var filterModel = function(model) {
if (!self.state.filterKey || !self.state.filterValue) { if (!self.state.filterKey || !self.state.filterValue) {
return true; return true;
} } else {
else {
return model.get(self.state.filterKey) === self.state.filterValue; return model.get(self.state.filterKey) === self.state.filterValue;
} }
}; };
@ -53,13 +55,16 @@ module.exports = function(){
return fullCollection; return fullCollection;
}; };
_.extend(this.prototype.state, { _.extend(this.prototype.state, {
filterKey : null, filterKey : null,
filterValue : null filterValue : null
}); });
_.extend(this.prototype.queryParams, { _.extend(this.prototype.queryParams, {
filterKey : 'filterKey', filterKey : 'filterKey',
filterValue : 'filterValue' filterValue : 'filterValue'
}); });
return this; return this;
}; };

@ -1,35 +1,46 @@
var ModelBinder = require('backbone.modelbinder'); var ModelBinder = require('backbone.modelbinder');
module.exports = function() { module.exports = function() {
var originalOnRender = this.prototype.onRender; var originalOnRender = this.prototype.onRender;
var originalBeforeClose = this.prototype.onBeforeClose; var originalBeforeClose = this.prototype.onBeforeClose;
this.prototype.onRender = function() { this.prototype.onRender = function() {
if (!this.model) { if (!this.model) {
throw 'View has no model for binding'; throw 'View has no model for binding';
} }
if (!this._modelBinder) { if (!this._modelBinder) {
this._modelBinder = new ModelBinder(); this._modelBinder = new ModelBinder();
} }
var options = { var options = {
changeTriggers : { changeTriggers : {
"" : 'change typeahead:selected typeahead:autocompleted', '' : 'change typeahead:selected typeahead:autocompleted',
"[contenteditable]" : 'blur', '[contenteditable]' : 'blur',
"[data-onkeyup]" : 'keyup' '[data-onkeyup]' : 'keyup'
} }
}; };
this._modelBinder.bind(this.model, this.el, null, options); this._modelBinder.bind(this.model, this.el, null, options);
if (originalOnRender) { if (originalOnRender) {
originalOnRender.call(this); originalOnRender.call(this);
} }
}; };
this.prototype.onBeforeClose = function() { this.prototype.onBeforeClose = function() {
if (this._modelBinder) { if (this._modelBinder) {
this._modelBinder.unbind(); this._modelBinder.unbind();
delete this._modelBinder; delete this._modelBinder;
} }
if (originalBeforeClose) { if (originalBeforeClose) {
originalBeforeClose.call(this); originalBeforeClose.call(this);
} }
}; };
return this; return this;
}; };

@ -8,10 +8,12 @@ module.exports = function(){
if (template) { if (template) {
return template.toLocaleLowerCase().replace('template', '').replace(regex, '-'); return template.toLocaleLowerCase().replace('template', '').replace(regex, '-');
} }
return undefined; return undefined;
}; };
var originalOnRender = this.onRender; var originalOnRender = this.onRender;
this.onRender = function() { this.onRender = function() {
if (window.NzbDrone.NameViews) { if (window.NzbDrone.NameViews) {

@ -2,22 +2,30 @@ var _ = require('underscore');
var Config = require('../Config'); var Config = require('../Config');
module.exports = function() { module.exports = function() {
var originalInit = this.prototype.initialize; var originalInit = this.prototype.initialize;
this.prototype.initialize = function(options) { this.prototype.initialize = function(options) {
options = options || {}; options = options || {};
if (options.tableName) { if (options.tableName) {
this.tableName = options.tableName; this.tableName = options.tableName;
} }
if (!this.tableName && !options.tableName) { if (!this.tableName && !options.tableName) {
throw 'tableName is required'; throw 'tableName is required';
} }
_setInitialState.call(this); _setInitialState.call(this);
this.on('backgrid:sort', _storeStateFromBackgrid, this); this.on('backgrid:sort', _storeStateFromBackgrid, this);
this.on('drone:sort', _storeState, this); this.on('drone:sort', _storeState, this);
if (originalInit) { if (originalInit) {
originalInit.call(this, options); originalInit.call(this, options);
} }
}; };
if (!this.prototype._getSortMapping) { if (!this.prototype._getSortMapping) {
this.prototype._getSortMapping = function(key) { this.prototype._getSortMapping = function(key) {
return { return {
@ -26,30 +34,39 @@ module.exports = function(){
}; };
}; };
} }
var _setInitialState = function() { var _setInitialState = function() {
var key = Config.getValue('{0}.sortKey'.format(this.tableName), this.state.sortKey); 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 direction = Config.getValue('{0}.sortDirection'.format(this.tableName), this.state.order);
var order = parseInt(direction, 10); var order = parseInt(direction, 10);
this.state.sortKey = this._getSortMapping(key).sortKey; this.state.sortKey = this._getSortMapping(key).sortKey;
this.state.order = order; this.state.order = order;
}; };
var _storeStateFromBackgrid = function(column, sortDirection) { var _storeStateFromBackgrid = function(column, sortDirection) {
var order = _convertDirectionToInt(sortDirection); var order = _convertDirectionToInt(sortDirection);
var sortKey = this._getSortMapping(column.get('name')).sortKey; var sortKey = this._getSortMapping(column.get('name')).sortKey;
Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortKey'.format(this.tableName), sortKey);
Config.setValue('{0}.sortDirection'.format(this.tableName), order); Config.setValue('{0}.sortDirection'.format(this.tableName), order);
}; };
var _storeState = function(sortModel, sortDirection) { var _storeState = function(sortModel, sortDirection) {
var order = _convertDirectionToInt(sortDirection); var order = _convertDirectionToInt(sortDirection);
var sortKey = this._getSortMapping(sortModel.get('name')).sortKey; var sortKey = this._getSortMapping(sortModel.get('name')).sortKey;
Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortKey'.format(this.tableName), sortKey);
Config.setValue('{0}.sortDirection'.format(this.tableName), order); Config.setValue('{0}.sortDirection'.format(this.tableName), order);
}; };
var _convertDirectionToInt = function(dir) { var _convertDirectionToInt = function(dir) {
if (dir === 'ascending') { if (dir === 'ascending') {
return '-1'; return '-1';
} }
return '1'; return '1';
}; };
return this; return this;
}; };

@ -2,14 +2,20 @@ var _ = require('underscore');
var Config = require('../Config'); var Config = require('../Config');
module.exports = function() { module.exports = function() {
var originalSetSorting = this.prototype.setSorting; var originalSetSorting = this.prototype.setSorting;
this.prototype.setSorting = function(sortKey, order, options) { this.prototype.setSorting = function(sortKey, order, options) {
var sortMapping = this._getSortMapping(sortKey); 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); return originalSetSorting.call(this, sortMapping.sortKey, order, options);
}; };
this.prototype._getSortMappings = function() { this.prototype._getSortMappings = function() {
var result = {}; var result = {};
if (this.sortMappings) { if (this.sortMappings) {
_.each(this.sortMappings, function(values, key) { _.each(this.sortMappings, function(values, key) {
var item = { var item = {
@ -21,80 +27,104 @@ module.exports = function(){
result[item.sortKey] = item; result[item.sortKey] = item;
}); });
} }
return result; return result;
}; };
this.prototype._getSortMapping = function(key) { this.prototype._getSortMapping = function(key) {
var sortMappings = this._getSortMappings(); var sortMappings = this._getSortMappings();
return sortMappings[key] || { return sortMappings[key] || {
name : key, name : key,
sortKey : key sortKey : key
}; };
}; };
this.prototype._getSecondarySorting = function() { this.prototype._getSecondarySorting = function() {
var sortKey = this.state.secondarySortKey; var sortKey = this.state.secondarySortKey;
var sortOrder = this.state.secondarySortOrder || -1; var sortOrder = this.state.secondarySortOrder || -1;
if (!sortKey || sortKey === this.state.sortKey) { if (!sortKey || sortKey === this.state.sortKey) {
return null; return null;
} }
var sortMapping = this._getSortMapping(sortKey); var sortMapping = this._getSortMapping(sortKey);
if (!sortMapping.sortValue) { if (!sortMapping.sortValue) {
sortMapping.sortValue = function(model, attr) { sortMapping.sortValue = function(model, attr) {
return model.get(attr); return model.get(attr);
}; };
} }
return { return {
key : sortKey, key : sortKey,
order : sortOrder, order : sortOrder,
sortValue : sortMapping.sortValue sortValue : sortMapping.sortValue
}; };
}; };
this.prototype._makeComparator = function(sortKey, order, sortValue) { this.prototype._makeComparator = function(sortKey, order, sortValue) {
var state = this.state; var state = this.state;
var secondarySorting = this._getSecondarySorting(); var secondarySorting = this._getSecondarySorting();
sortKey = sortKey || state.sortKey; sortKey = sortKey || state.sortKey;
order = order || state.order; order = order || state.order;
if (!sortKey || !order) { if (!sortKey || !order) {
return; return;
} }
if (!sortValue) { if (!sortValue) {
sortValue = function(model, attr) { sortValue = function(model, attr) {
return model.get(attr); return model.get(attr);
}; };
} }
return function(left, right) { return function(left, right) {
var l = sortValue(left, sortKey, order); var l = sortValue(left, sortKey, order);
var r = sortValue(right, sortKey, order); var r = sortValue(right, sortKey, order);
var t; var t;
if (order === 1) { if (order === 1) {
t = l; t = l;
l = r; l = r;
r = t; r = t;
} }
if (l === r) { if (l === r) {
if (secondarySorting) { if (secondarySorting) {
var ls = secondarySorting.sortValue(left, secondarySorting.key, order); var ls = secondarySorting.sortValue(left, secondarySorting.key, order);
var rs = secondarySorting.sortValue(right, secondarySorting.key, order); var rs = secondarySorting.sortValue(right, secondarySorting.key, order);
var ts; var ts;
if (secondarySorting.order === 1) { if (secondarySorting.order === 1) {
ts = ls; ts = ls;
ls = rs; ls = rs;
rs = ts; rs = ts;
} }
if (ls === rs) { if (ls === rs) {
return 0; return 0;
} }
if (ls < rs) { if (ls < rs) {
return -1; return -1;
} }
return 1; return 1;
} }
return 0; return 0;
} }
else if (l < r) { else if (l < r) {
return -1; return -1;
} }
return 1; return 1;
}; };
}; };
return this; return this;
}; };

@ -2,19 +2,23 @@ module.exports = function(){
this.prototype.appendHtml = function(collectionView, itemView, index) { this.prototype.appendHtml = function(collectionView, itemView, index) {
var childrenContainer = collectionView.itemViewContainer ? collectionView.$(collectionView.itemViewContainer) : collectionView.$el; var childrenContainer = collectionView.itemViewContainer ? collectionView.$(collectionView.itemViewContainer) : collectionView.$el;
var collection = collectionView.collection; var collection = collectionView.collection;
// If the index of the model is at the end of the collection append, else insert at proper index
if (index >= collection.size() - 1) { if (index >= collection.size() - 1) {
childrenContainer.append(itemView.el); childrenContainer.append(itemView.el);
} } else {
else {
var previousModel = collection.at(index + 1); var previousModel = collection.at(index + 1);
var previousView = this.children.findByModel(previousModel); var previousView = this.children.findByModel(previousModel);
if (previousView) { if (previousView) {
previousView.$el.before(itemView.$el); previousView.$el.before(itemView.$el);
} }
else { else {
childrenContainer.append(itemView.el); childrenContainer.append(itemView.el);
} }
} }
}; };
return this; return this;
}; };

@ -4,28 +4,33 @@ var _ = require('underscore');
module.exports = (function() { module.exports = (function() {
'use strict'; 'use strict';
return function() { return function() {
var originalInitialize = this.prototype.initialize; var originalInitialize = this.prototype.initialize;
var originalOnRender = this.prototype.onRender; var originalOnRender = this.prototype.onRender;
var originalBeforeClose = this.prototype.onBeforeClose; var originalBeforeClose = this.prototype.onBeforeClose;
var errorHandler = function(response) { var errorHandler = function(response) {
if (this.model) { if (this.model) {
this.model.trigger('validation:failed', response); this.model.trigger('validation:failed', response);
} } else {
else {
this.trigger('validation:failed', response); this.trigger('validation:failed', response);
} }
}; };
var validatedSync = function(method, model, options) { var validatedSync = function(method, model, options) {
model.trigger('validation:sync'); model.trigger('validation:sync');
arguments[2].isValidatedCall = true; arguments[2].isValidatedCall = true;
return model._originalSync.apply(this, arguments).fail(errorHandler.bind(this)); return model._originalSync.apply(this, arguments).fail(errorHandler.bind(this));
}; };
var bindToModel = function(model) { var bindToModel = function(model) {
if (!model._originalSync) { if (!model._originalSync) {
model._originalSync = model.sync; model._originalSync = model.sync;
model.sync = validatedSync.bind(this); model.sync = validatedSync.bind(this);
} }
}; };
var validationFailed = function(response) { var validationFailed = function(response) {
if (response.status === 400) { if (response.status === 400) {
var view = this; var view = this;
@ -35,43 +40,54 @@ module.exports = (function(){
}); });
} }
}; };
this.prototype.initialize = function(options) { this.prototype.initialize = function(options) {
if (this.model) { if (this.model) {
this.listenTo(this.model, 'validation:sync', function() { this.listenTo(this.model, 'validation:sync', function() {
this.$el.removeAllErrors(); this.$el.removeAllErrors();
}); });
this.listenTo(this.model, 'validation:failed', validationFailed); this.listenTo(this.model, 'validation:failed', validationFailed);
} } else {
else {
this.listenTo(this, 'validation:sync', function() { this.listenTo(this, 'validation:sync', function() {
this.$el.removeAllErrors(); this.$el.removeAllErrors();
}); });
this.listenTo(this, 'validation:failed', validationFailed); this.listenTo(this, 'validation:failed', validationFailed);
} }
if (originalInitialize) { if (originalInitialize) {
originalInitialize.call(this, options); originalInitialize.call(this, options);
} }
}; };
this.prototype.onRender = function() { this.prototype.onRender = function() {
Validation.bind(this); Validation.bind(this);
this.bindToModelValidation = bindToModel.bind(this); this.bindToModelValidation = bindToModel.bind(this);
if (this.model) { if (this.model) {
this.bindToModelValidation(this.model); this.bindToModelValidation(this.model);
} }
if (originalOnRender) { if (originalOnRender) {
originalOnRender.call(this); originalOnRender.call(this);
} }
}; };
this.prototype.onBeforeClose = function() { this.prototype.onBeforeClose = function() {
if (this.model) { if (this.model) {
Validation.unbind(this); 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.sync = this.model._originalSync;
this.model._originalSync = undefined; this.model._originalSync = undefined;
} }
if (originalBeforeClose) { if (originalBeforeClose) {
originalBeforeClose.call(this); originalBeforeClose.call(this);
} }
}; };
return this; return this;
}; };
}).call(this); }).call(this);

@ -1,17 +1,19 @@
var $ = require('jquery'); var $ = require('jquery');
require('typeahead'); require('typeahead');
module.exports = (function(){
$.fn.autoComplete = function(options) { $.fn.autoComplete = function(options) {
if (!options) { if (!options) {
throw 'options are required'; throw 'options are required';
} }
if (!options.resource) { if (!options.resource) {
throw 'resource is required'; throw 'resource is required';
} }
if (!options.query) { if (!options.query) {
throw 'query is required'; throw 'query is required';
} }
$(this).typeahead({ $(this).typeahead({
hint : true, hint : true,
highlight : true, highlight : true,
@ -31,14 +33,15 @@ module.exports = (function(){
success : function(response) { success : function(response) {
if (options.filter) { if (options.filter) {
options.filter.call(this, filter, response, callback); options.filter.call(this, filter, response, callback);
} } else {
else {
var matches = []; var matches = [];
$.each(response, function(i, d) { $.each(response, function(i, d) {
if (d[options.query] && d[options.property].startsWith(filter)) { if (d[options.query] && d[options.property].startsWith(filter)) {
matches.push({ value : d[options.property] }); matches.push({ value : d[options.property] });
} }
}); });
callback(matches); callback(matches);
} }
} }
@ -46,4 +49,3 @@ module.exports = (function(){
} }
}); });
}; };
}).call(this);

@ -1,21 +1,22 @@
var $ = require('jquery'); var $ = require('jquery');
require('./AutoComplete'); require('./AutoComplete');
module.exports = (function(){
$.fn.directoryAutoComplete = function() { $.fn.directoryAutoComplete = function() {
var query = 'path'; var query = 'path';
$(this).autoComplete({ $(this).autoComplete({
resource : '/filesystem', resource : '/filesystem',
query : query, query : query,
filter : function(filter, response, callback) { filter : function(filter, response, callback) {
var matches = []; var matches = [];
$.each(response.directories, function(i, d) { $.each(response.directories, function(i, d) {
if (d[query] && d[query].startsWith(filter)) { if (d[query] && d[query].startsWith(filter)) {
matches.push({ value : d[query] }); matches.push({ value : d[query] });
} }
}); });
callback(matches); callback(matches);
} }
}); });
}; };
}).call(this);

@ -1,29 +1,31 @@
var $ = require('jquery'); var $ = require('jquery');
var vent = require('vent'); var vent = require('vent');
require('../Shared/FileBrowser/FileBrowserLayout'); require('../Shared/FileBrowser/FileBrowserLayout');
require('./DirectoryAutoComplete'); require('./DirectoryAutoComplete');
module.exports = (function(){
$.fn.fileBrowser = function(options) { $.fn.fileBrowser = function(options) {
var inputs = $(this); var inputs = $(this);
inputs.each(function() { inputs.each(function() {
var input = $(this); var input = $(this);
var inputOptions = $.extend({ input : input }, options); var inputOptions = $.extend({ input : input }, options);
var inputGroup = $('<div class="input-group"></div>'); var inputGroup = $('<div class="input-group"></div>');
var inputGroupButton = $('<span class="input-group-btn "></span>'); 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>'); 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) { if (input.parent('.input-group').length > 0) {
input.parent('.input-group').find('.input-group-btn').prepend(button); input.parent('.input-group').find('.input-group-btn').prepend(button);
} } else {
else {
inputGroupButton.append(button); inputGroupButton.append(button);
input.wrap(inputGroup); input.wrap(inputGroup);
input.after(inputGroupButton); input.after(inputGroupButton);
} }
button.on('click', function() { button.on('click', function() {
vent.trigger(vent.Commands.ShowFileBrowser, inputOptions); vent.trigger(vent.Commands.ShowFileBrowser, inputOptions);
}); });
}); });
inputs.directoryAutoComplete(); inputs.directoryAutoComplete();
}; };
}).call(this);

@ -4,50 +4,88 @@ var TagCollection = require('../Tags/TagCollection');
var TagModel = require('../Tags/TagModel'); var TagModel = require('../Tags/TagModel');
require('bootstrap.tagsinput'); require('bootstrap.tagsinput');
module.exports = (function(){ 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);
};
};
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 originalAdd = $.fn.tagsinput.Constructor.prototype.add;
var originalRemove = $.fn.tagsinput.Constructor.prototype.remove; var originalRemove = $.fn.tagsinput.Constructor.prototype.remove;
var originalBuild = $.fn.tagsinput.Constructor.prototype.build; var originalBuild = $.fn.tagsinput.Constructor.prototype.build;
$.fn.tagsinput.Constructor.prototype.add = function(item, dontPushVal) { $.fn.tagsinput.Constructor.prototype.add = function(item, dontPushVal) {
var self = this; var self = this;
if (typeof item === 'string' && this.options.tag) { if (typeof item === 'string' && this.options.tag) {
var test = testTag(item); var test = testTag(item);
if (item === null || item === '' || !testTag(item)) { if (item === null || item === '' || !testTag(item)) {
return; return;
} }
var existing = _.find(TagCollection.toJSON(), { label : item }); var existing = _.find(TagCollection.toJSON(), { label : item });
if (existing) { if (existing) {
originalAdd.call(this, existing, dontPushVal); originalAdd.call(this, existing, dontPushVal);
} } else {
else {
var newTag = new TagModel(); var newTag = new TagModel();
newTag.set({ label : item.toLowerCase() }); newTag.set({ label : item.toLowerCase() });
TagCollection.add(newTag); TagCollection.add(newTag);
newTag.save().done(function() { newTag.save().done(function() {
item = newTag.toJSON(); item = newTag.toJSON();
originalAdd.call(self, item, dontPushVal); originalAdd.call(self, item, dontPushVal);
}); });
} }
} } else {
else {
originalAdd.call(this, item, dontPushVal); originalAdd.call(this, item, dontPushVal);
} }
if (this.options.tag) { if (this.options.tag) {
self.$input.typeahead('val', ''); self.$input.typeahead('val', '');
} }
}; };
$.fn.tagsinput.Constructor.prototype.remove = function(item, dontPushVal) { $.fn.tagsinput.Constructor.prototype.remove = function(item, dontPushVal) {
if (item === null) { if (item === null) {
return; return;
} }
originalRemove.call(this, item, dontPushVal); originalRemove.call(this, item, dontPushVal);
}; };
$.fn.tagsinput.Constructor.prototype.build = function(options) { $.fn.tagsinput.Constructor.prototype.build = function(options) {
var self = this; var self = this;
var defaults = { var defaults = {
confirmKeys : [9, 13, 32, 44, 59] confirmKeys : [
9,
13,
32,
44,
59
] //tab, enter, space, comma, semi-colon
}; };
options = $.extend({}, defaults, options); options = $.extend({}, defaults, options);
self.$input.on('keydown', function(event) { self.$input.on('keydown', function(event) {
if (event.which === 9) { if (event.which === 9) {
var e = $.Event('keypress'); var e = $.Event('keypress');
@ -56,17 +94,21 @@ module.exports = (function(){
event.preventDefault(); event.preventDefault();
} }
}); });
self.$input.on('focusout', function() { self.$input.on('focusout', function() {
self.add(self.$input.val()); self.add(self.$input.val());
self.$input.val(''); self.$input.val('');
}); });
originalBuild.call(this, options); originalBuild.call(this, options);
}; };
$.fn.tagInput = function(options) { $.fn.tagInput = function(options) {
var input = this; var input = this;
var model = options.model; var model = options.model;
var property = options.property; var property = options.property;
var tags = getExistingTags(model.get(property)); var tags = getExistingTags(model.get(property));
var tagInput = $(this).tagsinput({ var tagInput = $(this).tagsinput({
tag : true, tag : true,
freeInput : true, freeInput : true,
@ -79,7 +121,11 @@ module.exports = (function(){
source : substringMatcher() source : substringMatcher()
} }
}); });
//Override the free input being set to false because we're using objects
$(tagInput)[0].options.freeInput = true; $(tagInput)[0].options.freeInput = true;
//Remove any existing tags and re-add them
$(this).tagsinput('removeAll'); $(this).tagsinput('removeAll');
_.each(tags, function(tag) { _.each(tags, function(tag) {
$(input).tagsinput('add', tag); $(input).tagsinput('add', tag);
@ -98,26 +144,3 @@ module.exports = (function(){
model.set(property, tags); 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;
});
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;
}
};
}).call(this);

@ -6,26 +6,36 @@ require('signalR');
module.exports = _.extend(Backbone.Collection.prototype, { module.exports = _.extend(Backbone.Collection.prototype, {
bindSignalR : function(bindOptions) { bindSignalR : function(bindOptions) {
var collection = this; var collection = this;
bindOptions = bindOptions || {}; bindOptions = bindOptions || {};
var processMessage = function(options) { var processMessage = function(options) {
if (options.action === 'sync') { if (options.action === 'sync') {
console.log('sync received, re-fetching collection'); console.log('sync received, re-fetching collection');
collection.fetch(); collection.fetch();
return; return;
} }
if (options.action === 'deleted') { if (options.action === 'deleted') {
collection.remove(new collection.model(options.resource, { parse : true })); collection.remove(new collection.model(options.resource, { parse : true }));
return; return;
} }
var model = new collection.model(options.resource, { parse : true }); 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'))) { if (bindOptions.updateOnly && !collection.get(model.get('id'))) {
return; return;
} }
collection.add(model, { collection.add(model, {
merge : true, merge : true,
changeSource : 'signalr' changeSource : 'signalr'
}); });
console.log(options.action + ': {0}}'.format(options.resource)); console.log(options.action + ': {0}}'.format(options.resource));
}; };

@ -2,46 +2,64 @@ var Backbone = require('backbone');
var $ = require('jquery'); var $ = require('jquery');
var StatusModel = require('../System/StatusModel'); 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 = { var routeBinder = {
bind : function() { bind : function() {
var self = this; var self = this;
$(document).on('click', 'a[href]', function(event) { $(document).on('click', 'a[href]', function(event) {
self._handleClick(event); self._handleClick(event);
}); });
}, },
_handleClick : function(event) { _handleClick : function(event) {
var $target = $(event.target); var $target = $(event.target);
//check if tab nav
if ($target.parents('.nav-tabs').length) { if ($target.parents('.nav-tabs').length) {
return; return;
} }
if ($target.hasClass('no-router')) { if ($target.hasClass('no-router')) {
return; return;
} }
var href = event.target.getAttribute('href'); 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]; var linkElement = $target.closest('a')[0];
if ($(linkElement).hasClass('no-router')) { if ($(linkElement).hasClass('no-router')) {
return; return;
} }
href = linkElement.getAttribute('href'); href = linkElement.getAttribute('href');
} }
event.preventDefault(); event.preventDefault();
if (!href) { if (!href) {
throw 'couldn\'t find route target'; throw 'couldn\'t find route target';
} }
if (!href.startsWith('http')) { if (!href.startsWith('http')) {
if (event.ctrlKey) { if (event.ctrlKey) {
window.open(href, '_blank'); window.open(href, '_blank');
} }
else { else {
var relativeHref = href.replace(StatusModel.get('urlBase'), ''); 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'); window.open(href, '_blank');
} } else {
else { //Open in new tab
window.open('http://www.dereferer.org/?' + encodeURI(href), '_blank'); window.open('http://www.dereferer.org/?' + encodeURI(href), '_blank');
} }
} }

@ -1,7 +1,6 @@
var $ = require('jquery'); var $ = require('jquery');
var _ = require('underscore'); var _ = require('underscore');
$(document).ready(function() { $(document).ready(function() {
var _window = $(window); var _window = $(window);
var _scrollButton = $('#scroll-up'); var _scrollButton = $('#scroll-up');
@ -9,8 +8,7 @@ $(document).ready(function(){
var _scrollHandler = function() { var _scrollHandler = function() {
if (_window.scrollTop() > 100) { if (_window.scrollTop() > 100) {
_scrollButton.fadeIn(); _scrollButton.fadeIn();
} } else {
else {
_scrollButton.fadeOut(); _scrollButton.fadeOut();
} }
}; };

@ -8,8 +8,7 @@ module.exports = function(){
if (xhr && xhr.data && xhr.type === 'DELETE') { if (xhr && xhr.data && xhr.type === 'DELETE') {
if (xhr.url.contains('?')) { if (xhr.url.contains('?')) {
xhr.url += '&'; xhr.url += '&';
} } else {
else {
xhr.url += '?'; xhr.url += '?';
} }
xhr.url += $.param(xhr.data); xhr.url += $.param(xhr.data);

@ -5,43 +5,56 @@ module.exports = function(){
$.fn.spinForPromise = function(promise) { $.fn.spinForPromise = function(promise) {
var self = this; var self = this;
if (!promise || promise.state() !== 'pending') { if (!promise || promise.state() !== 'pending') {
return this; return this;
} }
promise.always(function() { promise.always(function() {
self.stopSpin(); self.stopSpin();
}); });
return this.startSpin(); return this.startSpin();
}; };
$.fn.startSpin = function() { $.fn.startSpin = function() {
var icon = this.find('i').andSelf('i'); var icon = this.find('i').andSelf('i');
if (!icon || !icon.attr('class')) { if (!icon || !icon.attr('class')) {
return this; return this;
} }
var iconClasses = icon.attr('class').match(/(?:^|\s)icon\-.+?(?:$|\s)/); var iconClasses = icon.attr('class').match(/(?:^|\s)icon\-.+?(?:$|\s)/);
if (iconClasses.length === 0) { if (iconClasses.length === 0) {
return this; return this;
} }
var iconClass = $.trim(iconClasses[0]); var iconClass = $.trim(iconClasses[0]);
this.addClass('disabled'); this.addClass('disabled');
if (icon.hasClass('icon-can-spin')) { if (icon.hasClass('icon-can-spin')) {
icon.addClass('icon-spin'); icon.addClass('icon-spin');
} } else {
else {
icon.attr('data-idle-icon', iconClass); icon.attr('data-idle-icon', iconClass);
icon.removeClass(iconClass); icon.removeClass(iconClass);
icon.addClass('icon-nd-spinner'); icon.addClass('icon-nd-spinner');
} }
return this; return this;
}; };
$.fn.stopSpin = function() { $.fn.stopSpin = function() {
var icon = this.find('i').andSelf('i'); var icon = this.find('i').andSelf('i');
this.removeClass('disabled'); this.removeClass('disabled');
icon.removeClass('icon-spin icon-nd-spinner'); icon.removeClass('icon-spin icon-nd-spinner');
var idleIcon = icon.attr('data-idle-icon'); var idleIcon = icon.attr('data-idle-icon');
if (idleIcon) { if (idleIcon) {
icon.addClass(idleIcon); icon.addClass(idleIcon);
} }
return this; return this;
}; };
}; };

@ -3,52 +3,71 @@ module.exports = function(){
var $ = this; var $ = this;
$.fn.processServerError = function(error) { $.fn.processServerError = function(error) {
var validationName = error.propertyName.toLowerCase(); var validationName = error.propertyName.toLowerCase();
var errorMessage = this.formatErrorMessage(error); var errorMessage = this.formatErrorMessage(error);
this.find('.validation-errors').addClass('alert alert-danger').append('<div><i class="icon-exclamation-sign"></i>' + errorMessage + '</div>'); this.find('.validation-errors').addClass('alert alert-danger').append('<div><i class="icon-exclamation-sign"></i>' + errorMessage + '</div>');
if (!validationName || validationName === '') { if (!validationName || validationName === '') {
this.addFormError(error); this.addFormError(error);
return this; return this;
} }
var input = this.find('[name]').filter(function() { var input = this.find('[name]').filter(function() {
return this.name.toLowerCase() === validationName; return this.name.toLowerCase() === validationName;
}); });
if (input.length === 0) { if (input.length === 0) {
input = this.find('[validation-name]').filter(function() { input = this.find('[validation-name]').filter(function() {
return $(this).attr('validation-name').toLowerCase() === validationName; return $(this).attr('validation-name').toLowerCase() === validationName;
}); });
//still not found?
if (input.length === 0) { if (input.length === 0) {
this.addFormError(error); this.addFormError(error);
console.error('couldn\'t find input for ' + error.propertyName); console.error('couldn\'t find input for ' + error.propertyName);
return this; return this;
} }
} }
var formGroup = input.parents('.form-group'); var formGroup = input.parents('.form-group');
if (formGroup.length === 0) { if (formGroup.length === 0) {
formGroup = input.parent(); formGroup = input.parent();
} } else {
else {
var inputGroup = formGroup.find('.input-group'); var inputGroup = formGroup.find('.input-group');
if (inputGroup.length === 0) { if (inputGroup.length === 0) {
formGroup.append('<span class="help-inline validation-error">' + errorMessage + '</span>'); formGroup.append('<span class="help-inline validation-error">' + errorMessage + '</span>');
} }
else { else {
inputGroup.parent().append('<span class="help-block validation-error">' + errorMessage + '</span>'); inputGroup.parent().append('<span class="help-block validation-error">' + errorMessage + '</span>');
} }
} }
formGroup.addClass('has-error'); formGroup.addClass('has-error');
return formGroup.find('.help-inline').text(); 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); var errorMessage = this.formatErrorMessage(error);
if (this.find('.modal-body')) { if (this.find('.modal-body')) {
this.find('.modal-body').prepend('<div class="alert alert-danger validation-error">' + errorMessage + '</div>'); this.find('.modal-body').prepend('<div class="alert alert-danger validation-error">' + errorMessage + '</div>');
} }
else { else {
this.prepend('<div class="alert alert-danger validation-error">' + errorMessage + '</div>'); this.prepend('<div class="alert alert-danger validation-error">' + errorMessage + '</div>');
} }
}; };
$.fn.removeAllErrors = function() { $.fn.removeAllErrors = function() {
this.find('.has-error').removeClass('has-error'); this.find('.has-error').removeClass('has-error');
this.find('.error').removeClass('error'); this.find('.error').removeClass('error');
@ -56,19 +75,21 @@ module.exports = function(){
this.find('.validation-error').remove(); this.find('.validation-error').remove();
return this.find('.help-inline.error-message').remove(); return this.find('.help-inline.error-message').remove();
}; };
$.fn.formatErrorMessage = function(error) { $.fn.formatErrorMessage = function(error) {
var errorMessage = error.errorMessage; var errorMessage = error.errorMessage;
if (error.infoLink) { if (error.infoLink) {
if (error.detailedDescription) { if (error.detailedDescription) {
errorMessage += ' <a class="no-router" target="_blank" href="' + error.infoLink + '"><i class="icon-external-link" title="' + error.detailedDescription + '"></i></a>'; errorMessage += ' <a class="no-router" target="_blank" href="' + error.infoLink + '"><i class="icon-external-link" title="' + error.detailedDescription + '"></i></a>';
} } else {
else {
errorMessage += ' <a class="no-router" target="_blank" href="' + error.infoLink + '"><i class="icon-external-link"></i></a>'; errorMessage += ' <a class="no-router" target="_blank" href="' + error.infoLink + '"><i class="icon-external-link"></i></a>';
} }
} } else if (error.detailedDescription) {
else if(error.detailedDescription) {
errorMessage += ' <i class="icon-nd-form-info" title="' + error.detailedDescription + '"></i>'; errorMessage += ' <i class="icon-nd-form-info" title="' + error.detailedDescription + '"></i>';
} }
return errorMessage; return errorMessage;
}; };
}; };
Loading…
Cancel
Save