Integration with Backbone.stickit + rework of nodes statistics using stickit
Change-Id: Ic196115d4fc1f081154cea711afc97448665a629
This commit is contained in:
parent
179f65e28f
commit
4a1ae9f867
@ -160,6 +160,10 @@ function(models, commonViews, ClusterPage, NodesTab, ClustersPage, ReleasesPage,
|
||||
return originalSync.apply(this, args);
|
||||
};
|
||||
|
||||
window.Coccyx.addTearDownCallback(function() {
|
||||
this.unstickit();
|
||||
});
|
||||
|
||||
window.isWebkit = navigator.userAgent.indexOf('AppleWebKit/') !== -1;
|
||||
|
||||
var app = new AppRouter();
|
||||
|
500
nailgun/static/js/libs/backbone.stickit.js
Normal file
500
nailgun/static/js/libs/backbone.stickit.js
Normal file
@ -0,0 +1,500 @@
|
||||
(function(Backbone) {
|
||||
var $ = Backbone.$ || window.jQuery || window.Zepto;
|
||||
|
||||
// Backbone.Stickit Namespace
|
||||
// --------------------------
|
||||
|
||||
Backbone.Stickit = {
|
||||
|
||||
_handlers: [],
|
||||
|
||||
addHandler: function(handlers) {
|
||||
// Fill-in default values.
|
||||
handlers = _.map(_.flatten([handlers]), function(handler) {
|
||||
return _.extend({
|
||||
updateModel: true,
|
||||
updateView: true,
|
||||
updateMethod: 'text'
|
||||
}, handler);
|
||||
});
|
||||
this._handlers = this._handlers.concat(handlers);
|
||||
}
|
||||
};
|
||||
|
||||
// Backbone.View Mixins
|
||||
// --------------------
|
||||
|
||||
_.extend(Backbone.View.prototype, {
|
||||
|
||||
// Collection of model event bindings.
|
||||
// [{model,event,fn}, ...]
|
||||
_modelBindings: null,
|
||||
|
||||
// Unbind the model and event bindings from `this._modelBindings` and
|
||||
// `this.$el`. If the optional `model` parameter is defined, then only
|
||||
// delete bindings for the given `model` and its corresponding view events.
|
||||
unstickit: function(model) {
|
||||
var models = [];
|
||||
_.each(this._modelBindings, function(binding, i) {
|
||||
if (model && binding.model !== model) return false;
|
||||
binding.model.off(binding.event, binding.fn);
|
||||
models.push(binding.model);
|
||||
delete this._modelBindings[i];
|
||||
}, this);
|
||||
|
||||
// Trigger an event for each model that was unbound.
|
||||
_.invoke(_.uniq(models), 'trigger', 'stickit:unstuck', this.cid);
|
||||
// Cleanup the null values.
|
||||
this._modelBindings = _.compact(this._modelBindings);
|
||||
|
||||
this.$el.off('.stickit' + (model ? '.' + model.cid : ''));
|
||||
},
|
||||
|
||||
// Using `this.bindings` configuration or the `optionalBindingsConfig`, binds `this.model`
|
||||
// or the `optionalModel` to elements in the view.
|
||||
stickit: function(optionalModel, optionalBindingsConfig) {
|
||||
var model = optionalModel || this.model,
|
||||
namespace = '.stickit.' + model.cid,
|
||||
bindings = optionalBindingsConfig || this.bindings || {};
|
||||
|
||||
this._modelBindings || (this._modelBindings = []);
|
||||
this.unstickit(model);
|
||||
|
||||
// Iterate through the selectors in the bindings configuration and configure
|
||||
// the various options for each field.
|
||||
_.each(bindings, function(v, selector) {
|
||||
var $el, options, modelAttr, config,
|
||||
binding = bindings[selector] || {},
|
||||
bindId = _.uniqueId();
|
||||
|
||||
// Support ':el' selector - special case selector for the view managed delegate.
|
||||
$el = selector === ':el' ? this.$el : this.$(selector);
|
||||
|
||||
// Fail fast if the selector didn't match an element.
|
||||
if (!$el.length) return;
|
||||
|
||||
// Allow shorthand setting of model attributes - `'selector':'observe'`.
|
||||
if (_.isString(binding)) binding = {observe:binding};
|
||||
|
||||
// Handle case where `observe` is in the form of a function.
|
||||
if (_.isFunction(binding.observe)) binding.observe = binding.observe.call(this);
|
||||
|
||||
config = getConfiguration($el, binding);
|
||||
|
||||
modelAttr = config.observe;
|
||||
|
||||
// Create the model set options with a unique `bindId` so that we
|
||||
// can avoid double-binding in the `change:attribute` event handler.
|
||||
config.bindId = bindId;
|
||||
// Add a reference to the view for handlers of stickitChange events
|
||||
config.view = this;
|
||||
options = _.extend({stickitChange:config}, config.setOptions);
|
||||
|
||||
initializeAttributes(this, $el, config, model, modelAttr);
|
||||
|
||||
initializeVisible(this, $el, config, model, modelAttr);
|
||||
|
||||
if (modelAttr) {
|
||||
// Setup one-way, form element to model, bindings.
|
||||
_.each(config.events, function(type) {
|
||||
var event = type + namespace;
|
||||
var method = function(event) {
|
||||
var val = config.getVal.call(this, $el, event, config, _.rest(arguments));
|
||||
// Don't update the model if false is returned from the `updateModel` configuration.
|
||||
if (evaluateBoolean(this, config.updateModel, val, config))
|
||||
setAttr(model, modelAttr, val, options, this, config);
|
||||
};
|
||||
if (selector === ':el') this.$el.on(event, method);
|
||||
else this.$el.on(event, selector, method);
|
||||
}, this);
|
||||
|
||||
// Setup a `change:modelAttr` observer to keep the view element in sync.
|
||||
// `modelAttr` may be an array of attributes or a single string value.
|
||||
_.each(_.flatten([modelAttr]), function(attr) {
|
||||
observeModelEvent(model, this, 'change:'+attr, function(model, val, options) {
|
||||
var changeId = options && options.stickitChange && options.stickitChange.bindId || null;
|
||||
if (changeId !== bindId)
|
||||
updateViewBindEl(this, $el, config, getAttr(model, modelAttr, config, this), model);
|
||||
});
|
||||
}, this);
|
||||
|
||||
updateViewBindEl(this, $el, config, getAttr(model, modelAttr, config, this), model, true);
|
||||
}
|
||||
|
||||
model.on('stickit:unstuck', function(cid) {
|
||||
if (cid === this.cid) applyViewFn(this, config.destroy, $el, model, config);
|
||||
}, this);
|
||||
|
||||
// After each binding is setup, call the `initialize` callback.
|
||||
applyViewFn(this, config.initialize, $el, model, config);
|
||||
}, this);
|
||||
|
||||
// Wrap `view.remove` to unbind stickit model and dom events.
|
||||
var remove = this.remove;
|
||||
this.remove = function() {
|
||||
var ret = this;
|
||||
this.unstickit();
|
||||
if (remove) ret = remove.apply(this, _.rest(arguments));
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Helpers
|
||||
// -------
|
||||
|
||||
// Evaluates the given `path` (in object/dot-notation) relative to the given
|
||||
// `obj`. If the path is null/undefined, then the given `obj` is returned.
|
||||
var evaluatePath = function(obj, path) {
|
||||
var parts = (path || '').split('.');
|
||||
var result = _.reduce(parts, function(memo, i) { return memo[i]; }, obj);
|
||||
return result == null ? obj : result;
|
||||
};
|
||||
|
||||
// If the given `fn` is a string, then view[fn] is called, otherwise it is
|
||||
// a function that should be executed.
|
||||
var applyViewFn = function(view, fn) {
|
||||
if (fn) return (_.isString(fn) ? view[fn] : fn).apply(view, _.rest(arguments, 2));
|
||||
};
|
||||
|
||||
var getSelectedOption = function($select) { return $select.find('option').not(function(){ return !this.selected; }); };
|
||||
|
||||
// Given a function, string (view function reference), or a boolean
|
||||
// value, returns the truthy result. Any other types evaluate as false.
|
||||
var evaluateBoolean = function(view, reference) {
|
||||
if (_.isBoolean(reference)) return reference;
|
||||
else if (_.isFunction(reference) || _.isString(reference))
|
||||
return applyViewFn.apply(this, arguments);
|
||||
return false;
|
||||
};
|
||||
|
||||
// Setup a model event binding with the given function, and track the event
|
||||
// in the view's _modelBindings.
|
||||
var observeModelEvent = function(model, view, event, fn) {
|
||||
model.on(event, fn, view);
|
||||
view._modelBindings.push({model:model, event:event, fn:fn});
|
||||
};
|
||||
|
||||
// Prepares the given `val`ue and sets it into the `model`.
|
||||
var setAttr = function(model, attr, val, options, context, config) {
|
||||
if (config.onSet) val = applyViewFn(context, config.onSet, val, config);
|
||||
model.set(attr, val, options);
|
||||
};
|
||||
|
||||
// Returns the given `attr`'s value from the `model`, escaping and
|
||||
// formatting if necessary. If `attr` is an array, then an array of
|
||||
// respective values will be returned.
|
||||
var getAttr = function(model, attr, config, context) {
|
||||
var val,
|
||||
retrieveVal = function(field) {
|
||||
return model[config.escape ? 'escape' : 'get'](field);
|
||||
},
|
||||
sanitizeVal = function(val) {
|
||||
return val == null ? '' : val;
|
||||
};
|
||||
val = _.isArray(attr) ? _.map(attr, retrieveVal) : retrieveVal(attr);
|
||||
if (config.onGet) val = applyViewFn(context, config.onGet, val, config);
|
||||
return _.isArray(val) ? _.map(val, sanitizeVal) : sanitizeVal(val);
|
||||
};
|
||||
|
||||
// Find handlers in `Backbone.Stickit._handlers` with selectors that match
|
||||
// `$el` and generate a configuration by mixing them in the order that they
|
||||
// were found with the given `binding`.
|
||||
var getConfiguration = Backbone.Stickit.getConfiguration = function($el, binding) {
|
||||
var handlers = [{
|
||||
updateModel: false,
|
||||
updateMethod: 'text',
|
||||
update: function($el, val, m, opts) { if ($el[opts.updateMethod]) $el[opts.updateMethod](val); },
|
||||
getVal: function($el, e, opts) { return $el[opts.updateMethod](); }
|
||||
}];
|
||||
handlers = handlers.concat(_.filter(Backbone.Stickit._handlers, function(handler) {
|
||||
return $el.is(handler.selector);
|
||||
}));
|
||||
handlers.push(binding);
|
||||
var config = _.extend.apply(_, handlers);
|
||||
// `updateView` is defaulted to false for configutrations with
|
||||
// `visible`; otherwise, `updateView` is defaulted to true.
|
||||
if (config.visible && !_.has(config, 'updateView')) config.updateView = false;
|
||||
else if (!_.has(config, 'updateView')) config.updateView = true;
|
||||
delete config.selector;
|
||||
return config;
|
||||
};
|
||||
|
||||
// Setup the attributes configuration - a list that maps an attribute or
|
||||
// property `name`, to an `observe`d model attribute, using an optional
|
||||
// `onGet` formatter.
|
||||
//
|
||||
// attributes: [{
|
||||
// name: 'attributeOrPropertyName',
|
||||
// observe: 'modelAttrName'
|
||||
// onGet: function(modelAttrVal, modelAttrName) { ... }
|
||||
// }, ...]
|
||||
//
|
||||
var initializeAttributes = function(view, $el, config, model, modelAttr) {
|
||||
var props = ['autofocus', 'autoplay', 'async', 'checked', 'controls', 'defer', 'disabled', 'hidden', 'loop', 'multiple', 'open', 'readonly', 'required', 'scoped', 'selected'];
|
||||
|
||||
_.each(config.attributes || [], function(attrConfig) {
|
||||
var lastClass = '', observed, updateAttr;
|
||||
attrConfig = _.clone(attrConfig);
|
||||
observed = attrConfig.observe || (attrConfig.observe = modelAttr),
|
||||
updateAttr = function() {
|
||||
var updateType = _.indexOf(props, attrConfig.name, true) > -1 ? 'prop' : 'attr',
|
||||
val = getAttr(model, observed, attrConfig, view);
|
||||
// If it is a class then we need to remove the last value and add the new.
|
||||
if (attrConfig.name === 'class') {
|
||||
$el.removeClass(lastClass).addClass(val);
|
||||
lastClass = val;
|
||||
}
|
||||
else $el[updateType](attrConfig.name, val);
|
||||
};
|
||||
_.each(_.flatten([observed]), function(attr) {
|
||||
observeModelEvent(model, view, 'change:' + attr, updateAttr);
|
||||
});
|
||||
updateAttr();
|
||||
});
|
||||
};
|
||||
|
||||
// If `visible` is configured, then the view element will be shown/hidden
|
||||
// based on the truthiness of the modelattr's value or the result of the
|
||||
// given callback. If a `visibleFn` is also supplied, then that callback
|
||||
// will be executed to manually handle showing/hiding the view element.
|
||||
//
|
||||
// observe: 'isRight',
|
||||
// visible: true, // or function(val, options) {}
|
||||
// visibleFn: function($el, isVisible, options) {} // optional handler
|
||||
//
|
||||
var initializeVisible = function(view, $el, config, model, modelAttr) {
|
||||
if (config.visible == null) return;
|
||||
var visibleCb = function() {
|
||||
var visible = config.visible,
|
||||
visibleFn = config.visibleFn,
|
||||
val = getAttr(model, modelAttr, config, view),
|
||||
isVisible = !!val;
|
||||
// If `visible` is a function then it should return a boolean result to show/hide.
|
||||
if (_.isFunction(visible) || _.isString(visible)) isVisible = applyViewFn(view, visible, val, config);
|
||||
// Either use the custom `visibleFn`, if provided, or execute the standard show/hide.
|
||||
if (visibleFn) applyViewFn(view, visibleFn, $el, isVisible, config);
|
||||
else {
|
||||
$el.toggle(isVisible);
|
||||
}
|
||||
};
|
||||
_.each(_.flatten([modelAttr]), function(attr) {
|
||||
observeModelEvent(model, view, 'change:' + attr, visibleCb);
|
||||
});
|
||||
visibleCb();
|
||||
};
|
||||
|
||||
// Update the value of `$el` using the given configuration and trigger the
|
||||
// `afterUpdate` callback. This action may be blocked by `config.updateView`.
|
||||
//
|
||||
// update: function($el, val, model, options) {}, // handler for updating
|
||||
// updateView: true, // defaults to true
|
||||
// afterUpdate: function($el, val, options) {} // optional callback
|
||||
//
|
||||
var updateViewBindEl = function(view, $el, config, val, model, isInitializing) {
|
||||
if (!evaluateBoolean(view, config.updateView, val, config)) return;
|
||||
applyViewFn(view, config.update, $el, val, model, config);
|
||||
if (!isInitializing) applyViewFn(view, config.afterUpdate, $el, val, config);
|
||||
};
|
||||
|
||||
// Default Handlers
|
||||
// ----------------
|
||||
|
||||
Backbone.Stickit.addHandler([{
|
||||
selector: '[contenteditable="true"]',
|
||||
updateMethod: 'html',
|
||||
events: ['input', 'change']
|
||||
}, {
|
||||
selector: 'input',
|
||||
events: ['propertychange', 'input', 'change'],
|
||||
update: function($el, val) { $el.val(val); },
|
||||
getVal: function($el) {
|
||||
return $el.val();
|
||||
}
|
||||
}, {
|
||||
selector: 'textarea',
|
||||
events: ['propertychange', 'input', 'change'],
|
||||
update: function($el, val) { $el.val(val); },
|
||||
getVal: function($el) { return $el.val(); }
|
||||
}, {
|
||||
selector: 'input[type="radio"]',
|
||||
events: ['change'],
|
||||
update: function($el, val) {
|
||||
$el.filter('[value="'+val+'"]').prop('checked', true);
|
||||
},
|
||||
getVal: function($el) {
|
||||
return $el.filter(':checked').val();
|
||||
}
|
||||
}, {
|
||||
selector: 'input[type="checkbox"]',
|
||||
events: ['change'],
|
||||
update: function($el, val, model, options) {
|
||||
if ($el.length > 1) {
|
||||
// There are multiple checkboxes so we need to go through them and check
|
||||
// any that have value attributes that match what's in the array of `val`s.
|
||||
val || (val = []);
|
||||
_.each($el, function(el) {
|
||||
if (_.indexOf(val, $(el).val()) > -1) $(el).prop('checked', true);
|
||||
else $(el).prop('checked', false);
|
||||
});
|
||||
} else {
|
||||
if (_.isBoolean(val)) $el.prop('checked', val);
|
||||
else $el.prop('checked', val === $el.val());
|
||||
}
|
||||
},
|
||||
getVal: function($el) {
|
||||
var val;
|
||||
if ($el.length > 1) {
|
||||
val = _.reduce($el, function(memo, el) {
|
||||
if ($(el).prop('checked')) memo.push($(el).val());
|
||||
return memo;
|
||||
}, []);
|
||||
} else {
|
||||
val = $el.prop('checked');
|
||||
// If the checkbox has a value attribute defined, then
|
||||
// use that value. Most browsers use "on" as a default.
|
||||
var boxval = $el.val();
|
||||
if (boxval !== 'on' && boxval != null) {
|
||||
val = val ? $el.val() : null;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}, {
|
||||
selector: 'select',
|
||||
events: ['change'],
|
||||
update: function($el, val, model, options) {
|
||||
var optList,
|
||||
selectConfig = options.selectOptions,
|
||||
list = selectConfig && selectConfig.collection || undefined,
|
||||
isMultiple = $el.prop('multiple');
|
||||
|
||||
// If there are no `selectOptions` then we assume that the `<select>`
|
||||
// is pre-rendered and that we need to generate the collection.
|
||||
if (!selectConfig) {
|
||||
selectConfig = {};
|
||||
var getList = function($el) {
|
||||
return $el.map(function() {
|
||||
return {value:this.value, label:this.text};
|
||||
}).get();
|
||||
};
|
||||
if ($el.find('optgroup').length) {
|
||||
list = {opt_labels:[]};
|
||||
// Search for options without optgroup
|
||||
if ($el.find('> option').length) {
|
||||
list.opt_labels.push(undefined);
|
||||
_.each($el.find('> option'), function(el) {
|
||||
list[undefined] = getList($(el));
|
||||
});
|
||||
}
|
||||
_.each($el.find('optgroup'), function(el) {
|
||||
var label = $(el).attr('label');
|
||||
list.opt_labels.push(label);
|
||||
list[label] = getList($(el).find('option'));
|
||||
});
|
||||
} else {
|
||||
list = getList($el.find('option'));
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in default label and path values.
|
||||
selectConfig.valuePath = selectConfig.valuePath || 'value';
|
||||
selectConfig.labelPath = selectConfig.labelPath || 'label';
|
||||
|
||||
var addSelectOptions = function(optList, $el, fieldVal) {
|
||||
_.each(optList, function(obj) {
|
||||
var option = $('<option/>'), optionVal = obj;
|
||||
|
||||
var fillOption = function(text, val) {
|
||||
option.text(text);
|
||||
optionVal = val;
|
||||
// Save the option value as data so that we can reference it later.
|
||||
option.data('stickit_bind_val', optionVal);
|
||||
if (!_.isArray(optionVal) && !_.isObject(optionVal)) option.val(optionVal);
|
||||
};
|
||||
|
||||
if (obj === '__default__')
|
||||
fillOption(selectConfig.defaultOption.label, selectConfig.defaultOption.value);
|
||||
else
|
||||
fillOption(evaluatePath(obj, selectConfig.labelPath), evaluatePath(obj, selectConfig.valuePath));
|
||||
|
||||
// Determine if this option is selected.
|
||||
if (!isMultiple && optionVal != null && fieldVal != null && optionVal === fieldVal || (_.isObject(fieldVal) && _.isEqual(optionVal, fieldVal)))
|
||||
option.prop('selected', true);
|
||||
else if (isMultiple && _.isArray(fieldVal)) {
|
||||
_.each(fieldVal, function(val) {
|
||||
if (_.isObject(val)) val = evaluatePath(val, selectConfig.valuePath);
|
||||
if (val === optionVal || (_.isObject(val) && _.isEqual(optionVal, val)))
|
||||
option.prop('selected', true);
|
||||
});
|
||||
}
|
||||
|
||||
$el.append(option);
|
||||
});
|
||||
};
|
||||
|
||||
$el.html('');
|
||||
|
||||
// The `list` configuration is a function that returns the options list or a string
|
||||
// which represents the path to the list relative to `window` or the view/`this`.
|
||||
var evaluate = function(view, list) {
|
||||
var context = window;
|
||||
if (list.indexOf('this.') === 0) context = view;
|
||||
list = list.replace(/^[a-z]*\.(.+)$/, '$1');
|
||||
return evaluatePath(context, list);
|
||||
};
|
||||
if (_.isString(list)) optList = evaluate(this, list);
|
||||
else if (_.isFunction(list)) optList = applyViewFn(this, list, $el, options);
|
||||
else optList = list;
|
||||
|
||||
// Support Backbone.Collection and deserialize.
|
||||
if (optList instanceof Backbone.Collection) optList = optList.toJSON();
|
||||
|
||||
if (selectConfig.defaultOption) {
|
||||
addSelectOptions(["__default__"], $el)
|
||||
}
|
||||
|
||||
if (_.isArray(optList)) {
|
||||
addSelectOptions(optList, $el, val);
|
||||
} else if (optList.opt_labels) {
|
||||
// To define a select with optgroups, format selectOptions.collection as an object
|
||||
// with an 'opt_labels' property, as in the following:
|
||||
//
|
||||
// {
|
||||
// 'opt_labels': ['Looney Tunes', 'Three Stooges'],
|
||||
// 'Looney Tunes': [{id: 1, name: 'Bugs Bunny'}, {id: 2, name: 'Donald Duck'}],
|
||||
// 'Three Stooges': [{id: 3, name : 'moe'}, {id: 4, name : 'larry'}, {id: 5, name : 'curly'}]
|
||||
// }
|
||||
//
|
||||
_.each(optList.opt_labels, function(label) {
|
||||
var $group = $('<optgroup/>').attr('label', label);
|
||||
addSelectOptions(optList[label], $group, val);
|
||||
$el.append($group);
|
||||
});
|
||||
// With no 'opt_labels' parameter, the object is assumed to be a simple value-label map.
|
||||
// Pass a selectOptions.comparator to override the default order of alphabetical by label.
|
||||
} else {
|
||||
var opts = [], opt;
|
||||
for (var i in optList) {
|
||||
opt = {};
|
||||
opt[selectConfig.valuePath] = i;
|
||||
opt[selectConfig.labelPath] = optList[i];
|
||||
opts.push(opt);
|
||||
}
|
||||
addSelectOptions(_.sortBy(opts, selectConfig.comparator || selectConfig.labelPath), $el, val);
|
||||
}
|
||||
},
|
||||
getVal: function($el) {
|
||||
var val;
|
||||
if ($el.prop('multiple')) {
|
||||
val = $(getSelectedOption($el).map(function() {
|
||||
return $(this).data('stickit_bind_val');
|
||||
})).get();
|
||||
} else {
|
||||
val = getSelectedOption($el).data('stickit_bind_val');
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}]);
|
||||
|
||||
})(Backbone);
|
0
nailgun/static/js/libs/retina.js
Executable file → Normal file
0
nailgun/static/js/libs/retina.js
Executable file → Normal file
@ -26,6 +26,7 @@ requirejs.config({
|
||||
utils: 'js/utils',
|
||||
lodash: 'js/libs/lodash',
|
||||
backbone: 'js/libs/backbone',
|
||||
stickit: 'js/libs/backbone.stickit',
|
||||
coccyx: 'js/libs/coccyx',
|
||||
bootstrap: 'js/libs/bootstrap.min',
|
||||
text: 'js/libs/text',
|
||||
@ -43,8 +44,11 @@ requirejs.config({
|
||||
deps: ['lodash', 'jquery'],
|
||||
exports: 'Backbone'
|
||||
},
|
||||
stickit: {
|
||||
deps: ['backbone']
|
||||
},
|
||||
coccyx: {
|
||||
deps: ['lodash', 'backbone']
|
||||
deps: ['backbone']
|
||||
},
|
||||
bootstrap: {
|
||||
deps: ['jquery']
|
||||
@ -62,7 +66,7 @@ requirejs.config({
|
||||
deps: ['jquery']
|
||||
},
|
||||
app: {
|
||||
deps: ['jquery', 'lodash', 'backbone', 'coccyx', 'bootstrap', 'retina', 'jquery-checkbox', 'jquery-timeout', 'jquery-ui', 'jquery-autoNumeric']
|
||||
deps: ['jquery', 'lodash', 'backbone', 'stickit', 'coccyx', 'bootstrap', 'retina', 'jquery-checkbox', 'jquery-timeout', 'jquery-ui', 'jquery-autoNumeric']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -99,14 +99,29 @@ function(utils, models, dialogViews, navbarTemplate, nodesStatsTemplate, notific
|
||||
|
||||
views.NodesStats = Backbone.View.extend({
|
||||
template: _.template(nodesStatsTemplate),
|
||||
bindings: {
|
||||
'.total-nodes-count': 'total',
|
||||
'.total-nodes-title': {
|
||||
observe: 'total',
|
||||
onGet: 'formatTitle',
|
||||
updateMethod: 'html'
|
||||
},
|
||||
'.unallocated-nodes-count': 'unallocated',
|
||||
'.unallocated-nodes-title': {
|
||||
observe: 'unallocated',
|
||||
onGet: 'formatTitle',
|
||||
updateMethod: 'html'
|
||||
}
|
||||
},
|
||||
formatTitle: function(value, options) {
|
||||
return !_.isUndefined(value) ? options.observe + '<br>' + 'node' + (value == 1 ? '' : 's') : '';
|
||||
},
|
||||
initialize: function(options) {
|
||||
_.defaults(this, options);
|
||||
this.statistics.on('change', this.render, this);
|
||||
},
|
||||
render: function() {
|
||||
if (this.statistics.deferred.state() == 'resolved') {
|
||||
this.$el.html(this.template({stats: this.statistics}));
|
||||
}
|
||||
this.$el.html(this.template({stats: this.statistics}));
|
||||
this.stickit(this.statistics);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
@ -1,14 +1,6 @@
|
||||
<div class="statistic">
|
||||
<div class="stat-count">
|
||||
<%= stats.get('total') %>
|
||||
</div>
|
||||
<div class="stat-title">
|
||||
total<br/>node<%= stats.get('total') == 1 ? '' : 's' %>
|
||||
</div>
|
||||
<div class="stat-count">
|
||||
<%= stats.get('unallocated') %>
|
||||
</div>
|
||||
<div class="stat-title">
|
||||
unallocated<br/>node<%= stats.get('unallocated') == 1 ? '' : 's' %>
|
||||
</div>
|
||||
<div class="stat-count total-nodes-count"></div>
|
||||
<div class="stat-title total-nodes-title"></div>
|
||||
<div class="stat-count unallocated-nodes-count"></div>
|
||||
<div class="stat-title unallocated-nodes-title"></div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user